Writes to stdout and VGA_WriteChars routine now update both VGA
[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)
46         SendNotifyMessageA( hFocusFrom, WM_KILLFOCUS, (WPARAM)hFocusTo, 0 );
47
48     if( !hFocusTo || hFocusTo != PERQDATA_GetFocusWnd( pMsgQ->pQData ) )
49     {
50         return;
51     }
52
53     /* According to API docs, the WM_SETFOCUS message is sent AFTER the window
54        has received the keyboard focus. */
55     if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hFocusTo);
56
57     SendMessageA( hFocusTo, WM_SETFOCUS, (WPARAM)hFocusFrom, 0 );
58 }
59
60
61 /*****************************************************************
62  *              SetFocus (USER32.@)
63  */
64 HWND WINAPI SetFocus( HWND hwnd )
65 {
66     HWND hWndFocus = 0, hwndTop = hwnd;
67     MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
68     BOOL bRet = 0;
69
70     /* Get the messageQ for the current thread */
71     if (!(pCurMsgQ = QUEUE_Current()))
72     {
73         WARN("\tCurrent message queue not found. Exiting!\n" );
74         return 0;
75     }
76
77     if (hwnd)
78     {
79         /* Check if we can set the focus to this window */
80         WND *wndPtr;
81
82         hwnd = WIN_GetFullHandle( hwnd );
83         for (;;)
84         {
85             HWND parent;
86             LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
87             if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
88             parent = GetAncestor( hwndTop, GA_PARENT );
89             if (!parent || parent == GetDesktopWindow()) break;
90             hwndTop = parent;
91         }
92
93         if (!(wndPtr = WIN_FindWndPtr( hwndTop ))) return 0;
94
95         /* Retrieve the message queue associated with this window */
96         pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
97         WIN_ReleaseWndPtr( wndPtr );
98         if ( !pMsgQ )
99         {
100             WARN("\tMessage queue not found. Exiting!\n" );
101             return 0;
102         }
103
104         /* Make sure that message queue for the window we are setting focus to
105          * shares the same perQ data as the current threads message queue.
106          * In other words you can't set focus to a window owned by a different
107          * thread unless AttachThreadInput has been called previously.
108          * (see AttachThreadInput and SetFocus docs)
109          */
110         if ( pCurMsgQ->pQData != pMsgQ->pQData )
111             goto CLEANUP;
112
113         /* Get the current focus window from the perQ data */
114         hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
115         
116         if( hwnd == hWndFocus )
117         {
118             bRet = 1;      /* Success */
119             goto CLEANUP;  /* Nothing to do */
120         }
121         
122         /* call hooks */
123         if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (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_CallHooksA( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hWndFocus ) )
143             return 0;
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
160     return bRet ? hWndFocus : 0;
161 }
162
163
164 /*****************************************************************
165  *              GetFocus (USER32.@)
166  */
167 HWND WINAPI GetFocus(void)
168 {
169     MESSAGEQUEUE *pCurMsgQ = 0;
170
171     /* Get the messageQ for the current thread */
172     if (!(pCurMsgQ = QUEUE_Current()))
173     {
174         WARN("\tCurrent message queue not found. Exiting!\n" );
175         return 0;
176     }
177
178     /* Get the current focus from the perQ data of the current message Q */
179     return PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
180 }