Trace undocumented toolbar messages.
[wine] / windows / focus.c
1 /*
2  * Focus functions
3  *
4  * Copyright 1993 David Metcalfe
5  *           1994 Alexandre Julliard
6  *           1995 Alex Korobka
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 "windef.h"
24 #include "wingdi.h"
25 #include "wine/winuser16.h"
26 #include "win.h"
27 #include "winpos.h"
28 #include "hook.h"
29 #include "message.h"
30 #include "queue.h"
31 #include "user.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(win);
35
36
37 /*****************************************************************
38  *               FOCUS_SwitchFocus 
39  * pMsgQ is the queue whose perQData focus is to be modified
40  */
41 void FOCUS_SwitchFocus( MESSAGEQUEUE *pMsgQ, HWND hFocusFrom, HWND hFocusTo )
42 {
43     PERQDATA_SetFocusWnd( pMsgQ->pQData, hFocusTo );
44
45     if (hFocusFrom) SendMessageA( hFocusFrom, WM_KILLFOCUS, (WPARAM)hFocusTo, 0 );
46
47     if( !hFocusTo || hFocusTo != PERQDATA_GetFocusWnd( pMsgQ->pQData ) )
48     {
49         return;
50     }
51
52     /* According to API docs, the WM_SETFOCUS message is sent AFTER the window
53        has received the keyboard focus. */
54     if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hFocusTo);
55
56     SendMessageA( hFocusTo, WM_SETFOCUS, (WPARAM)hFocusFrom, 0 );
57 }
58
59
60 /*****************************************************************
61  *              SetFocus (USER32.@)
62  */
63 HWND WINAPI SetFocus( HWND hwnd )
64 {
65     HWND hWndFocus = 0, hwndTop = hwnd;
66     MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
67     BOOL bRet = 0;
68
69     /* Get the messageQ for the current thread */
70     if (!(pCurMsgQ = QUEUE_Current()))
71     {
72         WARN("\tCurrent message queue not found. Exiting!\n" );
73         return 0;
74     }
75
76     if (hwnd)
77     {
78         /* Check if we can set the focus to this window */
79         WND *wndPtr;
80
81         hwnd = WIN_GetFullHandle( hwnd );
82         for (;;)
83         {
84             HWND parent;
85             LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
86             if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
87             parent = GetAncestor( hwndTop, GA_PARENT );
88             if (!parent || parent == GetDesktopWindow()) break;
89             hwndTop = parent;
90         }
91
92         if (!(wndPtr = WIN_FindWndPtr( hwndTop ))) return 0;
93
94         /* Retrieve the message queue associated with this window */
95         pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
96         WIN_ReleaseWndPtr( wndPtr );
97         if ( !pMsgQ )
98         {
99             WARN("\tMessage queue not found. Exiting!\n" );
100             return 0;
101         }
102
103         /* Make sure that message queue for the window we are setting focus to
104          * shares the same perQ data as the current threads message queue.
105          * In other words you can't set focus to a window owned by a different
106          * thread unless AttachThreadInput has been called previously.
107          * (see AttachThreadInput and SetFocus docs)
108          */
109         if ( pCurMsgQ->pQData != pMsgQ->pQData )
110             goto CLEANUP;
111
112         /* Get the current focus window from the perQ data */
113         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
114         
115         if( hwnd == hWndFocus )
116         {
117             bRet = 1;      /* Success */
118             goto CLEANUP;  /* Nothing to do */
119         }
120         
121         /* call hooks */
122         if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)hWndFocus) )
123             goto CLEANUP;
124
125         /* activate hwndTop if needed. */
126         if (hwndTop != GetActiveWindow())
127         {
128             if (!WINPOS_SetActiveWindow(hwndTop, 0, 0)) goto CLEANUP;
129
130             if (!IsWindow( hwnd )) goto CLEANUP;  /* Abort if window destroyed */
131         }
132
133         /* Get the current focus window from the perQ data */
134         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
135         
136         /* Change focus and send messages */
137         FOCUS_SwitchFocus( pMsgQ, hWndFocus, hwnd );
138     }
139     else /* NULL hwnd passed in */
140     {
141         if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hWndFocus ) )
142             return 0;
143
144         /* Get the current focus from the perQ data of the current message Q */
145         hWndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
146
147       /* Change focus and send messages */
148         FOCUS_SwitchFocus( pCurMsgQ, hWndFocus, hwnd );
149     }
150
151     bRet = 1;      /* Success */
152     
153 CLEANUP:
154
155     /* Unlock the queues before returning */
156     if ( pMsgQ )
157         QUEUE_Unlock( pMsgQ );
158
159     return bRet ? hWndFocus : 0;
160 }
161
162
163 /*****************************************************************
164  *              GetFocus (USER32.@)
165  */
166 HWND WINAPI GetFocus(void)
167 {
168     MESSAGEQUEUE *pCurMsgQ = 0;
169
170     /* Get the messageQ for the current thread */
171     if (!(pCurMsgQ = QUEUE_Current()))
172     {
173         WARN("\tCurrent message queue not found. Exiting!\n" );
174         return 0;
175     }
176
177     /* Get the current focus from the perQ data of the current message Q */
178     return PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
179 }