| /* |
| * 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; |
| } |