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
24 #include "wine/port.h"
33 #include "user_private.h"
34 #include "wine/server.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(win
);
40 /*****************************************************************
43 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
45 static HWND
set_focus_window( HWND hwnd
)
50 SERVER_START_REQ( set_focus_window
)
53 if ((ret
= !wine_server_call_err( req
))) previous
= reply
->previous
;
57 if (previous
== hwnd
) return previous
;
61 SendMessageW( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
62 if (hwnd
!= GetFocus()) return previous
; /* changed by the message */
66 if (USER_Driver
.pSetFocus
) USER_Driver
.pSetFocus(hwnd
);
67 SendMessageW( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
73 /*******************************************************************
76 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
78 HWND previous
= GetActiveWindow();
80 DWORD old_thread
, new_thread
;
81 CBTACTIVATESTRUCT cbt
;
85 if (prev
) *prev
= hwnd
;
89 /* call CBT hook chain */
91 cbt
.hWndActive
= previous
;
92 if (HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
, TRUE
)) return FALSE
;
94 if (IsWindow(previous
))
96 SendMessageW( previous
, WM_NCACTIVATE
, FALSE
, (LPARAM
)hwnd
);
97 SendMessageW( previous
, WM_ACTIVATE
,
98 MAKEWPARAM( WA_INACTIVE
, IsIconic(previous
) ), (LPARAM
)hwnd
);
101 SERVER_START_REQ( set_active_window
)
104 if ((ret
= !wine_server_call_err( req
))) previous
= reply
->previous
;
107 if (!ret
) return FALSE
;
108 if (prev
) *prev
= previous
;
109 if (previous
== hwnd
) return TRUE
;
113 /* send palette messages */
114 if (SendMessageW( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
115 SendMessageTimeoutW( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0,
116 SMTO_ABORTIFHUNG
, 2000, NULL
);
118 if (!GetPropA( hwnd
, "__wine_x11_managed" ))
119 SetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
121 if (!IsWindow(hwnd
)) return FALSE
;
124 old_thread
= previous
? GetWindowThreadProcessId( previous
, NULL
) : 0;
125 new_thread
= hwnd
? GetWindowThreadProcessId( hwnd
, NULL
) : 0;
127 if (old_thread
!= new_thread
)
131 if ((list
= WIN_ListChildren( GetDesktopWindow() )))
135 for (phwnd
= list
; *phwnd
; phwnd
++)
137 if (GetWindowThreadProcessId( *phwnd
, NULL
) == old_thread
)
138 SendMessageW( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
143 for (phwnd
= list
; *phwnd
; phwnd
++)
145 if (GetWindowThreadProcessId( *phwnd
, NULL
) == new_thread
)
146 SendMessageW( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
149 HeapFree( GetProcessHeap(), 0, list
);
155 SendMessageW( hwnd
, WM_NCACTIVATE
, (hwnd
== GetForegroundWindow()), (LPARAM
)previous
);
156 SendMessageW( hwnd
, WM_ACTIVATE
,
157 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, IsIconic(hwnd
) ),
161 /* now change focus if necessary */
164 HWND curfocus
= GetFocus();
165 if (!curfocus
|| !hwnd
|| GetAncestor( curfocus
, GA_ROOT
) != hwnd
)
166 set_focus_window( hwnd
);
173 /*******************************************************************
174 * set_foreground_window
176 static BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
178 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
181 SERVER_START_REQ( set_foreground_window
)
184 if ((ret
= !wine_server_call_err( req
)))
186 previous
= reply
->previous
;
187 send_msg_old
= reply
->send_msg_old
;
188 send_msg_new
= reply
->send_msg_new
;
195 if (send_msg_old
) /* old window belongs to other thread */
196 SendNotifyMessageW( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0 );
197 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
198 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
200 if (send_msg_new
) /* new window belongs to other thread */
201 SendNotifyMessageW( hwnd
, WM_WINE_SETACTIVEWINDOW
, (WPARAM
)hwnd
, 0 );
202 else /* new window belongs to us */
203 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
209 /*******************************************************************
210 * FOCUS_MouseActivate
212 * Activate a window as a result of a mouse click
214 BOOL
FOCUS_MouseActivate( HWND hwnd
)
216 return set_foreground_window( hwnd
, TRUE
);
220 /*******************************************************************
221 * SetActiveWindow (USER32.@)
223 HWND WINAPI
SetActiveWindow( HWND hwnd
)
227 TRACE( "%p\n", hwnd
);
231 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
233 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
234 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
236 hwnd
= WIN_GetFullHandle( hwnd
);
239 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
244 /*****************************************************************
245 * SetFocus (USER32.@)
247 HWND WINAPI
SetFocus( HWND hwnd
)
250 HWND previous
= GetFocus();
252 TRACE( "%p prev %p\n", hwnd
, previous
);
256 /* Check if we can set the focus to this window */
257 hwnd
= WIN_GetFullHandle( hwnd
);
258 if (hwnd
== previous
) return previous
; /* nothing to do */
262 LONG style
= GetWindowLongW( hwndTop
, GWL_STYLE
);
263 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
264 parent
= GetAncestor( hwndTop
, GA_PARENT
);
265 if (!parent
|| parent
== GetDesktopWindow()) break;
270 if (HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
, TRUE
)) return 0;
272 /* activate hwndTop if needed. */
273 if (hwndTop
!= GetActiveWindow())
275 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
276 if (!IsWindow( hwnd
)) return 0; /* Abort if window destroyed */
279 else /* NULL hwnd passed in */
281 if (!previous
) return 0; /* nothing to do */
282 if (HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
, TRUE
)) return 0;
285 /* change focus and send messages */
286 return set_focus_window( hwnd
);
290 /*******************************************************************
291 * SetForegroundWindow (USER32.@)
293 BOOL WINAPI
SetForegroundWindow( HWND hwnd
)
295 TRACE( "%p\n", hwnd
);
296 if (hwnd
) hwnd
= WIN_GetFullHandle( hwnd
);
297 return set_foreground_window( hwnd
, FALSE
);
301 /*******************************************************************
302 * GetActiveWindow (USER32.@)
304 HWND WINAPI
GetActiveWindow(void)
308 SERVER_START_REQ( get_thread_input
)
310 req
->tid
= GetCurrentThreadId();
311 if (!wine_server_call_err( req
)) ret
= reply
->active
;
318 /*****************************************************************
319 * GetFocus (USER32.@)
321 HWND WINAPI
GetFocus(void)
325 SERVER_START_REQ( get_thread_input
)
327 req
->tid
= GetCurrentThreadId();
328 if (!wine_server_call_err( req
)) ret
= reply
->focus
;
335 /*******************************************************************
336 * GetForegroundWindow (USER32.@)
338 HWND WINAPI
GetForegroundWindow(void)
342 SERVER_START_REQ( get_thread_input
)
345 if (!wine_server_call_err( req
)) ret
= reply
->foreground
;
352 /***********************************************************************
353 * SetShellWindowEx (USER32.@)
354 * hwndShell = Progman[Program Manager]
355 * |-> SHELLDLL_DefView
356 * hwndListView = | |-> SysListView32
357 * | | |-> tooltips_class32
363 BOOL WINAPI
SetShellWindowEx(HWND hwndShell
, HWND hwndListView
)
367 if (GetShellWindow())
370 if (GetWindowLongW(hwndShell
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
373 if (hwndListView
!= hwndShell
)
374 if (GetWindowLongW(hwndListView
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
377 if (hwndListView
&& hwndListView
!=hwndShell
)
378 SetWindowPos(hwndListView
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOACTIVATE
);
380 SetWindowPos(hwndShell
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOACTIVATE
);
382 SERVER_START_REQ(set_global_windows
)
384 req
->flags
= SET_GLOBAL_SHELL_WINDOWS
;
385 req
->shell_window
= hwndShell
;
386 req
->shell_listview
= hwndListView
;
387 ret
= !wine_server_call_err(req
);
395 /*******************************************************************
396 * SetShellWindow (USER32.@)
398 BOOL WINAPI
SetShellWindow(HWND hwndShell
)
400 return SetShellWindowEx(hwndShell
, hwndShell
);
404 /*******************************************************************
405 * GetShellWindow (USER32.@)
407 HWND WINAPI
GetShellWindow(void)
411 SERVER_START_REQ(set_global_windows
)
414 if (!wine_server_call_err(req
))
415 hwndShell
= reply
->old_shell_window
;
423 /***********************************************************************
424 * SetProgmanWindow (USER32.@)
426 HWND WINAPI
SetProgmanWindow ( HWND hwnd
)
428 SERVER_START_REQ(set_global_windows
)
430 req
->flags
= SET_GLOBAL_PROGMAN_WINDOW
;
431 req
->progman_window
= hwnd
;
432 if (wine_server_call_err( req
)) hwnd
= 0;
439 /***********************************************************************
440 * GetProgmanWindow (USER32.@)
442 HWND WINAPI
GetProgmanWindow(void)
446 SERVER_START_REQ(set_global_windows
)
449 if (!wine_server_call_err(req
)) ret
= reply
->old_progman_window
;
456 /***********************************************************************
457 * SetTaskmanWindow (USER32.@)
459 * hwnd = MSTaskSwWClass
460 * |-> SysTabControl32
462 HWND WINAPI
SetTaskmanWindow ( HWND hwnd
)
464 SERVER_START_REQ(set_global_windows
)
466 req
->flags
= SET_GLOBAL_TASKMAN_WINDOW
;
467 req
->taskman_window
= hwnd
;
468 if (wine_server_call_err( req
)) hwnd
= 0;
474 /***********************************************************************
475 * GetTaskmanWindow (USER32.@)
477 HWND WINAPI
GetTaskmanWindow(void)
481 SERVER_START_REQ(set_global_windows
)
484 if (!wine_server_call_err(req
)) ret
= reply
->old_taskman_window
;