Remove obsolete code from DOSVM_Wait.
[wine] / dlls / user / focus.c
1 /*
2  * Focus and activation functions
3  *
4  * Copyright 1993 David Metcalfe
5  * Copyright 1995 Alex Korobka
6  * Copyright 1994, 2002 Alexandre Julliard
7  *
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.
12  *
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.
17  *
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
21  */
22
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"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(win);
33
34
35 /*****************************************************************
36  *              set_focus_window
37  *
38  * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
39  */
40 static HWND set_focus_window( HWND hwnd )
41 {
42     HWND previous = 0;
43     BOOL ret;
44
45     SERVER_START_REQ( set_focus_window )
46     {
47         req->handle = hwnd;
48         if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
49     }
50     SERVER_END_REQ;
51     if (!ret) return 0;
52     if (previous == hwnd) return previous;
53
54     if (previous)
55     {
56         SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
57         if (hwnd != GetFocus()) return previous;  /* changed by the message */
58     }
59     if (IsWindow(hwnd))
60     {
61         if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hwnd);
62         SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
63     }
64     return previous;
65 }
66
67
68 /*******************************************************************
69  *              set_active_window
70  */
71 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
72 {
73     HWND previous = GetActiveWindow();
74     BOOL ret;
75     DWORD old_thread, new_thread;
76     CBTACTIVATESTRUCT cbt;
77
78     if (previous == hwnd)
79     {
80         if (prev) *prev = hwnd;
81         return TRUE;
82     }
83
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;
88
89     if (IsWindow(previous))
90     {
91         SendMessageW( previous, WM_NCACTIVATE, FALSE, 0 );
92         SendMessageW( previous, WM_ACTIVATE,
93                       MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
94     }
95
96     SERVER_START_REQ( set_active_window )
97     {
98         req->handle = hwnd;
99         if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
100     }
101     SERVER_END_REQ;
102     if (!ret) return FALSE;
103     if (prev) *prev = previous;
104     if (previous == hwnd) return TRUE;
105
106     if (hwnd)
107     {
108         /* send palette messages */
109         if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
110             SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 );
111
112         if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED))
113             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
114
115         if (!IsWindow(hwnd)) return FALSE;
116     }
117
118     old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
119     new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
120
121     if (old_thread != new_thread)
122     {
123         HWND *list, *phwnd;
124
125         if ((list = WIN_ListChildren( GetDesktopWindow() )))
126         {
127             if (old_thread)
128             {
129                 for (phwnd = list; *phwnd; phwnd++)
130                 {
131                     if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
132                         SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
133                 }
134             }
135             if (new_thread)
136             {
137                 for (phwnd = list; *phwnd; phwnd++)
138                 {
139                     if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
140                         SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
141                 }
142             }
143             HeapFree( GetProcessHeap(), 0, list );
144         }
145     }
146
147     if (IsWindow(hwnd))
148     {
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 );
153     }
154
155     /* now change focus if necessary */
156     if (focus)
157     {
158         HWND curfocus = GetFocus();
159         if (!curfocus || !hwnd || GetAncestor( curfocus, GA_ROOT ) != hwnd)
160             set_focus_window( hwnd );
161     }
162
163     return TRUE;
164 }
165
166
167 /*******************************************************************
168  *              set_foreground_window
169  */
170 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
171 {
172     BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
173     HWND previous = 0;
174
175     SERVER_START_REQ( set_foreground_window )
176     {
177         req->handle = hwnd;
178         if ((ret = !wine_server_call_err( req )))
179         {
180             previous = reply->previous;
181             send_msg_old = reply->send_msg_old;
182             send_msg_new = reply->send_msg_new;
183         }
184     }
185     SERVER_END_REQ;
186
187     if (ret)
188     {
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 );
193
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 );
198     }
199     return ret;
200 }
201
202
203 /*******************************************************************
204  *              FOCUS_MouseActivate
205  *
206  * Activate a window as a result of a mouse click
207  */
208 BOOL FOCUS_MouseActivate( HWND hwnd )
209 {
210     return set_foreground_window( hwnd, TRUE );
211 }
212
213
214 /*******************************************************************
215  *              SetActiveWindow (USER32.@)
216  */
217 HWND WINAPI SetActiveWindow( HWND hwnd )
218 {
219     HWND prev;
220
221     TRACE( "%p\n", hwnd );
222
223     if (hwnd)
224     {
225         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
226
227         if (!(style & WS_VISIBLE) || (style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
228             return GetActiveWindow();  /* Windows doesn't seem to return an error here */
229
230         hwnd = WIN_GetFullHandle( hwnd );
231     }
232
233     if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
234     return prev;
235 }
236
237
238 /*****************************************************************
239  *              SetFocus  (USER32.@)
240  */
241 HWND WINAPI SetFocus( HWND hwnd )
242 {
243     HWND hwndTop = hwnd;
244     HWND previous = GetFocus();
245
246     TRACE( "%p prev %p\n", hwnd, previous );
247
248     if (hwnd)
249     {
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 (;;)
254         {
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;
261         }
262
263         /* call hooks */
264         if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
265
266         /* activate hwndTop if needed. */
267         if (hwndTop != GetActiveWindow())
268         {
269             if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
270             if (!IsWindow( hwnd )) return 0;  /* Abort if window destroyed */
271         }
272     }
273     else /* NULL hwnd passed in */
274     {
275         if (!previous) return 0;  /* nothing to do */
276         if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
277     }
278
279     /* change focus and send messages */
280     return set_focus_window( hwnd );
281 }
282
283
284 /*******************************************************************
285  *              SetForegroundWindow  (USER32.@)
286  */
287 BOOL WINAPI SetForegroundWindow( HWND hwnd )
288 {
289     TRACE( "%p\n", hwnd );
290     if (hwnd) hwnd = WIN_GetFullHandle( hwnd );
291     return set_foreground_window( hwnd, FALSE );
292 }
293
294
295 /*******************************************************************
296  *              GetActiveWindow  (USER32.@)
297  */
298 HWND WINAPI GetActiveWindow(void)
299 {
300     HWND ret = 0;
301
302     SERVER_START_REQ( get_thread_input )
303     {
304         req->tid = GetCurrentThreadId();
305         if (!wine_server_call_err( req )) ret = reply->active;
306     }
307     SERVER_END_REQ;
308     return ret;
309 }
310
311
312 /*****************************************************************
313  *              GetFocus  (USER32.@)
314  */
315 HWND WINAPI GetFocus(void)
316 {
317     HWND ret = 0;
318
319     SERVER_START_REQ( get_thread_input )
320     {
321         req->tid = GetCurrentThreadId();
322         if (!wine_server_call_err( req )) ret = reply->focus;
323     }
324     SERVER_END_REQ;
325     return ret;
326 }
327
328
329 /*******************************************************************
330  *              GetForegroundWindow  (USER32.@)
331  */
332 HWND WINAPI GetForegroundWindow(void)
333 {
334     HWND ret = 0;
335
336     SERVER_START_REQ( get_thread_input )
337     {
338         req->tid = 0;
339         if (!wine_server_call_err( req )) ret = reply->foreground;
340     }
341     SERVER_END_REQ;
342     return ret;
343 }