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
30 #include "wine/server.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(win
);
36 /*****************************************************************
39 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
41 static HWND
set_focus_window( HWND hwnd
)
46 SERVER_START_REQ( set_focus_window
)
49 if ((ret
= !wine_server_call_err( req
))) previous
= reply
->previous
;
53 if (previous
== hwnd
) return previous
;
57 SendMessageW( previous
, WM_KILLFOCUS
, (WPARAM
)hwnd
, 0 );
58 if (hwnd
!= GetFocus()) return previous
; /* changed by the message */
62 if (USER_Driver
.pSetFocus
) USER_Driver
.pSetFocus(hwnd
);
63 SendMessageW( hwnd
, WM_SETFOCUS
, (WPARAM
)previous
, 0 );
69 /*******************************************************************
72 static BOOL
set_active_window( HWND hwnd
, HWND
*prev
, BOOL mouse
, BOOL focus
)
74 HWND previous
= GetActiveWindow();
76 DWORD old_thread
, new_thread
;
80 if (prev
) *prev
= hwnd
;
84 /* call CBT hook chain */
85 if (HOOK_IsHooked( WH_CBT
))
87 CBTACTIVATESTRUCT cbt
;
89 cbt
.hWndActive
= previous
;
90 if (HOOK_CallHooksW( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hwnd
, (LPARAM
)&cbt
)) return FALSE
;
93 if (IsWindow(previous
))
95 SendMessageW( previous
, WM_NCACTIVATE
, FALSE
, 0 );
96 SendMessageW( previous
, WM_ACTIVATE
,
97 MAKEWPARAM( WA_INACTIVE
, IsIconic(previous
) ), (LPARAM
)hwnd
);
100 SERVER_START_REQ( set_active_window
)
103 if ((ret
= !wine_server_call_err( req
))) previous
= reply
->previous
;
106 if (!ret
) return FALSE
;
107 if (prev
) *prev
= previous
;
108 if (previous
== hwnd
) return TRUE
;
112 /* send palette messages */
113 if (SendMessageW( hwnd
, WM_QUERYNEWPALETTE
, 0, 0 ))
114 SendMessageW( HWND_BROADCAST
, WM_PALETTEISCHANGING
, (WPARAM
)hwnd
, 0 );
116 if (!(GetWindowLongW( hwnd
, GWL_EXSTYLE
) & WS_EX_MANAGED
))
117 SetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
119 if (!IsWindow(hwnd
)) return FALSE
;
122 old_thread
= previous
? GetWindowThreadProcessId( previous
, NULL
) : 0;
123 new_thread
= hwnd
? GetWindowThreadProcessId( hwnd
, NULL
) : 0;
125 if (old_thread
!= new_thread
)
129 if ((list
= WIN_ListChildren( GetDesktopWindow() )))
133 for (phwnd
= list
; *phwnd
; phwnd
++)
135 if (GetWindowThreadProcessId( *phwnd
, NULL
) == old_thread
)
136 SendMessageW( *phwnd
, WM_ACTIVATEAPP
, 0, new_thread
);
141 for (phwnd
= list
; *phwnd
; phwnd
++)
143 if (GetWindowThreadProcessId( *phwnd
, NULL
) == new_thread
)
144 SendMessageW( *phwnd
, WM_ACTIVATEAPP
, 1, old_thread
);
147 HeapFree( GetProcessHeap(), 0, list
);
153 SendMessageW( hwnd
, WM_NCACTIVATE
, (hwnd
== GetForegroundWindow()), 0 );
154 SendMessageW( hwnd
, WM_ACTIVATE
,
155 MAKEWPARAM( mouse
? WA_CLICKACTIVE
: WA_ACTIVE
, IsIconic(hwnd
) ),
159 /* now change focus if necessary */
162 HWND curfocus
= GetFocus();
163 if (!curfocus
|| !hwnd
|| GetAncestor( curfocus
, GA_ROOT
) != hwnd
)
164 set_focus_window( hwnd
);
171 /*******************************************************************
172 * set_foreground_window
174 static BOOL
set_foreground_window( HWND hwnd
, BOOL mouse
)
176 BOOL ret
, send_msg_old
= FALSE
, send_msg_new
= FALSE
;
179 SERVER_START_REQ( set_foreground_window
)
182 if ((ret
= !wine_server_call_err( req
)))
184 previous
= reply
->previous
;
185 send_msg_old
= reply
->send_msg_old
;
186 send_msg_new
= reply
->send_msg_new
;
193 if (send_msg_old
) /* old window belongs to other thread */
194 SendNotifyMessageW( previous
, WM_WINE_SETACTIVEWINDOW
, 0, 0 );
195 else if (send_msg_new
) /* old window belongs to us but new one to other thread */
196 ret
= set_active_window( 0, NULL
, mouse
, TRUE
);
198 if (send_msg_new
) /* new window belongs to other thread */
199 SendNotifyMessageW( hwnd
, WM_WINE_SETACTIVEWINDOW
, hwnd
, 0 );
200 else /* new window belongs to us */
201 ret
= set_active_window( hwnd
, NULL
, mouse
, TRUE
);
207 /*******************************************************************
208 * FOCUS_MouseActivate
210 * Activate a window as a result of a mouse click
212 BOOL
FOCUS_MouseActivate( HWND hwnd
)
214 return set_foreground_window( hwnd
, TRUE
);
218 /*******************************************************************
219 * SetActiveWindow (USER32.@)
221 HWND WINAPI
SetActiveWindow( HWND hwnd
)
225 TRACE( "%x\n", hwnd
);
229 LONG style
= GetWindowLongW( hwnd
, GWL_STYLE
);
231 if (!(style
& WS_VISIBLE
) || (style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
232 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
234 hwnd
= WIN_GetFullHandle( hwnd
);
237 if (!set_active_window( hwnd
, &prev
, FALSE
, TRUE
)) return 0;
242 /*****************************************************************
243 * SetFocus (USER32.@)
245 HWND WINAPI
SetFocus( HWND hwnd
)
248 HWND previous
= GetFocus();
250 TRACE( "%x prev %x\n", hwnd
, previous
);
254 /* Check if we can set the focus to this window */
255 hwnd
= WIN_GetFullHandle( hwnd
);
256 if (hwnd
== previous
) return previous
; /* nothing to do */
260 LONG style
= GetWindowLongW( hwndTop
, GWL_STYLE
);
261 if (style
& (WS_MINIMIZE
| WS_DISABLED
)) return 0;
262 parent
= GetAncestor( hwndTop
, GA_PARENT
);
263 if (!parent
|| parent
== GetDesktopWindow()) break;
268 if (HOOK_CallHooksW( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)hwnd
, (LPARAM
)previous
)) return 0;
270 /* activate hwndTop if needed. */
271 if (hwndTop
!= GetActiveWindow())
273 if (!set_active_window( hwndTop
, NULL
, FALSE
, FALSE
)) return 0;
274 if (!IsWindow( hwnd
)) return 0; /* Abort if window destroyed */
277 else /* NULL hwnd passed in */
279 if (!previous
) return 0; /* nothing to do */
280 if( HOOK_CallHooksW( WH_CBT
, HCBT_SETFOCUS
, 0, (LPARAM
)previous
) )
284 /* change focus and send messages */
285 return set_focus_window( hwnd
);
289 /*******************************************************************
290 * SetForegroundWindow (USER32.@)
292 BOOL WINAPI
SetForegroundWindow( HWND hwnd
)
294 TRACE( "%x\n", hwnd
);
295 if (hwnd
) hwnd
= WIN_GetFullHandle( hwnd
);
296 return set_foreground_window( hwnd
, FALSE
);
300 /*******************************************************************
301 * GetActiveWindow (USER32.@)
303 HWND WINAPI
GetActiveWindow(void)
307 SERVER_START_REQ( get_thread_input
)
309 req
->tid
= GetCurrentThreadId();
310 if (!wine_server_call_err( req
)) ret
= reply
->active
;
317 /*****************************************************************
318 * GetFocus (USER32.@)
320 HWND WINAPI
GetFocus(void)
324 SERVER_START_REQ( get_thread_input
)
326 req
->tid
= GetCurrentThreadId();
327 if (!wine_server_call_err( req
)) ret
= reply
->focus
;
334 /*******************************************************************
335 * GetForegroundWindow (USER32.@)
337 HWND WINAPI
GetForegroundWindow(void)
341 SERVER_START_REQ( get_thread_input
)
344 if (!wine_server_call_err( req
)) ret
= reply
->foreground
;