INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[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 <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "win.h"
30 #include "message.h"
31 #include "user.h"
32 #include "wine/server.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(win);
36
37
38 /*****************************************************************
39  *              set_focus_window
40  *
41  * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
42  */
43 static HWND set_focus_window( HWND hwnd )
44 {
45     HWND previous = 0;
46     BOOL ret;
47
48     SERVER_START_REQ( set_focus_window )
49     {
50         req->handle = hwnd;
51         if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
52     }
53     SERVER_END_REQ;
54     if (!ret) return 0;
55     if (previous == hwnd) return previous;
56
57     if (previous)
58     {
59         SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
60         if (hwnd != GetFocus()) return previous;  /* changed by the message */
61     }
62     if (IsWindow(hwnd))
63     {
64         if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hwnd);
65         SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
66     }
67     return previous;
68 }
69
70
71 /*******************************************************************
72  *              set_active_window
73  */
74 static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
75 {
76     HWND previous = GetActiveWindow();
77     BOOL ret;
78     DWORD old_thread, new_thread;
79     CBTACTIVATESTRUCT cbt;
80
81     if (previous == hwnd)
82     {
83         if (prev) *prev = hwnd;
84         return TRUE;
85     }
86
87     /* call CBT hook chain */
88     cbt.fMouse     = mouse;
89     cbt.hWndActive = previous;
90     if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE;
91
92     if (IsWindow(previous))
93     {
94         SendMessageW( previous, WM_NCACTIVATE, FALSE, 0 );
95         SendMessageW( previous, WM_ACTIVATE,
96                       MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
97     }
98
99     SERVER_START_REQ( set_active_window )
100     {
101         req->handle = hwnd;
102         if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
103     }
104     SERVER_END_REQ;
105     if (!ret) return FALSE;
106     if (prev) *prev = previous;
107     if (previous == hwnd) return TRUE;
108
109     if (hwnd)
110     {
111         /* send palette messages */
112         if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
113             SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0,
114                                  SMTO_ABORTIFHUNG, 2000, NULL );
115
116         if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED))
117             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
118
119         if (!IsWindow(hwnd)) return FALSE;
120     }
121
122     old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
123     new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
124
125     if (old_thread != new_thread)
126     {
127         HWND *list, *phwnd;
128
129         if ((list = WIN_ListChildren( GetDesktopWindow() )))
130         {
131             if (old_thread)
132             {
133                 for (phwnd = list; *phwnd; phwnd++)
134                 {
135                     if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
136                         SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
137                 }
138             }
139             if (new_thread)
140             {
141                 for (phwnd = list; *phwnd; phwnd++)
142                 {
143                     if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
144                         SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
145                 }
146             }
147             HeapFree( GetProcessHeap(), 0, list );
148         }
149     }
150
151     if (IsWindow(hwnd))
152     {
153         SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), 0 );
154         SendMessageW( hwnd, WM_ACTIVATE,
155                       MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
156                       (LPARAM)previous );
157     }
158
159     /* now change focus if necessary */
160     if (focus)
161     {
162         HWND curfocus = GetFocus();
163         if (!curfocus || !hwnd || GetAncestor( curfocus, GA_ROOT ) != hwnd)
164             set_focus_window( hwnd );
165     }
166
167     return TRUE;
168 }
169
170
171 /*******************************************************************
172  *              set_foreground_window
173  */
174 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
175 {
176     BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
177     HWND previous = 0;
178
179     SERVER_START_REQ( set_foreground_window )
180     {
181         req->handle = hwnd;
182         if ((ret = !wine_server_call_err( req )))
183         {
184             previous = reply->previous;
185             send_msg_old = reply->send_msg_old;
186             send_msg_new = reply->send_msg_new;
187         }
188     }
189     SERVER_END_REQ;
190
191     if (ret)
192     {
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 );
197
198         if (send_msg_new)  /* new window belongs to other thread */
199             SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
200         else  /* new window belongs to us */
201             ret = set_active_window( hwnd, NULL, mouse, TRUE );
202     }
203     return ret;
204 }
205
206
207 /*******************************************************************
208  *              FOCUS_MouseActivate
209  *
210  * Activate a window as a result of a mouse click
211  */
212 BOOL FOCUS_MouseActivate( HWND hwnd )
213 {
214     return set_foreground_window( hwnd, TRUE );
215 }
216
217
218 /*******************************************************************
219  *              SetActiveWindow (USER32.@)
220  */
221 HWND WINAPI SetActiveWindow( HWND hwnd )
222 {
223     HWND prev;
224
225     TRACE( "%p\n", hwnd );
226
227     if (hwnd)
228     {
229         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
230
231         if (!(style & WS_VISIBLE) || (style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
232             return GetActiveWindow();  /* Windows doesn't seem to return an error here */
233
234         hwnd = WIN_GetFullHandle( hwnd );
235     }
236
237     if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
238     return prev;
239 }
240
241
242 /*****************************************************************
243  *              SetFocus  (USER32.@)
244  */
245 HWND WINAPI SetFocus( HWND hwnd )
246 {
247     HWND hwndTop = hwnd;
248     HWND previous = GetFocus();
249
250     TRACE( "%p prev %p\n", hwnd, previous );
251
252     if (hwnd)
253     {
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 */
257         for (;;)
258         {
259             HWND parent;
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;
264             hwndTop = parent;
265         }
266
267         /* call hooks */
268         if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous, TRUE )) return 0;
269
270         /* activate hwndTop if needed. */
271         if (hwndTop != GetActiveWindow())
272         {
273             if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
274             if (!IsWindow( hwnd )) return 0;  /* Abort if window destroyed */
275         }
276     }
277     else /* NULL hwnd passed in */
278     {
279         if (!previous) return 0;  /* nothing to do */
280         if (HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous, TRUE )) return 0;
281     }
282
283     /* change focus and send messages */
284     return set_focus_window( hwnd );
285 }
286
287
288 /*******************************************************************
289  *              SetForegroundWindow  (USER32.@)
290  */
291 BOOL WINAPI SetForegroundWindow( HWND hwnd )
292 {
293     TRACE( "%p\n", hwnd );
294     if (hwnd) hwnd = WIN_GetFullHandle( hwnd );
295     return set_foreground_window( hwnd, FALSE );
296 }
297
298
299 /*******************************************************************
300  *              GetActiveWindow  (USER32.@)
301  */
302 HWND WINAPI GetActiveWindow(void)
303 {
304     HWND ret = 0;
305
306     SERVER_START_REQ( get_thread_input )
307     {
308         req->tid = GetCurrentThreadId();
309         if (!wine_server_call_err( req )) ret = reply->active;
310     }
311     SERVER_END_REQ;
312     return ret;
313 }
314
315
316 /*****************************************************************
317  *              GetFocus  (USER32.@)
318  */
319 HWND WINAPI GetFocus(void)
320 {
321     HWND ret = 0;
322
323     SERVER_START_REQ( get_thread_input )
324     {
325         req->tid = GetCurrentThreadId();
326         if (!wine_server_call_err( req )) ret = reply->focus;
327     }
328     SERVER_END_REQ;
329     return ret;
330 }
331
332
333 /*******************************************************************
334  *              GetForegroundWindow  (USER32.@)
335  */
336 HWND WINAPI GetForegroundWindow(void)
337 {
338     HWND ret = 0;
339
340     SERVER_START_REQ( get_thread_input )
341     {
342         req->tid = 0;
343         if (!wine_server_call_err( req )) ret = reply->foreground;
344     }
345     SERVER_END_REQ;
346     return ret;
347 }
348
349
350 /***********************************************************************
351 *               SetShellWindowEx (USER32.@)
352 * hwndShell =    Progman[Program Manager]
353 *                |-> SHELLDLL_DefView
354 * hwndListView = |   |-> SysListView32
355 *                |   |   |-> tooltips_class32
356 *                |   |
357 *                |   |-> SysHeader32
358 *                |
359 *                |-> ProxyTarget
360 */
361 BOOL WINAPI SetShellWindowEx(HWND hwndShell, HWND hwndListView)
362 {
363     BOOL ret;
364
365     if (GetShellWindow())
366         return FALSE;
367
368     if (GetWindowLongW(hwndShell, GWL_EXSTYLE) & WS_EX_TOPMOST)
369         return FALSE;
370
371     if (hwndListView != hwndShell)
372         if (GetWindowLongW(hwndListView, GWL_EXSTYLE) & WS_EX_TOPMOST)
373             return FALSE;
374
375     if (hwndListView && hwndListView!=hwndShell)
376         SetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
377
378     SetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
379
380     SERVER_START_REQ(set_global_windows)
381     {
382         req->flags          = SET_GLOBAL_SHELL_WINDOWS;
383         req->shell_window   = hwndShell;
384         req->shell_listview = hwndListView;
385         ret = !wine_server_call_err(req);
386     }
387     SERVER_END_REQ;
388
389     return ret;
390 }
391
392
393 /*******************************************************************
394 *               SetShellWindow (USER32.@)
395 */
396 BOOL WINAPI SetShellWindow(HWND hwndShell)
397 {
398     return SetShellWindowEx(hwndShell, hwndShell);
399 }
400
401
402 /*******************************************************************
403 *               GetShellWindow (USER32.@)
404 */
405 HWND WINAPI GetShellWindow(void)
406 {
407     HWND hwndShell = 0;
408
409     SERVER_START_REQ(set_global_windows)
410     {
411         req->flags = 0;
412         if (!wine_server_call_err(req))
413             hwndShell = reply->old_shell_window;
414     }
415     SERVER_END_REQ;
416
417     return hwndShell;
418 }
419
420
421 /***********************************************************************
422  *              SetProgmanWindow (USER32.@)
423  */
424 HWND WINAPI SetProgmanWindow ( HWND hwnd )
425 {
426     SERVER_START_REQ(set_global_windows)
427     {
428         req->flags          = SET_GLOBAL_PROGMAN_WINDOW;
429         req->progman_window = hwnd;
430         if (wine_server_call_err( req )) hwnd = 0;
431     }
432     SERVER_END_REQ;
433     return hwnd;
434 }
435
436
437 /***********************************************************************
438  *              GetProgmanWindow (USER32.@)
439  */
440 HWND WINAPI GetProgmanWindow(void)
441 {
442     HWND ret = 0;
443
444     SERVER_START_REQ(set_global_windows)
445     {
446         req->flags = 0;
447         if (!wine_server_call_err(req)) ret = reply->old_progman_window;
448     }
449     SERVER_END_REQ;
450     return ret;
451 }
452
453
454 /***********************************************************************
455  *              SetTaskmanWindow (USER32.@)
456  * NOTES
457  *   hwnd = MSTaskSwWClass
458  *          |-> SysTabControl32
459  */
460 HWND WINAPI SetTaskmanWindow ( HWND hwnd )
461 {
462     SERVER_START_REQ(set_global_windows)
463     {
464         req->flags          = SET_GLOBAL_TASKMAN_WINDOW;
465         req->taskman_window = hwnd;
466         if (wine_server_call_err( req )) hwnd = 0;
467     }
468     SERVER_END_REQ;
469     return hwnd;
470 }
471
472 /***********************************************************************
473  *              GetTaskmanWindow (USER32.@)
474  */
475 HWND WINAPI GetTaskmanWindow(void)
476 {
477     HWND ret = 0;
478
479     SERVER_START_REQ(set_global_windows)
480     {
481         req->flags = 0;
482         if (!wine_server_call_err(req)) ret = reply->old_taskman_window;
483     }
484     SERVER_END_REQ;
485     return ret;
486 }