d2d1: Create feature level 10.0 device context state objects.
[wine.git] / dlls / user32 / focus.c
blob34cc3880cc9f6149bd0691b3aa61d7ec01462416
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 "imm.h"
31 #include "user_private.h"
32 #include "wine/server.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(win);
38 /*****************************************************************
39 * set_focus_window
41 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
43 static HWND set_focus_window( HWND hwnd )
45 HWND previous = 0, ime_default;
46 BOOL ret;
48 SERVER_START_REQ( set_focus_window )
50 req->handle = wine_server_user_handle( hwnd );
51 if ((ret = !wine_server_call_err( req )))
52 previous = wine_server_ptr_handle( reply->previous );
54 SERVER_END_REQ;
55 if (!ret) return 0;
56 if (previous == hwnd) return previous;
58 if (previous)
60 SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
62 ime_default = ImmGetDefaultIMEWnd( previous );
63 if (ime_default)
64 SendMessageW( ime_default, WM_IME_INTERNAL, IME_INTERNAL_DEACTIVATE, (LPARAM)previous );
66 if (hwnd != GetFocus()) return previous; /* changed by the message */
68 if (IsWindow(hwnd))
70 USER_Driver->pSetFocus(hwnd);
72 ime_default = ImmGetDefaultIMEWnd( hwnd );
73 if (ime_default)
74 SendMessageW( ime_default, WM_IME_INTERNAL, IME_INTERNAL_ACTIVATE, (LPARAM)hwnd );
76 SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
78 return previous;
82 /*******************************************************************
83 * set_active_window
85 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
87 HWND previous = GetActiveWindow();
88 BOOL ret;
89 DWORD old_thread, new_thread;
90 CBTACTIVATESTRUCT cbt;
92 if (previous == hwnd)
94 if (prev) *prev = hwnd;
95 return TRUE;
98 /* call CBT hook chain */
99 cbt.fMouse = mouse;
100 cbt.hWndActive = previous;
101 if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
103 if (IsWindow(previous))
105 SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
106 SendMessageW( previous, WM_ACTIVATE,
107 MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
110 SERVER_START_REQ( set_active_window )
112 req->handle = wine_server_user_handle( hwnd );
113 if ((ret = !wine_server_call_err( req )))
114 previous = wine_server_ptr_handle( reply->previous );
116 SERVER_END_REQ;
117 if (!ret) return FALSE;
118 if (prev) *prev = previous;
119 if (previous == hwnd) return TRUE;
121 if (hwnd)
123 /* send palette messages */
124 if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
125 SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
126 SMTO_ABORTIFHUNG, 2000, NULL );
127 if (!IsWindow(hwnd)) return FALSE;
130 old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
131 new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
133 if (old_thread != new_thread)
135 HWND *list, *phwnd;
137 if ((list = WIN_ListChildren( GetDesktopWindow() )))
139 if (old_thread)
141 for (phwnd = list; *phwnd; phwnd++)
143 if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
144 SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
147 if (new_thread)
149 for (phwnd = list; *phwnd; phwnd++)
151 if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
152 SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
155 HeapFree( GetProcessHeap(), 0, list );
159 if (IsWindow(hwnd))
161 SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous );
162 SendMessageW( hwnd, WM_ACTIVATE,
163 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
164 (LPARAM)previous );
165 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
166 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
169 /* now change focus if necessary */
170 if (focus)
172 GUITHREADINFO info;
174 info.cbSize = sizeof(info);
175 GetGUIThreadInfo( GetCurrentThreadId(), &info );
176 /* Do not change focus if the window is no more active */
177 if (hwnd == info.hwndActive)
179 if (!info.hwndFocus || !hwnd || GetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
180 set_focus_window( hwnd );
184 return TRUE;
188 /*******************************************************************
189 * set_foreground_window
191 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
193 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
194 HWND previous = 0;
196 SERVER_START_REQ( set_foreground_window )
198 req->handle = wine_server_user_handle( hwnd );
199 if ((ret = !wine_server_call_err( req )))
201 previous = wine_server_ptr_handle( reply->previous );
202 send_msg_old = reply->send_msg_old;
203 send_msg_new = reply->send_msg_new;
206 SERVER_END_REQ;
208 if (ret && previous != hwnd)
210 if (send_msg_old) /* old window belongs to other thread */
211 SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
212 else if (send_msg_new) /* old window belongs to us but new one to other thread */
213 ret = set_active_window( 0, NULL, mouse, TRUE );
215 if (send_msg_new) /* new window belongs to other thread */
216 SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
217 else /* new window belongs to us */
218 ret = set_active_window( hwnd, NULL, mouse, TRUE );
220 return ret;
224 /*******************************************************************
225 * FOCUS_MouseActivate
227 * Activate a window as a result of a mouse click
229 BOOL FOCUS_MouseActivate( HWND hwnd )
231 return set_foreground_window( hwnd, TRUE );
235 /*******************************************************************
236 * SetActiveWindow (USER32.@)
238 HWND WINAPI SetActiveWindow( HWND hwnd )
240 HWND prev;
242 TRACE( "%p\n", hwnd );
244 if (hwnd)
246 LONG style;
248 hwnd = WIN_GetFullHandle( hwnd );
249 if (!IsWindow( hwnd ))
251 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
252 return 0;
255 style = GetWindowLongW( hwnd, GWL_STYLE );
256 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
257 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
260 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
261 return prev;
265 /*****************************************************************
266 * SetFocus (USER32.@)
268 HWND WINAPI SetFocus( HWND hwnd )
270 HWND hwndTop = hwnd;
271 HWND previous = GetFocus();
273 TRACE( "%p prev %p\n", hwnd, previous );
275 if (hwnd)
277 /* Check if we can set the focus to this window */
278 hwnd = WIN_GetFullHandle( hwnd );
279 if (!IsWindow( hwnd ))
281 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
282 return 0;
284 if (hwnd == previous) return previous; /* nothing to do */
285 for (;;)
287 HWND parent;
288 LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
289 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
290 if (!(style & WS_CHILD)) break;
291 parent = GetAncestor( hwndTop, GA_PARENT );
292 if (!parent || parent == GetDesktopWindow())
294 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
295 break;
297 if (parent == get_hwnd_message_parent()) return 0;
298 hwndTop = parent;
301 /* call hooks */
302 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
304 /* activate hwndTop if needed. */
305 if (hwndTop != GetActiveWindow())
307 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
308 if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
310 /* Do not change focus if the window is no longer active */
311 if (hwndTop != GetActiveWindow()) return 0;
314 else /* NULL hwnd passed in */
316 if (!previous) return 0; /* nothing to do */
317 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
320 /* change focus and send messages */
321 return set_focus_window( hwnd );
325 /*******************************************************************
326 * SetForegroundWindow (USER32.@)
328 BOOL WINAPI SetForegroundWindow( HWND hwnd )
330 TRACE( "%p\n", hwnd );
332 hwnd = WIN_GetFullHandle( hwnd );
333 return set_foreground_window( hwnd, FALSE );
337 /*******************************************************************
338 * GetActiveWindow (USER32.@)
340 HWND WINAPI GetActiveWindow(void)
342 HWND ret = 0;
344 SERVER_START_REQ( get_thread_input )
346 req->tid = GetCurrentThreadId();
347 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->active );
349 SERVER_END_REQ;
350 return ret;
354 /*****************************************************************
355 * GetFocus (USER32.@)
357 HWND WINAPI GetFocus(void)
359 HWND ret = 0;
361 SERVER_START_REQ( get_thread_input )
363 req->tid = GetCurrentThreadId();
364 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->focus );
366 SERVER_END_REQ;
367 return ret;
371 /*******************************************************************
372 * GetForegroundWindow (USER32.@)
374 HWND WINAPI GetForegroundWindow(void)
376 HWND ret = 0;
378 SERVER_START_REQ( get_thread_input )
380 req->tid = 0;
381 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground );
383 SERVER_END_REQ;
384 return ret;
388 /***********************************************************************
389 * SetShellWindowEx (USER32.@)
390 * hwndShell = Progman[Program Manager]
391 * |-> SHELLDLL_DefView
392 * hwndListView = | |-> SysListView32
393 * | | |-> tooltips_class32
394 * | |
395 * | |-> SysHeader32
397 * |-> ProxyTarget
399 BOOL WINAPI SetShellWindowEx(HWND hwndShell, HWND hwndListView)
401 BOOL ret;
403 if (GetShellWindow())
404 return FALSE;
406 if (GetWindowLongW(hwndShell, GWL_EXSTYLE) & WS_EX_TOPMOST)
407 return FALSE;
409 if (hwndListView != hwndShell)
410 if (GetWindowLongW(hwndListView, GWL_EXSTYLE) & WS_EX_TOPMOST)
411 return FALSE;
413 if (hwndListView && hwndListView!=hwndShell)
414 SetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
416 SetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
418 SERVER_START_REQ(set_global_windows)
420 req->flags = SET_GLOBAL_SHELL_WINDOWS;
421 req->shell_window = wine_server_user_handle( hwndShell );
422 req->shell_listview = wine_server_user_handle( hwndListView );
423 ret = !wine_server_call_err(req);
425 SERVER_END_REQ;
427 return ret;
431 /*******************************************************************
432 * SetShellWindow (USER32.@)
434 BOOL WINAPI SetShellWindow(HWND hwndShell)
436 return SetShellWindowEx(hwndShell, hwndShell);
440 /*******************************************************************
441 * GetShellWindow (USER32.@)
443 HWND WINAPI GetShellWindow(void)
445 HWND hwndShell = 0;
447 SERVER_START_REQ(set_global_windows)
449 req->flags = 0;
450 if (!wine_server_call_err(req))
451 hwndShell = wine_server_ptr_handle( reply->old_shell_window );
453 SERVER_END_REQ;
455 return hwndShell;
459 /***********************************************************************
460 * SetProgmanWindow (USER32.@)
462 HWND WINAPI SetProgmanWindow ( HWND hwnd )
464 SERVER_START_REQ(set_global_windows)
466 req->flags = SET_GLOBAL_PROGMAN_WINDOW;
467 req->progman_window = wine_server_user_handle( hwnd );
468 if (wine_server_call_err( req )) hwnd = 0;
470 SERVER_END_REQ;
471 return hwnd;
475 /***********************************************************************
476 * GetProgmanWindow (USER32.@)
478 HWND WINAPI GetProgmanWindow(void)
480 HWND ret = 0;
482 SERVER_START_REQ(set_global_windows)
484 req->flags = 0;
485 if (!wine_server_call_err(req))
486 ret = wine_server_ptr_handle( reply->old_progman_window );
488 SERVER_END_REQ;
489 return ret;
493 /***********************************************************************
494 * SetTaskmanWindow (USER32.@)
495 * NOTES
496 * hwnd = MSTaskSwWClass
497 * |-> SysTabControl32
499 HWND WINAPI SetTaskmanWindow ( HWND hwnd )
501 SERVER_START_REQ(set_global_windows)
503 req->flags = SET_GLOBAL_TASKMAN_WINDOW;
504 req->taskman_window = wine_server_user_handle( hwnd );
505 if (wine_server_call_err( req )) hwnd = 0;
507 SERVER_END_REQ;
508 return hwnd;
511 /***********************************************************************
512 * GetTaskmanWindow (USER32.@)
514 HWND WINAPI GetTaskmanWindow(void)
516 HWND ret = 0;
518 SERVER_START_REQ(set_global_windows)
520 req->flags = 0;
521 if (!wine_server_call_err(req))
522 ret = wine_server_ptr_handle( reply->old_taskman_window );
524 SERVER_END_REQ;
525 return ret;