Transfered the window struct memory release from WIN_DestroyWindow to
[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 "win.h"
11 #include "winpos.h"
12 #include "hook.h"
13 #include "message.h"
14 #include "task.h"
15 #include "debug.h"
16
17
18 /*****************************************************************
19  *               FOCUS_SwitchFocus 
20  * pMsgQ is the queue whose perQData focus is to be modified
21  */
22 void FOCUS_SwitchFocus( MESSAGEQUEUE *pMsgQ, HWND hFocusFrom, HWND hFocusTo )
23 {
24     WND *pFocusTo = WIN_FindWndPtr( hFocusTo );
25
26     PERQDATA_SetFocusWnd( pMsgQ->pQData, hFocusTo );
27     
28 #if 0
29     if (hFocusFrom) SendMessageA( hFocusFrom, WM_KILLFOCUS, hFocusTo, 0 );
30 #else
31     /* FIXME: must be SendMessage16() because 32A doesn't do
32      * intertask at this time */
33     if (hFocusFrom) SendMessage16( hFocusFrom, WM_KILLFOCUS, hFocusTo, 0 );
34 #endif
35
36     if( !pFocusTo || hFocusTo != PERQDATA_GetFocusWnd( pMsgQ->pQData ) )
37     {
38         WIN_ReleaseWndPtr(pFocusTo);
39         return;
40     }
41
42     /* According to API docs, the WM_SETFOCUS message is sent AFTER the window
43        has received the keyboard focus. */
44
45     pFocusTo->pDriver->pSetFocus(pFocusTo);
46
47     WIN_ReleaseWndPtr(pFocusTo);
48 #if 0
49     SendMessageA( hFocusTo, WM_SETFOCUS, hFocusFrom, 0 );
50 #else
51     SendMessage16( hFocusTo, WM_SETFOCUS, hFocusFrom, 0 );
52 #endif
53 }
54
55
56 /*****************************************************************
57  *               SetFocus16   (USER.22)
58  */
59 HWND16 WINAPI SetFocus16( HWND16 hwnd )
60 {
61     return (HWND16)SetFocus( hwnd );
62 }
63
64
65 /*****************************************************************
66  *               SetFocus32   (USER32.481)
67  */
68 HWND WINAPI SetFocus( HWND hwnd )
69 {
70     HWND hWndFocus = 0, hwndTop = hwnd;
71     WND *wndPtr = WIN_FindWndPtr( hwnd );
72     MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
73     BOOL16 bRet = 0;
74
75     /* Get the messageQ for the current thread */
76     if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
77     {
78         WARN( win, "\tCurrent message queue not found. Exiting!\n" );
79         goto CLEANUP;
80     }
81
82     if (wndPtr)
83     {
84           /* Check if we can set the focus to this window */
85
86         while ( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD  )
87         {
88             if ( wndPtr->dwStyle & ( WS_MINIMIZE | WS_DISABLED) )
89                  goto CLEANUP;
90             WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
91             if (!wndPtr) goto CLEANUP;
92             hwndTop = wndPtr->hwndSelf;
93         }
94
95         /* Retrieve the message queue associated with this window */
96         pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
97         if ( !pMsgQ )
98         {
99             WARN( win, "\tMessage queue not found. Exiting!\n" );
100             goto CLEANUP;
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_CallHooks16( WH_CBT, HCBT_SETFOCUS, (WPARAM16)hwnd,
123                               (LPARAM)hWndFocus) )
124             goto CLEANUP;
125
126         /* activate hwndTop if needed. */
127         if (hwndTop != GetActiveWindow())
128         {
129             if (!WINPOS_SetActiveWindow(hwndTop, 0, 0)) goto CLEANUP;
130
131             if (!IsWindow( hwnd )) goto CLEANUP;  /* Abort if window destroyed */
132         }
133
134         /* Get the current focus window from the perQ data */
135         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
136         
137         /* Change focus and send messages */
138         FOCUS_SwitchFocus( pMsgQ, hWndFocus, hwnd );
139     }
140     else /* NULL hwnd passed in */
141     {
142         if( HOOK_CallHooks16( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hWndFocus ) )
143             goto CLEANUP;
144
145         /* Get the current focus from the perQ data of the current message Q */
146         hWndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
147
148       /* Change focus and send messages */
149         FOCUS_SwitchFocus( pCurMsgQ, hWndFocus, hwnd );
150     }
151
152     bRet = 1;      // Success
153     
154 CLEANUP:
155
156     /* Unlock the queues before returning */
157     if ( pMsgQ )
158         QUEUE_Unlock( pMsgQ );
159     if ( pCurMsgQ )
160         QUEUE_Unlock( pCurMsgQ );
161
162     WIN_ReleaseWndPtr(wndPtr);
163     return bRet ? hWndFocus : 0;
164 }
165
166
167 /*****************************************************************
168  *               GetFocus16   (USER.23)
169  */
170 HWND16 WINAPI GetFocus16(void)
171 {
172     return (HWND16)GetFocus();
173 }
174
175
176 /*****************************************************************
177  *               GetFocus32   (USER32.240)
178  */
179 HWND WINAPI GetFocus(void)
180 {
181     MESSAGEQUEUE *pCurMsgQ = 0;
182     HWND hwndFocus = 0;
183
184     /* Get the messageQ for the current thread */
185     if (!(pCurMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() )))
186     {
187         WARN( win, "\tCurrent message queue not found. Exiting!\n" );
188         return 0;
189     }
190
191     /* Get the current focus from the perQ data of the current message Q */
192     hwndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
193
194     QUEUE_Unlock( pCurMsgQ );
195
196     return hwndFocus;
197 }