Release 20030408.
[wine/gsoc-2012-control.git] / dlls / user / focus.c
blob46e446bd94ff107f10983dff065fd21e309a8fd3
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "winerror.h"
26 #include "win.h"
27 #include "message.h"
28 #include "user.h"
29 #include "wine/server.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(win);
35 /*****************************************************************
36 * set_focus_window
38 * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
40 static HWND set_focus_window( HWND hwnd )
42 HWND previous = 0;
43 BOOL ret;
45 SERVER_START_REQ( set_focus_window )
47 req->handle = hwnd;
48 if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
50 SERVER_END_REQ;
51 if (!ret) return 0;
52 if (previous == hwnd) return previous;
54 if (previous)
56 SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
57 if (hwnd != GetFocus()) return previous; /* changed by the message */
59 if (IsWindow(hwnd))
61 if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hwnd);
62 SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
64 return previous;
68 /*******************************************************************
69 * set_active_window
71 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
73 HWND previous = GetActiveWindow();
74 BOOL ret;
75 DWORD old_thread, new_thread;
76 CBTACTIVATESTRUCT cbt;
78 if (previous == hwnd)
80 if (prev) *prev = hwnd;
81 return TRUE;
84 /* call CBT hook chain */
85 cbt.fMouse = mouse;
86 cbt.hWndActive = previous;
87 if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
89 if (IsWindow(previous))
91 SendMessageW( previous, WM_NCACTIVATE, FALSE, 0 );
92 SendMessageW( previous, WM_ACTIVATE,
93 MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
96 SERVER_START_REQ( set_active_window )
98 req->handle = hwnd;
99 if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
101 SERVER_END_REQ;
102 if (!ret) return FALSE;
103 if (prev) *prev = previous;
104 if (previous == hwnd) return TRUE;
106 if (hwnd)
108 /* send palette messages */
109 if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
110 SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 );
112 if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED))
113 SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
115 if (!IsWindow(hwnd)) return FALSE;
118 old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
119 new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
121 if (old_thread != new_thread)
123 HWND *list, *phwnd;
125 if ((list = WIN_ListChildren( GetDesktopWindow() )))
127 if (old_thread)
129 for (phwnd = list; *phwnd; phwnd++)
131 if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
132 SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
135 if (new_thread)
137 for (phwnd = list; *phwnd; phwnd++)
139 if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
140 SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
143 HeapFree( GetProcessHeap(), 0, list );
147 if (IsWindow(hwnd))
149 SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), 0 );
150 SendMessageW( hwnd, WM_ACTIVATE,
151 MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
152 (LPARAM)previous );
155 /* now change focus if necessary */
156 if (focus)
158 HWND curfocus = GetFocus();
159 if (!curfocus || !hwnd || GetAncestor( curfocus, GA_ROOT ) != hwnd)
160 set_focus_window( hwnd );
163 return TRUE;
167 /*******************************************************************
168 * set_foreground_window
170 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
172 BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
173 HWND previous = 0;
175 SERVER_START_REQ( set_foreground_window )
177 req->handle = hwnd;
178 if ((ret = !wine_server_call_err( req )))
180 previous = reply->previous;
181 send_msg_old = reply->send_msg_old;
182 send_msg_new = reply->send_msg_new;
185 SERVER_END_REQ;
187 if (ret)
189 if (send_msg_old) /* old window belongs to other thread */
190 SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
191 else if (send_msg_new) /* old window belongs to us but new one to other thread */
192 ret = set_active_window( 0, NULL, mouse, TRUE );
194 if (send_msg_new) /* new window belongs to other thread */
195 SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
196 else /* new window belongs to us */
197 ret = set_active_window( hwnd, NULL, mouse, TRUE );
199 return ret;
203 /*******************************************************************
204 * FOCUS_MouseActivate
206 * Activate a window as a result of a mouse click
208 BOOL FOCUS_MouseActivate( HWND hwnd )
210 return set_foreground_window( hwnd, TRUE );
214 /*******************************************************************
215 * SetActiveWindow (USER32.@)
217 HWND WINAPI SetActiveWindow( HWND hwnd )
219 HWND prev;
221 TRACE( "%p\n", hwnd );
223 if (hwnd)
225 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
227 if (!(style & WS_VISIBLE) || (style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
228 return GetActiveWindow(); /* Windows doesn't seem to return an error here */
230 hwnd = WIN_GetFullHandle( hwnd );
233 if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
234 return prev;
238 /*****************************************************************
239 * SetFocus (USER32.@)
241 HWND WINAPI SetFocus( HWND hwnd )
243 HWND hwndTop = hwnd;
244 HWND previous = GetFocus();
246 TRACE( "%p prev %p\n", hwnd, previous );
248 if (hwnd)
250 /* Check if we can set the focus to this window */
251 hwnd = WIN_GetFullHandle( hwnd );
252 if (hwnd == previous) return previous; /* nothing to do */
253 for (;;)
255 HWND parent;
256 LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
257 if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
258 parent = GetAncestor( hwndTop, GA_PARENT );
259 if (!parent || parent == GetDesktopWindow()) break;
260 hwndTop = parent;
263 /* call hooks */
264 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
266 /* activate hwndTop if needed. */
267 if (hwndTop != GetActiveWindow())
269 if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
270 if (!IsWindow( hwnd )) return 0; /* Abort if window destroyed */
273 else /* NULL hwnd passed in */
275 if (!previous) return 0; /* nothing to do */
276 if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
279 /* change focus and send messages */
280 return set_focus_window( hwnd );
284 /*******************************************************************
285 * SetForegroundWindow (USER32.@)
287 BOOL WINAPI SetForegroundWindow( HWND hwnd )
289 TRACE( "%p\n", hwnd );
290 if (hwnd) hwnd = WIN_GetFullHandle( hwnd );
291 return set_foreground_window( hwnd, FALSE );
295 /*******************************************************************
296 * GetActiveWindow (USER32.@)
298 HWND WINAPI GetActiveWindow(void)
300 HWND ret = 0;
302 SERVER_START_REQ( get_thread_input )
304 req->tid = GetCurrentThreadId();
305 if (!wine_server_call_err( req )) ret = reply->active;
307 SERVER_END_REQ;
308 return ret;
312 /*****************************************************************
313 * GetFocus (USER32.@)
315 HWND WINAPI GetFocus(void)
317 HWND ret = 0;
319 SERVER_START_REQ( get_thread_input )
321 req->tid = GetCurrentThreadId();
322 if (!wine_server_call_err( req )) ret = reply->focus;
324 SERVER_END_REQ;
325 return ret;
329 /*******************************************************************
330 * GetForegroundWindow (USER32.@)
332 HWND WINAPI GetForegroundWindow(void)
334 HWND ret = 0;
336 SERVER_START_REQ( get_thread_input )
338 req->tid = 0;
339 if (!wine_server_call_err( req )) ret = reply->foreground;
341 SERVER_END_REQ;
342 return ret;