Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[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 "debug.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( win, "\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         /* Retrieve the message queue associated with this window */
99         pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
100         if ( !pMsgQ )
101         {
102             WARN( win, "\tMessage queue not found. Exiting!\n" );
103             goto CLEANUP;
104         }
105
106         /* Make sure that message queue for the window we are setting focus to
107          * shares the same perQ data as the current threads message queue.
108          * In other words you can't set focus to a window owned by a different
109          * thread unless AttachThreadInput has been called previously.
110          * (see AttachThreadInput and SetFocus docs)
111          */
112         if ( pCurMsgQ->pQData != pMsgQ->pQData )
113             goto CLEANUP;
114
115         /* Get the current focus window from the perQ data */
116         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
117         
118         if( hwnd == hWndFocus )
119         {
120             bRet = 1;      /* Success */
121             goto CLEANUP;  /* Nothing to do */
122         }
123         
124         /* call hooks */
125         if( HOOK_CallHooks16( WH_CBT, HCBT_SETFOCUS, (WPARAM16)hwnd,
126                               (LPARAM)hWndFocus) )
127             goto CLEANUP;
128
129         /* activate hwndTop if needed. */
130         if (hwndTop != GetActiveWindow())
131         {
132             if (!WINPOS_SetActiveWindow(hwndTop, 0, 0)) goto CLEANUP;
133
134             if (!IsWindow( hwnd )) goto CLEANUP;  /* Abort if window destroyed */
135         }
136
137         /* Get the current focus window from the perQ data */
138         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
139         
140         /* Change focus and send messages */
141         FOCUS_SwitchFocus( pMsgQ, hWndFocus, hwnd );
142     }
143     else /* NULL hwnd passed in */
144     {
145         if( HOOK_CallHooks16( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hWndFocus ) )
146             goto CLEANUP;
147
148         /* Get the current focus from the perQ data of the current message Q */
149         hWndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
150
151       /* Change focus and send messages */
152         FOCUS_SwitchFocus( pCurMsgQ, hWndFocus, hwnd );
153     }
154
155     bRet = 1;      /* Success */
156     
157 CLEANUP:
158
159     /* Unlock the queues before returning */
160     if ( pMsgQ )
161         QUEUE_Unlock( pMsgQ );
162     if ( pCurMsgQ )
163         QUEUE_Unlock( pCurMsgQ );
164
165     WIN_ReleaseWndPtr(wndPtr);
166     return bRet ? hWndFocus : 0;
167 }
168
169
170 /*****************************************************************
171  *               GetFocus16   (USER.23)
172  */
173 HWND16 WINAPI GetFocus16(void)
174 {
175     return (HWND16)GetFocus();
176 }
177
178
179 /*****************************************************************
180  *               GetFocus32   (USER32.240)
181  */
182 HWND WINAPI GetFocus(void)
183 {
184     MESSAGEQUEUE *pCurMsgQ = 0;
185     HWND hwndFocus = 0;
186
187     /* Get the messageQ for the current thread */
188     if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
189     {
190         WARN( win, "\tCurrent message queue not found. Exiting!\n" );
191         return 0;
192     }
193
194     /* Get the current focus from the perQ data of the current message Q */
195     hwndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
196
197     QUEUE_Unlock( pCurMsgQ );
198
199     return hwndFocus;
200 }