mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / user32 / focus.c
blob4c18238a98bf6201d392f16c1850ca0a0f0179a4
1 /*
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "win.h"
30 #include "user_private.h"
31 #include "wine/server.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(win);
37 /*****************************************************************
38 * set_focus_window
40 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
42 static HWND set_focus_window( HWND hwnd )
44 HWND previous = 0;
45 BOOL ret;
47 SERVER_START_REQ( set_focus_window )
49 req->handle = wine_server_user_handle( hwnd );
50 if ((ret = !wine_server_call_err( req )))
51 previous = wine_server_ptr_handle( reply->previous );
53 SERVER_END_REQ;
54 if (!ret) return 0;
55 if (previous == hwnd) return previous;
57 if (previous)
59 SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
60 if (hwnd != GetFocus()) return previous; /* changed by the message */
62 if (IsWindow(hwnd))
64 USER_Driver->pSetFocus(hwnd);
65 SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
67 return previous;
71 /*******************************************************************
72 * set_active_window
74 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
76 HWND previous = GetActiveWindow();
77 BOOL ret;
78 DWORD old_thread, new_thread;
79 CBTACTIVATESTRUCT cbt;
81 if (previous == hwnd)
83 if (prev) *prev = hwnd;
84 return TRUE;
87 /* call CBT hook chain */
88 cbt.fMouse = mouse;
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, (LPARAM)hwnd );
95 SendMessageW( previous, WM_ACTIVATE,
96 MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
99 SERVER_START_REQ( set_active_window )
101 req->handle = wine_server_user_handle( hwnd );
102 if ((ret = !wine_server_call_err( req )))
103 previous = wine_server_ptr_handle( reply->previous );
105 SERVER_END_REQ;
106 if (!ret) return FALSE;
107 if (prev) *prev = previous;
108 if (previous == hwnd) return TRUE;
110 if (hwnd)
112 /* send palette messages */
113 if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
114 SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
115 SMTO_ABORTIFHUNG, 2000, NULL );
116 if (!IsWindow(hwnd)) return FALSE;
119 old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
120 new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
122 if (old_thread != new_thread)
124 HWND *list, *phwnd;
126 if ((list = WIN_ListChildren( GetDesktopWindow() )))
128 if (old_thread)
130 for (phwnd = list; *phwnd; phwnd++)
132 if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
133 SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
136 if (new_thread)
138 for (phwnd = list; *phwnd; phwnd++)
140 if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
141 SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
144 HeapFree( GetProcessHeap(), 0, list );
148 if (IsWindow(hwnd))
150 SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous );
151 SendMessageW( hwnd, WM_ACTIVATE,
152 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
153 (LPARAM)previous );
154 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
155 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
158 /* now change focus if necessary */
159 if (focus)
161 GUITHREADINFO info;
163 info.cbSize = sizeof(info);
164 GetGUIThreadInfo( GetCurrentThreadId(), &info );
165 /* Do not change focus if the window is no more active */
166 if (hwnd == info.hwndActive)
168 if (!info.hwndFocus || !hwnd || GetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
169 set_focus_window( hwnd );
173 return TRUE;
177 /*******************************************************************
178 * set_foreground_window
180 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
182 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
183 HWND previous = 0;
185 SERVER_START_REQ( set_foreground_window )
187 req->handle = wine_server_user_handle( hwnd );
188 if ((ret = !wine_server_call_err( req )))
190 previous = wine_server_ptr_handle( reply->previous );
191 send_msg_old = reply->send_msg_old;
192 send_msg_new = reply->send_msg_new;
195 SERVER_END_REQ;
197 if (ret && previous != hwnd)
199 if (send_msg_old) /* old window belongs to other thread */
200 SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
201 else if (send_msg_new) /* old window belongs to us but new one to other thread */
202 ret = set_active_window( 0, NULL, mouse, TRUE );
204 if (send_msg_new) /* new window belongs to other thread */
205 SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
206 else /* new window belongs to us */
207 ret = set_active_window( hwnd, NULL, mouse, TRUE );
209 return ret;
213 /*******************************************************************
214 * FOCUS_MouseActivate
216 * Activate a window as a result of a mouse click
218 BOOL FOCUS_MouseActivate( HWND hwnd )
220 return set_foreground_window( hwnd, TRUE );
224 /*******************************************************************
225 * SetActiveWindow (USER32.@)
227 HWND WINAPI SetActiveWindow( HWND hwnd )
229 HWND prev;
231 TRACE( "%p\n", hwnd );
233 if (hwnd)
235 LONG style;
237 hwnd = WIN_GetFullHandle( hwnd );
238 if (!IsWindow( hwnd ))
240 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
241 return 0;
244 style = GetWindowLongW( hwnd, GWL_STYLE );
245 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
246 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
249 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
250 return prev;
254 /*****************************************************************
255 * SetFocus (USER32.@)
257 HWND WINAPI SetFocus( HWND hwnd )
259 HWND hwndTop = hwnd;
260 HWND previous = GetFocus();
262 TRACE( "%p prev %p\n", hwnd, previous );
264 if (hwnd)
266 /* Check if we can set the focus to this window */
267 hwnd = WIN_GetFullHandle( hwnd );
268 if (!IsWindow( hwnd ))
270 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
271 return 0;
273 if (hwnd == previous) return previous; /* nothing to do */
274 for (;;)
276 HWND parent;
277 LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
278 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
279 if (!(style & WS_CHILD)) break;
280 parent = GetAncestor( hwndTop, GA_PARENT );
281 if (!parent || parent == GetDesktopWindow())
283 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
284 break;
286 if (parent == get_hwnd_message_parent()) return 0;
287 hwndTop = parent;
290 /* call hooks */
291 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
293 /* activate hwndTop if needed. */
294 if (hwndTop != GetActiveWindow())
296 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
297 if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
299 /* Do not change focus if the window is no longer active */
300 if (hwndTop != GetActiveWindow()) return 0;
303 else /* NULL hwnd passed in */
305 if (!previous) return 0; /* nothing to do */
306 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
309 /* change focus and send messages */
310 return set_focus_window( hwnd );
314 /*******************************************************************
315 * SetForegroundWindow (USER32.@)
317 BOOL WINAPI SetForegroundWindow( HWND hwnd )
319 TRACE( "%p\n", hwnd );
321 hwnd = WIN_GetFullHandle( hwnd );
322 return set_foreground_window( hwnd, FALSE );
326 /*******************************************************************
327 * GetActiveWindow (USER32.@)
329 HWND WINAPI GetActiveWindow(void)
331 HWND ret = 0;
333 SERVER_START_REQ( get_thread_input )
335 req->tid = GetCurrentThreadId();
336 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->active );
338 SERVER_END_REQ;
339 return ret;
343 /*****************************************************************
344 * GetFocus (USER32.@)
346 HWND WINAPI GetFocus(void)
348 HWND ret = 0;
350 SERVER_START_REQ( get_thread_input )
352 req->tid = GetCurrentThreadId();
353 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->focus );
355 SERVER_END_REQ;
356 return ret;
360 /*******************************************************************
361 * GetForegroundWindow (USER32.@)
363 HWND WINAPI GetForegroundWindow(void)
365 HWND ret = 0;
367 SERVER_START_REQ( get_thread_input )
369 req->tid = 0;
370 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground );
372 SERVER_END_REQ;
373 return ret;
377 /***********************************************************************
378 * SetShellWindowEx (USER32.@)
379 * hwndShell = Progman[Program Manager]
380 * |-> SHELLDLL_DefView
381 * hwndListView = | |-> SysListView32
382 * | | |-> tooltips_class32
383 * | |
384 * | |-> SysHeader32
386 * |-> ProxyTarget
388 BOOL WINAPI SetShellWindowEx(HWND hwndShell, HWND hwndListView)
390 BOOL ret;
392 if (GetShellWindow())
393 return FALSE;
395 if (GetWindowLongW(hwndShell, GWL_EXSTYLE) & WS_EX_TOPMOST)
396 return FALSE;
398 if (hwndListView != hwndShell)
399 if (GetWindowLongW(hwndListView, GWL_EXSTYLE) & WS_EX_TOPMOST)
400 return FALSE;
402 if (hwndListView && hwndListView!=hwndShell)
403 SetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
405 SetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
407 SERVER_START_REQ(set_global_windows)
409 req->flags = SET_GLOBAL_SHELL_WINDOWS;
410 req->shell_window = wine_server_user_handle( hwndShell );
411 req->shell_listview = wine_server_user_handle( hwndListView );
412 ret = !wine_server_call_err(req);
414 SERVER_END_REQ;
416 return ret;
420 /*******************************************************************
421 * SetShellWindow (USER32.@)
423 BOOL WINAPI SetShellWindow(HWND hwndShell)
425 return SetShellWindowEx(hwndShell, hwndShell);
429 /*******************************************************************
430 * GetShellWindow (USER32.@)
432 HWND WINAPI GetShellWindow(void)
434 HWND hwndShell = 0;
436 SERVER_START_REQ(set_global_windows)
438 req->flags = 0;
439 if (!wine_server_call_err(req))
440 hwndShell = wine_server_ptr_handle( reply->old_shell_window );
442 SERVER_END_REQ;
444 return hwndShell;
448 /***********************************************************************
449 * SetProgmanWindow (USER32.@)
451 HWND WINAPI SetProgmanWindow ( HWND hwnd )
453 SERVER_START_REQ(set_global_windows)
455 req->flags = SET_GLOBAL_PROGMAN_WINDOW;
456 req->progman_window = wine_server_user_handle( hwnd );
457 if (wine_server_call_err( req )) hwnd = 0;
459 SERVER_END_REQ;
460 return hwnd;
464 /***********************************************************************
465 * GetProgmanWindow (USER32.@)
467 HWND WINAPI GetProgmanWindow(void)
469 HWND ret = 0;
471 SERVER_START_REQ(set_global_windows)
473 req->flags = 0;
474 if (!wine_server_call_err(req))
475 ret = wine_server_ptr_handle( reply->old_progman_window );
477 SERVER_END_REQ;
478 return ret;
482 /***********************************************************************
483 * SetTaskmanWindow (USER32.@)
484 * NOTES
485 * hwnd = MSTaskSwWClass
486 * |-> SysTabControl32
488 HWND WINAPI SetTaskmanWindow ( HWND hwnd )
490 SERVER_START_REQ(set_global_windows)
492 req->flags = SET_GLOBAL_TASKMAN_WINDOW;
493 req->taskman_window = wine_server_user_handle( hwnd );
494 if (wine_server_call_err( req )) hwnd = 0;
496 SERVER_END_REQ;
497 return hwnd;
500 /***********************************************************************
501 * GetTaskmanWindow (USER32.@)
503 HWND WINAPI GetTaskmanWindow(void)
505 HWND ret = 0;
507 SERVER_START_REQ(set_global_windows)
509 req->flags = 0;
510 if (!wine_server_call_err(req))
511 ret = wine_server_ptr_handle( reply->old_taskman_window );
513 SERVER_END_REQ;
514 return ret;