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