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
31 #include "user_private.h"
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
)
45 HWND previous
= 0, ime_default
;
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
);
56 if (previous
== hwnd
) return previous
;
60 SendMessageW( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
62 ime_default
= ImmGetDefaultIMEWnd( previous
);
64 SendMessageW( ime_default
, WM_IME_INTERNAL
, IME_INTERNAL_DEACTIVATE
, (LPARAM
)previous
);
66 if (hwnd
!= GetFocus()) return previous
; /* changed by the message */
70 USER_Driver
->pSetFocus(hwnd
);
72 ime_default
= ImmGetDefaultIMEWnd( hwnd
);
74 SendMessageW( ime_default
, WM_IME_INTERNAL
, IME_INTERNAL_ACTIVATE
, (LPARAM
)hwnd
);
77 NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS
, hwnd
, OBJID_CLIENT
, 0 );
79 SendMessageW( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
85 /*******************************************************************
88 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
90 HWND previous
= GetActiveWindow();
92 DWORD old_thread
, new_thread
;
93 CBTACTIVATESTRUCT cbt
;
97 if (prev
) *prev
= hwnd
;
101 /* call CBT hook chain */
103 cbt
.hWndActive
= previous
;
104 if (HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
, TRUE
)) return FALSE
;
106 if (IsWindow(previous
))
108 SendMessageW( previous
, WM_NCACTIVATE
, FALSE
, (LPARAM
)hwnd
);
109 SendMessageW( previous
, WM_ACTIVATE
,
110 MAKEWPARAM( WA_INACTIVE
, IsIconic(previous
) ), (LPARAM
)hwnd
);
113 SERVER_START_REQ( set_active_window
)
115 req
->handle
= wine_server_user_handle( hwnd
);
116 if ((ret
= !wine_server_call_err( req
)))
117 previous
= wine_server_ptr_handle( reply
->previous
);
120 if (!ret
) return FALSE
;
121 if (prev
) *prev
= previous
;
122 if (previous
== hwnd
) return TRUE
;
126 /* send palette messages */
127 if (SendMessageW( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
128 SendMessageTimeoutW( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0,
129 SMTO_ABORTIFHUNG
, 2000, NULL
);
130 if (!IsWindow(hwnd
)) return FALSE
;
133 old_thread
= previous
? GetWindowThreadProcessId( previous
, NULL
) : 0;
134 new_thread
= hwnd
? GetWindowThreadProcessId( hwnd
, NULL
) : 0;
136 if (old_thread
!= new_thread
)
140 if ((list
= WIN_ListChildren( GetDesktopWindow() )))
144 for (phwnd
= list
; *phwnd
; phwnd
++)
146 if (GetWindowThreadProcessId( *phwnd
, NULL
) == old_thread
)
147 SendMessageW( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
152 for (phwnd
= list
; *phwnd
; phwnd
++)
154 if (GetWindowThreadProcessId( *phwnd
, NULL
) == new_thread
)
155 SendMessageW( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
158 HeapFree( GetProcessHeap(), 0, list
);
164 SendMessageW( hwnd
, WM_NCACTIVATE
, hwnd
== NtUserGetForegroundWindow(), (LPARAM
)previous
);
165 SendMessageW( hwnd
, WM_ACTIVATE
,
166 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, IsIconic(hwnd
) ),
168 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == GetDesktopWindow())
169 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
172 /* now change focus if necessary */
177 info
.cbSize
= sizeof(info
);
178 NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
);
179 /* Do not change focus if the window is no more active */
180 if (hwnd
== info
.hwndActive
)
182 if (!info
.hwndFocus
|| !hwnd
|| NtUserGetAncestor( info
.hwndFocus
, GA_ROOT
) != hwnd
)
183 set_focus_window( hwnd
);
191 /*******************************************************************
192 * set_foreground_window
194 static BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
196 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
199 SERVER_START_REQ( set_foreground_window
)
201 req
->handle
= wine_server_user_handle( hwnd
);
202 if ((ret
= !wine_server_call_err( req
)))
204 previous
= wine_server_ptr_handle( reply
->previous
);
205 send_msg_old
= reply
->send_msg_old
;
206 send_msg_new
= reply
->send_msg_new
;
211 if (ret
&& previous
!= hwnd
)
213 if (send_msg_old
) /* old window belongs to other thread */
214 SendNotifyMessageW( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0 );
215 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
216 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
218 if (send_msg_new
) /* new window belongs to other thread */
219 SendNotifyMessageW( hwnd
, WM_WINE_SETACTIVEWINDOW
, (WPARAM
)hwnd
, 0 );
220 else /* new window belongs to us */
221 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
227 /*******************************************************************
228 * FOCUS_MouseActivate
230 * Activate a window as a result of a mouse click
232 BOOL
FOCUS_MouseActivate( HWND hwnd
)
234 return set_foreground_window( hwnd
, TRUE
);
238 /*******************************************************************
239 * SetActiveWindow (USER32.@)
241 HWND WINAPI
SetActiveWindow( HWND hwnd
)
245 TRACE( "%p\n", hwnd
);
251 hwnd
= WIN_GetFullHandle( hwnd
);
252 if (!IsWindow( hwnd
))
254 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
258 style
= GetWindowLongW( hwnd
, GWL_STYLE
);
259 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
260 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
263 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
268 /*****************************************************************
269 * SetFocus (USER32.@)
271 HWND WINAPI
SetFocus( HWND hwnd
)
274 HWND previous
= GetFocus();
276 TRACE( "%p prev %p\n", hwnd
, previous
);
280 /* Check if we can set the focus to this window */
281 hwnd
= WIN_GetFullHandle( hwnd
);
282 if (!IsWindow( hwnd
))
284 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
287 if (hwnd
== previous
) return previous
; /* nothing to do */
291 LONG style
= GetWindowLongW( hwndTop
, GWL_STYLE
);
292 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
293 if (!(style
& WS_CHILD
)) break;
294 parent
= NtUserGetAncestor( hwndTop
, GA_PARENT
);
295 if (!parent
|| parent
== GetDesktopWindow())
297 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return 0;
300 if (parent
== get_hwnd_message_parent()) return 0;
305 if (HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
, TRUE
)) return 0;
307 /* activate hwndTop if needed. */
308 if (hwndTop
!= GetActiveWindow())
310 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
311 if (!IsWindow( hwnd
)) return 0; /* Abort if window destroyed */
313 /* Do not change focus if the window is no longer active */
314 if (hwndTop
!= GetActiveWindow()) return 0;
317 else /* NULL hwnd passed in */
319 if (!previous
) return 0; /* nothing to do */
320 if (HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
, TRUE
)) return 0;
323 /* change focus and send messages */
324 return set_focus_window( hwnd
);
328 /*******************************************************************
329 * SetForegroundWindow (USER32.@)
331 BOOL WINAPI
SetForegroundWindow( HWND hwnd
)
333 TRACE( "%p\n", hwnd
);
335 hwnd
= WIN_GetFullHandle( hwnd
);
336 return set_foreground_window( hwnd
, FALSE
);
340 /*******************************************************************
341 * GetActiveWindow (USER32.@)
343 HWND WINAPI
GetActiveWindow(void)
346 info
.cbSize
= sizeof(info
);
347 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndActive
: 0;
351 /*****************************************************************
352 * GetFocus (USER32.@)
354 HWND WINAPI
GetFocus(void)
357 info
.cbSize
= sizeof(info
);
358 return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
) ? info
.hwndFocus
: 0;
362 /***********************************************************************
363 * SetShellWindowEx (USER32.@)
364 * hwndShell = Progman[Program Manager]
365 * |-> SHELLDLL_DefView
366 * hwndListView = | |-> SysListView32
367 * | | |-> tooltips_class32
373 BOOL WINAPI
SetShellWindowEx(HWND hwndShell
, HWND hwndListView
)
377 if (GetShellWindow())
380 if (GetWindowLongW(hwndShell
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
383 if (hwndListView
!= hwndShell
)
384 if (GetWindowLongW(hwndListView
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
387 if (hwndListView
&& hwndListView
!=hwndShell
)
388 SetWindowPos(hwndListView
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOACTIVATE
);
390 SetWindowPos(hwndShell
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOACTIVATE
);
392 SERVER_START_REQ(set_global_windows
)
394 req
->flags
= SET_GLOBAL_SHELL_WINDOWS
;
395 req
->shell_window
= wine_server_user_handle( hwndShell
);
396 req
->shell_listview
= wine_server_user_handle( hwndListView
);
397 ret
= !wine_server_call_err(req
);
405 /*******************************************************************
406 * SetShellWindow (USER32.@)
408 BOOL WINAPI
SetShellWindow(HWND hwndShell
)
410 return SetShellWindowEx(hwndShell
, hwndShell
);
414 /*******************************************************************
415 * GetShellWindow (USER32.@)
417 HWND WINAPI
GetShellWindow(void)
421 SERVER_START_REQ(set_global_windows
)
424 if (!wine_server_call_err(req
))
425 hwndShell
= wine_server_ptr_handle( reply
->old_shell_window
);
433 /***********************************************************************
434 * SetProgmanWindow (USER32.@)
436 HWND WINAPI
SetProgmanWindow ( HWND hwnd
)
438 SERVER_START_REQ(set_global_windows
)
440 req
->flags
= SET_GLOBAL_PROGMAN_WINDOW
;
441 req
->progman_window
= wine_server_user_handle( hwnd
);
442 if (wine_server_call_err( req
)) hwnd
= 0;
449 /***********************************************************************
450 * GetProgmanWindow (USER32.@)
452 HWND WINAPI
GetProgmanWindow(void)
456 SERVER_START_REQ(set_global_windows
)
459 if (!wine_server_call_err(req
))
460 ret
= wine_server_ptr_handle( reply
->old_progman_window
);
467 /***********************************************************************
468 * SetTaskmanWindow (USER32.@)
470 * hwnd = MSTaskSwWClass
471 * |-> SysTabControl32
473 HWND WINAPI
SetTaskmanWindow ( HWND hwnd
)
475 SERVER_START_REQ(set_global_windows
)
477 req
->flags
= SET_GLOBAL_TASKMAN_WINDOW
;
478 req
->taskman_window
= wine_server_user_handle( hwnd
);
479 if (wine_server_call_err( req
)) hwnd
= 0;
485 /***********************************************************************
486 * GetTaskmanWindow (USER32.@)
488 HWND WINAPI
GetTaskmanWindow(void)
492 SERVER_START_REQ(set_global_windows
)
495 if (!wine_server_call_err(req
))
496 ret
= wine_server_ptr_handle( reply
->old_taskman_window
);