2 * Focus and activation functions
4 * Copyright 1993 David Metcalfe
5 * Copyright 1995 Alex Korobka
6 * Copyright 1994, 2002 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/server.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(win);
38 /*****************************************************************
41 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
43 static HWND set_focus_window( HWND hwnd )
48 SERVER_START_REQ( set_focus_window )
51 if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
55 if (previous == hwnd) return previous;
59 SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
60 if (hwnd != GetFocus()) return previous; /* changed by the message */
64 if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hwnd);
65 SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
71 /*******************************************************************
74 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
76 HWND previous = GetActiveWindow();
78 DWORD old_thread, new_thread;
79 CBTACTIVATESTRUCT cbt;
83 if (prev) *prev = hwnd;
87 /* call CBT hook chain */
89 cbt.hWndActive = previous;
90 if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
92 if (IsWindow(previous))
94 SendMessageW( previous, WM_NCACTIVATE, FALSE, 0 );
95 SendMessageW( previous, WM_ACTIVATE,
96 MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
99 SERVER_START_REQ( set_active_window )
102 if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
105 if (!ret) return FALSE;
106 if (prev) *prev = previous;
107 if (previous == hwnd) return TRUE;
111 /* send palette messages */
112 if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
113 SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 );
115 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED))
116 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
118 if (!IsWindow(hwnd)) return FALSE;
121 old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
122 new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
124 if (old_thread != new_thread)
128 if ((list = WIN_ListChildren( GetDesktopWindow() )))
132 for (phwnd = list; *phwnd; phwnd++)
134 if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
135 SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
140 for (phwnd = list; *phwnd; phwnd++)
142 if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
143 SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
146 HeapFree( GetProcessHeap(), 0, list );
152 SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), 0 );
153 SendMessageW( hwnd, WM_ACTIVATE,
154 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
158 /* now change focus if necessary */
161 HWND curfocus = GetFocus();
162 if (!curfocus || !hwnd || GetAncestor( curfocus, GA_ROOT ) != hwnd)
163 set_focus_window( hwnd );
170 /*******************************************************************
171 * set_foreground_window
173 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
175 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
178 SERVER_START_REQ( set_foreground_window )
181 if ((ret = !wine_server_call_err( req )))
183 previous = reply->previous;
184 send_msg_old = reply->send_msg_old;
185 send_msg_new = reply->send_msg_new;
192 if (send_msg_old) /* old window belongs to other thread */
193 SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
194 else if (send_msg_new) /* old window belongs to us but new one to other thread */
195 ret = set_active_window( 0, NULL, mouse, TRUE );
197 if (send_msg_new) /* new window belongs to other thread */
198 SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
199 else /* new window belongs to us */
200 ret = set_active_window( hwnd, NULL, mouse, TRUE );
206 /*******************************************************************
207 * FOCUS_MouseActivate
209 * Activate a window as a result of a mouse click
211 BOOL FOCUS_MouseActivate( HWND hwnd )
213 return set_foreground_window( hwnd, TRUE );
217 /*******************************************************************
218 * SetActiveWindow (USER32.@)
220 HWND WINAPI SetActiveWindow( HWND hwnd )
224 TRACE( "%p\n", hwnd );
228 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
230 if (!(style & WS_VISIBLE) || (style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
231 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
233 hwnd = WIN_GetFullHandle( hwnd );
236 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
241 /*****************************************************************
242 * SetFocus (USER32.@)
244 HWND WINAPI SetFocus( HWND hwnd )
247 HWND previous = GetFocus();
249 TRACE( "%p prev %p\n", hwnd, previous );
253 /* Check if we can set the focus to this window */
254 hwnd = WIN_GetFullHandle( hwnd );
255 if (hwnd == previous) return previous; /* nothing to do */
259 LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
260 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
261 parent = GetAncestor( hwndTop, GA_PARENT );
262 if (!parent || parent == GetDesktopWindow()) break;
267 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
269 /* activate hwndTop if needed. */
270 if (hwndTop != GetActiveWindow())
272 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
273 if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
276 else /* NULL hwnd passed in */
278 if (!previous) return 0; /* nothing to do */
279 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
282 /* change focus and send messages */
283 return set_focus_window( hwnd );
287 /*******************************************************************
288 * SetForegroundWindow (USER32.@)
290 BOOL WINAPI SetForegroundWindow( HWND hwnd )
292 TRACE( "%p\n", hwnd );
293 if (hwnd) hwnd = WIN_GetFullHandle( hwnd );
294 return set_foreground_window( hwnd, FALSE );
298 /*******************************************************************
299 * GetActiveWindow (USER32.@)
301 HWND WINAPI GetActiveWindow(void)
305 SERVER_START_REQ( get_thread_input )
307 req->tid = GetCurrentThreadId();
308 if (!wine_server_call_err( req )) ret = reply->active;
315 /*****************************************************************
316 * GetFocus (USER32.@)
318 HWND WINAPI GetFocus(void)
322 SERVER_START_REQ( get_thread_input )
324 req->tid = GetCurrentThreadId();
325 if (!wine_server_call_err( req )) ret = reply->focus;
332 /*******************************************************************
333 * GetForegroundWindow (USER32.@)
335 HWND WINAPI GetForegroundWindow(void)
339 SERVER_START_REQ( get_thread_input )
342 if (!wine_server_call_err( req )) ret = reply->foreground;