kernel32: Pass completion value to ntdll layer.
[wine/wine64.git] / dlls / user32 / focus.c
blobe2932d2d59092443f60c973d2beb40704db32d27
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 "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "win.h"
32 #include "user_private.h"
33 #include "wine/server.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(win);
39 /*****************************************************************
40 * set_focus_window
42 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
44 static HWND set_focus_window( HWND hwnd )
46 HWND previous = 0;
47 BOOL ret;
49 SERVER_START_REQ( set_focus_window )
51 req->handle = hwnd;
52 if ((ret = !wine_server_call_err( req ))) previous = 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 );
61 if (hwnd != GetFocus()) return previous; /* changed by the message */
63 if (IsWindow(hwnd))
65 USER_Driver->pSetFocus(hwnd);
66 SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
68 return previous;
72 /*******************************************************************
73 * set_active_window
75 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
77 HWND previous = GetActiveWindow();
78 BOOL ret;
79 DWORD old_thread, new_thread;
80 CBTACTIVATESTRUCT cbt;
82 if (previous == hwnd)
84 if (prev) *prev = hwnd;
85 return TRUE;
88 /* call CBT hook chain */
89 cbt.fMouse = mouse;
90 cbt.hWndActive = previous;
91 if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
93 if (IsWindow(previous))
95 SendMessageW( previous, WM_NCACTIVATE, FALSE, (LPARAM)hwnd );
96 SendMessageW( previous, WM_ACTIVATE,
97 MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
100 SERVER_START_REQ( set_active_window )
102 req->handle = hwnd;
103 if ((ret = !wine_server_call_err( req ))) previous = 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 );
117 if (!GetPropA( hwnd, "__wine_x11_managed" ))
118 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
120 if (!IsWindow(hwnd)) return FALSE;
123 old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
124 new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
126 if (old_thread != new_thread)
128 HWND *list, *phwnd;
130 if ((list = WIN_ListChildren( GetDesktopWindow() )))
132 if (old_thread)
134 for (phwnd = list; *phwnd; phwnd++)
136 if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
137 SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
140 if (new_thread)
142 for (phwnd = list; *phwnd; phwnd++)
144 if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
145 SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
148 HeapFree( GetProcessHeap(), 0, list );
152 if (IsWindow(hwnd))
154 SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous );
155 SendMessageW( hwnd, WM_ACTIVATE,
156 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
157 (LPARAM)previous );
160 /* now change focus if necessary */
161 if (focus)
163 GUITHREADINFO info;
165 GetGUIThreadInfo( GetCurrentThreadId(), &info );
166 /* Do not change focus if the window is no more active */
167 if (hwnd == info.hwndActive)
169 if (!info.hwndFocus || !hwnd || GetAncestor( info.hwndFocus, GA_ROOT ) != hwnd)
170 set_focus_window( hwnd );
174 return TRUE;
178 /*******************************************************************
179 * set_foreground_window
181 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
183 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
184 HWND previous = 0;
186 SERVER_START_REQ( set_foreground_window )
188 req->handle = hwnd;
189 if ((ret = !wine_server_call_err( req )))
191 previous = reply->previous;
192 send_msg_old = reply->send_msg_old;
193 send_msg_new = reply->send_msg_new;
196 SERVER_END_REQ;
198 if (ret)
200 if (send_msg_old) /* old window belongs to other thread */
201 SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
202 else if (send_msg_new) /* old window belongs to us but new one to other thread */
203 ret = set_active_window( 0, NULL, mouse, TRUE );
205 if (send_msg_new) /* new window belongs to other thread */
206 SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
207 else /* new window belongs to us */
208 ret = set_active_window( hwnd, NULL, mouse, TRUE );
210 return ret;
214 /*******************************************************************
215 * FOCUS_MouseActivate
217 * Activate a window as a result of a mouse click
219 BOOL FOCUS_MouseActivate( HWND hwnd )
221 return set_foreground_window( hwnd, TRUE );
225 /*******************************************************************
226 * SetActiveWindow (USER32.@)
228 HWND WINAPI SetActiveWindow( HWND hwnd )
230 HWND prev;
232 TRACE( "%p\n", hwnd );
234 if (hwnd)
236 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
238 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
239 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
241 hwnd = WIN_GetFullHandle( hwnd );
244 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
245 return prev;
249 /*****************************************************************
250 * SetFocus (USER32.@)
252 HWND WINAPI SetFocus( HWND hwnd )
254 HWND hwndTop = hwnd;
255 HWND previous = GetFocus();
257 TRACE( "%p prev %p\n", hwnd, previous );
259 if (hwnd)
261 /* Check if we can set the focus to this window */
262 hwnd = WIN_GetFullHandle( hwnd );
263 if (hwnd == previous) return previous; /* nothing to do */
264 for (;;)
266 HWND parent;
267 LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
268 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
269 parent = GetAncestor( hwndTop, GA_PARENT );
270 if (!parent || parent == GetDesktopWindow()) break;
271 hwndTop = parent;
274 /* call hooks */
275 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
277 /* activate hwndTop if needed. */
278 if (hwndTop != GetActiveWindow())
280 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
281 if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
284 else /* NULL hwnd passed in */
286 if (!previous) return 0; /* nothing to do */
287 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
290 /* change focus and send messages */
291 return set_focus_window( hwnd );
295 /*******************************************************************
296 * SetForegroundWindow (USER32.@)
298 BOOL WINAPI SetForegroundWindow( HWND hwnd )
300 TRACE( "%p\n", hwnd );
302 hwnd = WIN_GetFullHandle( hwnd );
303 return set_foreground_window( hwnd, FALSE );
307 /*******************************************************************
308 * GetActiveWindow (USER32.@)
310 HWND WINAPI GetActiveWindow(void)
312 HWND ret = 0;
314 SERVER_START_REQ( get_thread_input )
316 req->tid = GetCurrentThreadId();
317 if (!wine_server_call_err( req )) ret = reply->active;
319 SERVER_END_REQ;
320 return ret;
324 /*****************************************************************
325 * GetFocus (USER32.@)
327 HWND WINAPI GetFocus(void)
329 HWND ret = 0;
331 SERVER_START_REQ( get_thread_input )
333 req->tid = GetCurrentThreadId();
334 if (!wine_server_call_err( req )) ret = reply->focus;
336 SERVER_END_REQ;
337 return ret;
341 /*******************************************************************
342 * GetForegroundWindow (USER32.@)
344 HWND WINAPI GetForegroundWindow(void)
346 HWND ret = 0;
348 SERVER_START_REQ( get_thread_input )
350 req->tid = 0;
351 if (!wine_server_call_err( req )) ret = reply->foreground;
353 SERVER_END_REQ;
354 return ret;
358 /***********************************************************************
359 * SetShellWindowEx (USER32.@)
360 * hwndShell = Progman[Program Manager]
361 * |-> SHELLDLL_DefView
362 * hwndListView = | |-> SysListView32
363 * | | |-> tooltips_class32
364 * | |
365 * | |-> SysHeader32
367 * |-> ProxyTarget
369 BOOL WINAPI SetShellWindowEx(HWND hwndShell, HWND hwndListView)
371 BOOL ret;
373 if (GetShellWindow())
374 return FALSE;
376 if (GetWindowLongW(hwndShell, GWL_EXSTYLE) & WS_EX_TOPMOST)
377 return FALSE;
379 if (hwndListView != hwndShell)
380 if (GetWindowLongW(hwndListView, GWL_EXSTYLE) & WS_EX_TOPMOST)
381 return FALSE;
383 if (hwndListView && hwndListView!=hwndShell)
384 SetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
386 SetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
388 SERVER_START_REQ(set_global_windows)
390 req->flags = SET_GLOBAL_SHELL_WINDOWS;
391 req->shell_window = hwndShell;
392 req->shell_listview = hwndListView;
393 ret = !wine_server_call_err(req);
395 SERVER_END_REQ;
397 return ret;
401 /*******************************************************************
402 * SetShellWindow (USER32.@)
404 BOOL WINAPI SetShellWindow(HWND hwndShell)
406 return SetShellWindowEx(hwndShell, hwndShell);
410 /*******************************************************************
411 * GetShellWindow (USER32.@)
413 HWND WINAPI GetShellWindow(void)
415 HWND hwndShell = 0;
417 SERVER_START_REQ(set_global_windows)
419 req->flags = 0;
420 if (!wine_server_call_err(req))
421 hwndShell = reply->old_shell_window;
423 SERVER_END_REQ;
425 return hwndShell;
429 /***********************************************************************
430 * SetProgmanWindow (USER32.@)
432 HWND WINAPI SetProgmanWindow ( HWND hwnd )
434 SERVER_START_REQ(set_global_windows)
436 req->flags = SET_GLOBAL_PROGMAN_WINDOW;
437 req->progman_window = hwnd;
438 if (wine_server_call_err( req )) hwnd = 0;
440 SERVER_END_REQ;
441 return hwnd;
445 /***********************************************************************
446 * GetProgmanWindow (USER32.@)
448 HWND WINAPI GetProgmanWindow(void)
450 HWND ret = 0;
452 SERVER_START_REQ(set_global_windows)
454 req->flags = 0;
455 if (!wine_server_call_err(req)) ret = reply->old_progman_window;
457 SERVER_END_REQ;
458 return ret;
462 /***********************************************************************
463 * SetTaskmanWindow (USER32.@)
464 * NOTES
465 * hwnd = MSTaskSwWClass
466 * |-> SysTabControl32
468 HWND WINAPI SetTaskmanWindow ( HWND hwnd )
470 SERVER_START_REQ(set_global_windows)
472 req->flags = SET_GLOBAL_TASKMAN_WINDOW;
473 req->taskman_window = hwnd;
474 if (wine_server_call_err( req )) hwnd = 0;
476 SERVER_END_REQ;
477 return hwnd;
480 /***********************************************************************
481 * GetTaskmanWindow (USER32.@)
483 HWND WINAPI GetTaskmanWindow(void)
485 HWND ret = 0;
487 SERVER_START_REQ(set_global_windows)
489 req->flags = 0;
490 if (!wine_server_call_err(req)) ret = reply->old_taskman_window;
492 SERVER_END_REQ;
493 return ret;