Cosmetics.
[wine] / windows / focus.c
1 /*
2  * Focus functions
3  *
4  * Copyright 1993 David Metcalfe
5  *           1994 Alexandre Julliard
6  *           1995 Alex Korobka
7  *
8  */
9
10 #include "wine/winuser16.h"
11 #include "win.h"
12 #include "winpos.h"
13 #include "hook.h"
14 #include "message.h"
15 #include "task.h"
16 #include "debugtools.h"
17
18 DEFAULT_DEBUG_CHANNEL(win)
19
20
21 /*****************************************************************
22  *               FOCUS_SwitchFocus 
23  * pMsgQ is the queue whose perQData focus is to be modified
24  */
25 void FOCUS_SwitchFocus( MESSAGEQUEUE *pMsgQ, HWND hFocusFrom, HWND hFocusTo )
26 {
27     WND *pFocusTo = WIN_FindWndPtr( hFocusTo );
28
29     PERQDATA_SetFocusWnd( pMsgQ->pQData, hFocusTo );
30     
31 #if 0
32     if (hFocusFrom) SendMessageA( hFocusFrom, WM_KILLFOCUS, hFocusTo, 0 );
33 #else
34     /* FIXME: must be SendMessage16() because 32A doesn't do
35      * intertask at this time */
36     if (hFocusFrom) SendMessage16( hFocusFrom, WM_KILLFOCUS, hFocusTo, 0 );
37 #endif
38
39     if( !pFocusTo || hFocusTo != PERQDATA_GetFocusWnd( pMsgQ->pQData ) )
40     {
41         WIN_ReleaseWndPtr(pFocusTo);
42         return;
43     }
44
45     /* According to API docs, the WM_SETFOCUS message is sent AFTER the window
46        has received the keyboard focus. */
47
48     pFocusTo->pDriver->pSetFocus(pFocusTo);
49
50     WIN_ReleaseWndPtr(pFocusTo);
51 #if 0
52     SendMessageA( hFocusTo, WM_SETFOCUS, hFocusFrom, 0 );
53 #else
54     SendMessage16( hFocusTo, WM_SETFOCUS, hFocusFrom, 0 );
55 #endif
56 }
57
58
59 /*****************************************************************
60  *               SetFocus16   (USER.22)
61  */
62 HWND16 WINAPI SetFocus16( HWND16 hwnd )
63 {
64     return (HWND16)SetFocus( hwnd );
65 }
66
67
68 /*****************************************************************
69  *               SetFocus32   (USER32.481)
70  */
71 HWND WINAPI SetFocus( HWND hwnd )
72 {
73     HWND hWndFocus = 0, hwndTop = hwnd;
74     WND *wndPtr = WIN_FindWndPtr( hwnd );
75     MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
76     BOOL16 bRet = 0;
77
78     /* Get the messageQ for the current thread */
79     if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
80     {
81         WARN("\tCurrent message queue not found. Exiting!\n" );
82         goto CLEANUP;
83     }
84
85     if (wndPtr)
86     {
87           /* Check if we can set the focus to this window */
88
89         while ( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD  )
90         {
91             if ( wndPtr->dwStyle & ( WS_MINIMIZE | WS_DISABLED) )
92                  goto CLEANUP;
93             WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
94             if (!wndPtr) goto CLEANUP;
95             hwndTop = wndPtr->hwndSelf;
96         }
97
98         /* definitely at the top window now */
99         if ( wndPtr->dwStyle & ( WS_MINIMIZE | WS_DISABLED) ) goto CLEANUP;
100
101         /* Retrieve the message queue associated with this window */
102         pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
103         if ( !pMsgQ )
104         {
105             WARN("\tMessage queue not found. Exiting!\n" );
106             goto CLEANUP;
107         }
108
109         /* Make sure that message queue for the window we are setting focus to
110          * shares the same perQ data as the current threads message queue.
111          * In other words you can't set focus to a window owned by a different
112          * thread unless AttachThreadInput has been called previously.
113          * (see AttachThreadInput and SetFocus docs)
114          */
115         if ( pCurMsgQ->pQData != pMsgQ->pQData )
116             goto CLEANUP;
117
118         /* Get the current focus window from the perQ data */
119         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
120         
121         if( hwnd == hWndFocus )
122         {
123             bRet = 1;      /* Success */
124             goto CLEANUP;  /* Nothing to do */
125         }
126         
127         /* call hooks */
128         if( HOOK_CallHooks16( WH_CBT, HCBT_SETFOCUS, (WPARAM16)hwnd,
129                               (LPARAM)hWndFocus) )
130             goto CLEANUP;
131
132         /* activate hwndTop if needed. */
133         if (hwndTop != GetActiveWindow())
134         {
135             if (!WINPOS_SetActiveWindow(hwndTop, 0, 0)) goto CLEANUP;
136
137             if (!IsWindow( hwnd )) goto CLEANUP;  /* Abort if window destroyed */
138         }
139
140         /* Get the current focus window from the perQ data */
141         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
142         
143         /* Change focus and send messages */
144         FOCUS_SwitchFocus( pMsgQ, hWndFocus, hwnd );
145     }
146     else /* NULL hwnd passed in */
147     {
148         if( HOOK_CallHooks16( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hWndFocus ) )
149             goto CLEANUP;
150
151         /* Get the current focus from the perQ data of the current message Q */
152         hWndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
153
154       /* Change focus and send messages */
155         FOCUS_SwitchFocus( pCurMsgQ, hWndFocus, hwnd );
156     }
157
158     bRet = 1;      /* Success */
159     
160 CLEANUP:
161
162     /* Unlock the queues before returning */
163     if ( pMsgQ )
164         QUEUE_Unlock( pMsgQ );
165     if ( pCurMsgQ )
166         QUEUE_Unlock( pCurMsgQ );
167
168     WIN_ReleaseWndPtr(wndPtr);
169     return bRet ? hWndFocus : 0;
170 }
171
172
173 /*****************************************************************
174  *               GetFocus16   (USER.23)
175  */
176 HWND16 WINAPI GetFocus16(void)
177 {
178     return (HWND16)GetFocus();
179 }
180
181
182 /*****************************************************************
183  *               GetFocus32   (USER32.240)
184  */
185 HWND WINAPI GetFocus(void)
186 {
187     MESSAGEQUEUE *pCurMsgQ = 0;
188     HWND hwndFocus = 0;
189
190     /* Get the messageQ for the current thread */
191     if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
192     {
193         WARN("\tCurrent message queue not found. Exiting!\n" );
194         return 0;
195     }
196
197     /* Get the current focus from the perQ data of the current message Q */
198     hwndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
199
200     QUEUE_Unlock( pCurMsgQ );
201
202     return hwndFocus;
203 }