6f0eae730577fb0f68cf990690c0a3174d371a71
[reactos.git] / reactos / subsys / win32k / ntuser / focus.c
1 /*
2 * ReactOS Win32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * $Id$
20 */
21
22 #include <w32k.h>
23
24 #define NDEBUG
25 #include <debug.h>
26
27 HWND FASTCALL
28 IntGetCaptureWindow()
29 {
30 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
31 return ForegroundQueue != NULL ? ForegroundQueue->CaptureWindow : 0;
32 }
33
34 HWND FASTCALL
35 IntGetFocusWindow()
36 {
37 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
38 return ForegroundQueue != NULL ? ForegroundQueue->FocusWindow : 0;
39 }
40
41 HWND FASTCALL
42 IntGetThreadFocusWindow()
43 {
44 PUSER_MESSAGE_QUEUE ThreadQueue;
45 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
46 return ThreadQueue != NULL ? ThreadQueue->FocusWindow : 0;
47 }
48
49 VOID FASTCALL
50 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
51 {
52 if (hWndPrev)
53 {
54 co_IntPostOrSendMessage(hWndPrev, WM_NCACTIVATE, FALSE, 0);
55 co_IntPostOrSendMessage(hWndPrev, WM_ACTIVATE,
56 MAKEWPARAM(WA_INACTIVE, UserGetWindowLong(hWndPrev, GWL_STYLE, FALSE) & WS_MINIMIZE),
57 (LPARAM)hWnd);
58 }
59 }
60
61 VOID FASTCALL
62 co_IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
63 {
64 USER_REFERENCE_ENTRY Ref;
65 PWINDOW_OBJECT Window;
66
67 if ((Window = UserGetWindowObject(hWnd)))
68 {
69
70 UserRefObjectCo(Window, &Ref);
71
72 /* Send palette messages */
73 if (co_IntPostOrSendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0))
74 {
75 co_IntPostOrSendMessage(HWND_BROADCAST, WM_PALETTEISCHANGING,
76 (WPARAM)hWnd, 0);
77 }
78
79 if (UserGetWindow(hWnd, GW_HWNDPREV) != NULL)
80 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0,
81 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
82
83 if (!IntGetOwner(Window) && !IntGetParent(Window))
84 {
85 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd);
86 }
87
88 UserDerefObjectCo(Window);
89
90 /* FIXME: IntIsWindow */
91
92 co_IntPostOrSendMessage(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == UserGetForegroundWindow()), 0);
93 /* FIXME: WA_CLICKACTIVE */
94 co_IntPostOrSendMessage(hWnd, WM_ACTIVATE,
95 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE,
96 UserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_MINIMIZE),
97 (LPARAM)hWndPrev);
98 }
99 }
100
101 VOID FASTCALL
102 co_IntSendKillFocusMessages(HWND hWndPrev, HWND hWnd)
103 {
104 if (hWndPrev)
105 {
106 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
107 }
108 }
109
110 VOID FASTCALL
111 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
112 {
113 if (hWnd)
114 {
115 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
116 }
117 }
118
119 HWND FASTCALL
120 IntFindChildWindowToOwner(PWINDOW_OBJECT Root, PWINDOW_OBJECT Owner)
121 {
122 HWND Ret;
123 PWINDOW_OBJECT Child, OwnerWnd;
124
125 for(Child = Root->FirstChild; Child; Child = Child->NextSibling)
126 {
127 OwnerWnd = UserGetWindowObject(Child->hOwner);
128 if(!OwnerWnd)
129 continue;
130
131 if(OwnerWnd == Owner)
132 {
133 Ret = Child->hSelf;
134 return Ret;
135 }
136 }
137
138 return NULL;
139 }
140
141 STATIC BOOL FASTCALL
142 co_IntSetForegroundAndFocusWindow(PWINDOW_OBJECT Window, PWINDOW_OBJECT FocusWindow, BOOL MouseActivate)
143 {
144 HWND hWnd = Window->hSelf;
145 HWND hWndPrev = NULL;
146 HWND hWndFocus = FocusWindow->hSelf;
147 HWND hWndFocusPrev = NULL;
148 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
149
150 ASSERT_REFS_CO(Window);
151
152 DPRINT("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, hWndFocus, MouseActivate ? "TRUE" : "FALSE");
153 DPRINT("(%wZ)\n", &Window->WindowName);
154
155 if ((Window->Style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
156 {
157 DPRINT("Failed - Child\n");
158 return FALSE;
159 }
160
161 if (0 == (Window->Style & WS_VISIBLE))
162 {
163 DPRINT("Failed - Invisible\n");
164 return FALSE;
165 }
166
167 PrevForegroundQueue = IntGetFocusMessageQueue();
168 if (PrevForegroundQueue != 0)
169 {
170 hWndPrev = PrevForegroundQueue->ActiveWindow;
171 }
172
173 if (hWndPrev == hWnd)
174 {
175 DPRINT("Failed - Same\n");
176 return TRUE;
177 }
178
179 hWndFocusPrev = (PrevForegroundQueue == FocusWindow->MessageQueue
180 ? FocusWindow->MessageQueue->FocusWindow : NULL);
181
182 /* FIXME: Call hooks. */
183
184 co_IntSendDeactivateMessages(hWndPrev, hWnd);
185 co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
186
187 IntSetFocusMessageQueue(Window->MessageQueue);
188 if (Window->MessageQueue)
189 {
190 Window->MessageQueue->ActiveWindow = hWnd;
191 }
192
193 if (FocusWindow->MessageQueue)
194 {
195 FocusWindow->MessageQueue->FocusWindow = hWndFocus;
196 }
197
198 if (PrevForegroundQueue != Window->MessageQueue)
199 {
200 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
201 }
202
203 co_IntSendSetFocusMessages(hWndFocusPrev, hWndFocus);
204 co_IntSendActivateMessages(hWndPrev, hWnd, MouseActivate);
205
206 return TRUE;
207 }
208
209 BOOL FASTCALL
210 co_IntSetForegroundWindow(PWINDOW_OBJECT Window)//FIXME: can Window be NULL??
211 {
212 /*if (Window)*/ ASSERT_REFS_CO(Window);
213
214 return co_IntSetForegroundAndFocusWindow(Window, Window, FALSE);
215 }
216
217 BOOL FASTCALL
218 co_IntMouseActivateWindow(PWINDOW_OBJECT Window)
219 {
220 HWND Top;
221 PWINDOW_OBJECT TopWindow;
222 USER_REFERENCE_ENTRY Ref;
223
224 ASSERT_REFS_CO(Window);
225
226 if(Window->Style & WS_DISABLED)
227 {
228 BOOL Ret;
229 PWINDOW_OBJECT TopWnd;
230 PWINDOW_OBJECT DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
231 if(DesktopWindow)
232 {
233 Top = IntFindChildWindowToOwner(DesktopWindow, Window);
234 if((TopWnd = UserGetWindowObject(Top)))
235 {
236 UserRefObjectCo(TopWnd, &Ref);
237 Ret = co_IntMouseActivateWindow(TopWnd);
238 UserDerefObjectCo(TopWnd);
239
240 return Ret;
241 }
242 }
243 return FALSE;
244 }
245
246
247 TopWindow = UserGetAncestor(Window, GA_ROOT);
248 if (!TopWindow) return FALSE;
249
250 /* TMN: Check return valud from this function? */
251 UserRefObjectCo(TopWindow, &Ref);
252
253 co_IntSetForegroundAndFocusWindow(TopWindow, Window, TRUE);
254
255 UserDerefObjectCo(TopWindow);
256
257 return TRUE;
258 }
259
260 HWND FASTCALL
261 co_IntSetActiveWindow(PWINDOW_OBJECT Window OPTIONAL)
262 {
263 PUSER_MESSAGE_QUEUE ThreadQueue;
264 HWND hWndPrev;
265 HWND hWnd = 0;
266
267 if (Window)
268 ASSERT_REFS_CO(Window);
269
270 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
271 ASSERT(ThreadQueue != 0);
272
273 if (Window != 0)
274 {
275 if (!(Window->Style & WS_VISIBLE) ||
276 (Window->Style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
277 {
278 return ThreadQueue ? 0 : ThreadQueue->ActiveWindow;
279 }
280 hWnd = Window->hSelf;
281 }
282
283 hWndPrev = ThreadQueue->ActiveWindow;
284 if (hWndPrev == hWnd)
285 {
286 return hWndPrev;
287 }
288
289 /* FIXME: Call hooks. */
290
291 ThreadQueue->ActiveWindow = hWnd;
292
293 co_IntSendDeactivateMessages(hWndPrev, hWnd);
294 co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
295
296 /* FIXME */
297 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
298 return hWndPrev;
299 }
300
301 static
302 HWND FASTCALL
303 co_IntSetFocusWindow(PWINDOW_OBJECT Window)
304 {
305 HWND hWndPrev = 0;
306 PUSER_MESSAGE_QUEUE ThreadQueue;
307
308 ASSERT_REFS_CO(Window);
309
310 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
311 ASSERT(ThreadQueue != 0);
312
313 hWndPrev = ThreadQueue->FocusWindow;
314 if (hWndPrev == Window->hSelf)
315 {
316 return hWndPrev;
317 }
318
319 ThreadQueue->FocusWindow = Window->hSelf;
320
321 co_IntSendKillFocusMessages(hWndPrev, Window->hSelf);
322 co_IntSendSetFocusMessages(hWndPrev, Window->hSelf);
323
324 return hWndPrev;
325 }
326
327
328 /*
329 * @implemented
330 */
331 HWND FASTCALL
332 UserGetForegroundWindow(VOID)
333 {
334 PUSER_MESSAGE_QUEUE ForegroundQueue;
335
336 ForegroundQueue = IntGetFocusMessageQueue();
337 return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
338 }
339
340
341 /*
342 * @implemented
343 */
344 HWND STDCALL
345 NtUserGetForegroundWindow(VOID)
346 {
347 DECLARE_RETURN(HWND);
348
349 DPRINT("Enter NtUserGetForegroundWindow\n");
350 UserEnterExclusive();
351
352 RETURN( UserGetForegroundWindow());
353
354 CLEANUP:
355 DPRINT("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
356 UserLeave();
357 END_CLEANUP;
358 }
359
360
361 HWND FASTCALL UserGetActiveWindow()
362 {
363 PUSER_MESSAGE_QUEUE ThreadQueue;
364 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
365 return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
366 }
367
368
369 /*
370 * @implemented
371 */
372 HWND STDCALL
373 NtUserGetActiveWindow(VOID)
374 {
375 DECLARE_RETURN(HWND);
376
377 DPRINT("Enter NtUserGetActiveWindow\n");
378 UserEnterShared();
379
380 RETURN( UserGetActiveWindow());
381
382 CLEANUP:
383 DPRINT("Leave NtUserGetActiveWindow, ret=%i\n",_ret_);
384 UserLeave();
385 END_CLEANUP;
386 }
387
388 HWND STDCALL
389 NtUserSetActiveWindow(HWND hWnd)
390 {
391 USER_REFERENCE_ENTRY Ref;
392 DECLARE_RETURN(HWND);
393
394 DPRINT("Enter NtUserSetActiveWindow(%x)\n", hWnd);
395 UserEnterExclusive();
396
397 if (hWnd)
398 {
399 PWINDOW_OBJECT Window;
400 PUSER_MESSAGE_QUEUE ThreadQueue;
401 HWND hWndPrev;
402
403 if (!(Window = UserGetWindowObject(hWnd)))
404 {
405 RETURN( 0);
406 }
407
408 DPRINT("(%wZ)\n", &Window->WindowName);
409
410 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
411
412 if (Window->MessageQueue != ThreadQueue)
413 {
414 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
415 RETURN( 0);
416 }
417
418 UserRefObjectCo(Window, &Ref);
419 hWndPrev = co_IntSetActiveWindow(Window);
420 UserDerefObjectCo(Window);
421
422 RETURN( hWndPrev);
423 }
424 else
425 {
426 RETURN( co_IntSetActiveWindow(0));
427 }
428
429 CLEANUP:
430 DPRINT("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
431 UserLeave();
432 END_CLEANUP;
433 }
434
435 /*
436 * @implemented
437 */
438 HWND STDCALL
439 NtUserGetCapture(VOID)
440 {
441 DECLARE_RETURN(HWND);
442
443 DPRINT("Enter NtUserGetCapture\n");
444 UserEnterShared();
445
446 PUSER_MESSAGE_QUEUE ThreadQueue;
447 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
448 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
449
450 CLEANUP:
451 DPRINT("Leave NtUserGetCapture, ret=%i\n",_ret_);
452 UserLeave();
453 END_CLEANUP;
454 }
455
456 /*
457 * @implemented
458 */
459 HWND STDCALL
460 NtUserSetCapture(HWND hWnd)
461 {
462 PUSER_MESSAGE_QUEUE ThreadQueue;
463 PWINDOW_OBJECT Window;
464 HWND hWndPrev;
465 DECLARE_RETURN(HWND);
466
467 DPRINT("Enter NtUserSetCapture(%x)\n", hWnd);
468 UserEnterExclusive();
469
470 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
471
472 if((Window = UserGetWindowObject(hWnd)))
473 {
474 if(Window->MessageQueue != ThreadQueue)
475 {
476 RETURN(NULL);
477 }
478 }
479
480 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
481
482 /* also remove other windows if not capturing anymore */
483 if(hWnd == NULL)
484 {
485 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
486 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
487 }
488
489 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
490 ThreadQueue->CaptureWindow = hWnd;
491
492 RETURN( hWndPrev);
493
494 CLEANUP:
495 DPRINT("Leave NtUserSetCapture, ret=%i\n",_ret_);
496 UserLeave();
497 END_CLEANUP;
498 }
499
500
501
502 HWND FASTCALL co_UserSetFocus(PWINDOW_OBJECT Window OPTIONAL)
503 {
504 if (Window)
505 {
506 PUSER_MESSAGE_QUEUE ThreadQueue;
507 HWND hWndPrev;
508 PWINDOW_OBJECT TopWnd;
509 USER_REFERENCE_ENTRY Ref;
510
511 ASSERT_REFS_CO(Window);
512
513 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
514
515 if (Window->Style & (WS_MINIMIZE | WS_DISABLED))
516 {
517 return( (ThreadQueue ? ThreadQueue->FocusWindow : 0));
518 }
519
520 if (Window->MessageQueue != ThreadQueue)
521 {
522 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
523 return( 0);
524 }
525
526 TopWnd = UserGetAncestor(Window, GA_ROOT);
527 if (TopWnd && TopWnd->hSelf != UserGetActiveWindow())
528 {
529 // PWINDOW_OBJECT WndTops = UserGetWindowObject(hWndTop);
530 UserRefObjectCo(TopWnd, &Ref);
531 co_IntSetActiveWindow(TopWnd);
532 UserDerefObjectCo(TopWnd);
533 }
534
535 hWndPrev = co_IntSetFocusWindow(Window);
536
537 return( hWndPrev);
538 }
539 else
540 {
541 return( co_IntSetFocusWindow(NULL));
542 }
543
544 }
545
546
547 /*
548 * @implemented
549 */
550 HWND STDCALL
551 NtUserSetFocus(HWND hWnd)
552 {
553 PWINDOW_OBJECT Window;
554 USER_REFERENCE_ENTRY Ref;
555 DECLARE_RETURN(HWND);
556 HWND ret;
557
558 DPRINT("Enter NtUserSetFocus(%x)\n", hWnd);
559 UserEnterExclusive();
560
561 if (!(Window = UserGetWindowObject(hWnd)))
562 {
563 RETURN(NULL);
564 }
565
566 UserRefObjectCo(Window, &Ref);
567 ret = co_UserSetFocus(Window);
568 UserDerefObjectCo(Window);
569
570 RETURN(ret);
571
572 CLEANUP:
573 DPRINT("Leave NtUserSetFocus, ret=%i\n",_ret_);
574 UserLeave();
575 END_CLEANUP;
576 }
577
578 /* EOF */