Sweden-Number/dlls/user/focus.c

349 lines
9.5 KiB
C

/*
* Focus and activation functions
*
* Copyright 1993 David Metcalfe
* Copyright 1995 Alex Korobka
* Copyright 1994, 2002 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "winbase.h"
#include "winuser.h"
#include "winerror.h"
#include "win.h"
#include "hook.h"
#include "message.h"
#include "user.h"
#include "wine/server.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(win);
/*****************************************************************
* set_focus_window
*
* Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
*/
static HWND set_focus_window( HWND hwnd )
{
HWND previous = 0;
BOOL ret;
SERVER_START_REQ( set_focus_window )
{
req->handle = hwnd;
if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
}
SERVER_END_REQ;
if (!ret) return 0;
if (previous == hwnd) return previous;
if (previous)
{
SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
if (hwnd != GetFocus()) return previous; /* changed by the message */
}
if (IsWindow(hwnd))
{
if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hwnd);
SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
}
return previous;
}
/*******************************************************************
* set_active_window
*/
static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
{
HWND previous = GetActiveWindow();
BOOL ret;
DWORD old_thread, new_thread;
if (previous == hwnd)
{
if (prev) *prev = hwnd;
return TRUE;
}
/* call CBT hook chain */
if (HOOK_IsHooked( WH_CBT ))
{
CBTACTIVATESTRUCT cbt;
cbt.fMouse = mouse;
cbt.hWndActive = previous;
if (HOOK_CallHooksW( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt )) return FALSE;
}
if (IsWindow(previous))
{
SendMessageW( previous, WM_NCACTIVATE, FALSE, 0 );
SendMessageW( previous, WM_ACTIVATE,
MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
}
SERVER_START_REQ( set_active_window )
{
req->handle = hwnd;
if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
}
SERVER_END_REQ;
if (!ret) return FALSE;
if (prev) *prev = previous;
if (previous == hwnd) return TRUE;
if (hwnd)
{
/* send palette messages */
if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 );
if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED))
SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
if (!IsWindow(hwnd)) return FALSE;
}
old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
if (old_thread != new_thread)
{
HWND *list, *phwnd;
if ((list = WIN_ListChildren( GetDesktopWindow() )))
{
if (old_thread)
{
for (phwnd = list; *phwnd; phwnd++)
{
if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
}
}
if (new_thread)
{
for (phwnd = list; *phwnd; phwnd++)
{
if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
}
}
HeapFree( GetProcessHeap(), 0, list );
}
}
if (IsWindow(hwnd))
{
SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), 0 );
SendMessageW( hwnd, WM_ACTIVATE,
MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
(LPARAM)previous );
}
/* now change focus if necessary */
if (focus)
{
HWND curfocus = GetFocus();
if (!curfocus || !hwnd || GetAncestor( curfocus, GA_ROOT ) != hwnd)
set_focus_window( hwnd );
}
return TRUE;
}
/*******************************************************************
* set_foreground_window
*/
static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
{
BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
HWND previous = 0;
SERVER_START_REQ( set_foreground_window )
{
req->handle = hwnd;
if ((ret = !wine_server_call_err( req )))
{
previous = reply->previous;
send_msg_old = reply->send_msg_old;
send_msg_new = reply->send_msg_new;
}
}
SERVER_END_REQ;
if (ret)
{
if (send_msg_old) /* old window belongs to other thread */
SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
else if (send_msg_new) /* old window belongs to us but new one to other thread */
ret = set_active_window( 0, NULL, mouse, TRUE );
if (send_msg_new) /* new window belongs to other thread */
SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, hwnd, 0 );
else /* new window belongs to us */
ret = set_active_window( hwnd, NULL, mouse, TRUE );
}
return ret;
}
/*******************************************************************
* FOCUS_MouseActivate
*
* Activate a window as a result of a mouse click
*/
BOOL FOCUS_MouseActivate( HWND hwnd )
{
return set_foreground_window( hwnd, TRUE );
}
/*******************************************************************
* SetActiveWindow (USER32.@)
*/
HWND WINAPI SetActiveWindow( HWND hwnd )
{
HWND prev;
TRACE( "%x\n", hwnd );
if (hwnd)
{
LONG style = GetWindowLongW( hwnd, GWL_STYLE );
if (!(style & WS_VISIBLE) || (style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
return GetActiveWindow(); /* Windows doesn't seem to return an error here */
hwnd = WIN_GetFullHandle( hwnd );
}
if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
return prev;
}
/*****************************************************************
* SetFocus (USER32.@)
*/
HWND WINAPI SetFocus( HWND hwnd )
{
HWND hwndTop = hwnd;
HWND previous = GetFocus();
TRACE( "%x prev %x\n", hwnd, previous );
if (hwnd)
{
/* Check if we can set the focus to this window */
hwnd = WIN_GetFullHandle( hwnd );
if (hwnd == previous) return previous; /* nothing to do */
for (;;)
{
HWND parent;
LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
parent = GetAncestor( hwndTop, GA_PARENT );
if (!parent || parent == GetDesktopWindow()) break;
hwndTop = parent;
}
/* call hooks */
if (HOOK_CallHooksW( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous )) return 0;
/* activate hwndTop if needed. */
if (hwndTop != GetActiveWindow())
{
if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
}
}
else /* NULL hwnd passed in */
{
if (!previous) return 0; /* nothing to do */
if( HOOK_CallHooksW( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous ) )
return 0;
}
/* change focus and send messages */
return set_focus_window( hwnd );
}
/*******************************************************************
* SetForegroundWindow (USER32.@)
*/
BOOL WINAPI SetForegroundWindow( HWND hwnd )
{
TRACE( "%x\n", hwnd );
if (hwnd) hwnd = WIN_GetFullHandle( hwnd );
return set_foreground_window( hwnd, FALSE );
}
/*******************************************************************
* GetActiveWindow (USER32.@)
*/
HWND WINAPI GetActiveWindow(void)
{
HWND ret = 0;
SERVER_START_REQ( get_thread_input )
{
req->tid = GetCurrentThreadId();
if (!wine_server_call_err( req )) ret = reply->active;
}
SERVER_END_REQ;
return ret;
}
/*****************************************************************
* GetFocus (USER32.@)
*/
HWND WINAPI GetFocus(void)
{
HWND ret = 0;
SERVER_START_REQ( get_thread_input )
{
req->tid = GetCurrentThreadId();
if (!wine_server_call_err( req )) ret = reply->focus;
}
SERVER_END_REQ;
return ret;
}
/*******************************************************************
* GetForegroundWindow (USER32.@)
*/
HWND WINAPI GetForegroundWindow(void)
{
HWND ret = 0;
SERVER_START_REQ( get_thread_input )
{
req->tid = 0;
if (!wine_server_call_err( req )) ret = reply->foreground;
}
SERVER_END_REQ;
return ret;
}