[Win32k]
[reactos.git] / reactos / subsystems / win32 / 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21 #include <win32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 HWND FASTCALL
27 IntGetCaptureWindow(VOID)
28 {
29 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
30 return ForegroundQueue != NULL ? ForegroundQueue->CaptureWindow : 0;
31 }
32
33 HWND FASTCALL
34 IntGetFocusWindow(VOID)
35 {
36 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
37 return ForegroundQueue != NULL ? ForegroundQueue->FocusWindow : 0;
38 }
39
40 HWND FASTCALL
41 IntGetThreadFocusWindow(VOID)
42 {
43 PTHREADINFO pti;
44 PUSER_MESSAGE_QUEUE ThreadQueue;
45
46 pti = PsGetCurrentThreadWin32Thread();
47 ThreadQueue = pti->MessageQueue;
48 return ThreadQueue != NULL ? ThreadQueue->FocusWindow : 0;
49 }
50
51 VOID FASTCALL
52 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
53 {
54 PWND WndPrev ;
55
56 if (hWndPrev && (WndPrev = UserGetWindowObject(hWndPrev)))
57 {
58 co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0);
59 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
60 MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
61 (LPARAM)hWnd);
62 }
63 }
64
65 VOID FASTCALL
66 co_IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
67 {
68 USER_REFERENCE_ENTRY Ref, RefPrev;
69 PWND Window, WindowPrev = NULL;
70
71 if ((Window = UserGetWindowObject(hWnd)))
72 {
73 UserRefObjectCo(Window, &Ref);
74
75 WindowPrev = UserGetWindowObject(hWndPrev);
76
77 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
78
79 /* Send palette messages */
80 if (co_IntPostOrSendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0))
81 {
82 UserSendNotifyMessage( HWND_BROADCAST,
83 WM_PALETTEISCHANGING,
84 (WPARAM)hWnd,
85 0);
86 }
87
88 if (Window->spwndPrev != NULL)
89 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0,
90 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
91
92 if (!Window->spwndOwner && !IntGetParent(Window))
93 {
94 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd);
95 }
96
97 if (Window)
98 { // Set last active for window and it's owner.
99 Window->hWndLastActive = hWnd;
100 if (Window->spwndOwner)
101 Window->spwndOwner->hWndLastActive = hWnd;
102 Window->state |= WNDS_ACTIVEFRAME;
103 }
104
105 if (WindowPrev)
106 WindowPrev->state &= ~WNDS_ACTIVEFRAME;
107
108 if (Window && WindowPrev)
109 {
110 PWND cWindow;
111 HWND *List, *phWnd;
112 HANDLE OldTID = IntGetWndThreadId(WindowPrev);
113 HANDLE NewTID = IntGetWndThreadId(Window);
114
115 DPRINT("SendActiveMessage Old -> %x, New -> %x\n", OldTID, NewTID);
116 if (Window->style & WS_MINIMIZE)
117 {
118 DPRINT("Widow was minimized\n");
119 }
120
121 if (OldTID != NewTID)
122 {
123 List = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
124 if (List)
125 {
126 for (phWnd = List; *phWnd; ++phWnd)
127 {
128 cWindow = UserGetWindowObject(*phWnd);
129
130 if (cWindow && (IntGetWndThreadId(cWindow) == OldTID))
131 { // FALSE if the window is being deactivated,
132 // ThreadId that owns the window being activated.
133 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
134 }
135 }
136 for (phWnd = List; *phWnd; ++phWnd)
137 {
138 cWindow = UserGetWindowObject(*phWnd);
139 if (cWindow && (IntGetWndThreadId(cWindow) == NewTID))
140 { // TRUE if the window is being activated,
141 // ThreadId that owns the window being deactivated.
142 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
143 }
144 }
145 ExFreePool(List);
146 }
147 }
148 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
149 }
150
151 UserDerefObjectCo(Window);
152
153 /* FIXME: IntIsWindow */
154 co_IntSendMessageNoWait(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == UserGetForegroundWindow()), 0);
155 /* FIXME: WA_CLICKACTIVE */
156 co_IntSendMessageNoWait(hWnd, WM_ACTIVATE,
157 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE,
158 Window->style & WS_MINIMIZE),
159 (LPARAM)hWndPrev);
160 }
161 }
162
163 VOID FASTCALL
164 co_IntSendKillFocusMessages(HWND hWndPrev, HWND hWnd)
165 {
166 if (hWndPrev)
167 {
168 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
169 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
170 }
171 }
172
173 VOID FASTCALL
174 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
175 {
176 if (hWnd)
177 {
178 PWND pWnd = UserGetWindowObject(hWnd);
179 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
180 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
181 }
182 }
183
184 HWND FASTCALL
185 IntFindChildWindowToOwner(PWND Root, PWND Owner)
186 {
187 HWND Ret;
188 PWND Child, OwnerWnd;
189
190 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
191 {
192 OwnerWnd = Child->spwndOwner;
193 if(!OwnerWnd)
194 continue;
195
196 if(OwnerWnd == Owner)
197 {
198 Ret = Child->head.h;
199 return Ret;
200 }
201 }
202
203 return NULL;
204 }
205
206 static BOOL FASTCALL
207 co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate)
208 {
209 HWND hWnd = Wnd->head.h;
210 HWND hWndPrev = NULL;
211 HWND hWndFocus = FocusWindow->head.h;
212 HWND hWndFocusPrev = NULL;
213 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
214
215 ASSERT_REFS_CO(Wnd);
216
217 DPRINT("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, hWndFocus, MouseActivate ? "TRUE" : "FALSE");
218
219 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
220 {
221 DPRINT("Failed - Child\n");
222 return FALSE;
223 }
224
225 if (0 == (Wnd->style & WS_VISIBLE) &&
226 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess)
227 {
228 DPRINT("Failed - Invisible\n");
229 return FALSE;
230 }
231
232 PrevForegroundQueue = IntGetFocusMessageQueue();
233 if (PrevForegroundQueue != 0)
234 {
235 hWndPrev = PrevForegroundQueue->ActiveWindow;
236 hWndFocusPrev = PrevForegroundQueue->FocusWindow;
237 }
238
239 if (hWndPrev == hWnd)
240 {
241 DPRINT("Failed - Same\n");
242 return TRUE;
243 }
244
245 /* FIXME: Call hooks. */
246
247 co_IntSendDeactivateMessages(hWndPrev, hWnd);
248 co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
249
250
251 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
252
253 if (Wnd->head.pti->MessageQueue)
254 {
255 Wnd->head.pti->MessageQueue->ActiveWindow = hWnd;
256 }
257
258 if (FocusWindow->head.pti->MessageQueue)
259 {
260 FocusWindow->head.pti->MessageQueue->FocusWindow = hWndFocus;
261 }
262
263 if (PrevForegroundQueue != Wnd->head.pti->MessageQueue)
264 {
265 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
266 }
267
268 co_IntSendSetFocusMessages(hWndFocusPrev, hWndFocus);
269 co_IntSendActivateMessages(hWndPrev, hWnd, MouseActivate);
270
271 return TRUE;
272 }
273
274 BOOL FASTCALL
275 co_IntSetForegroundWindow(PWND Window)//FIXME: can Window be NULL??
276 {
277 /*if (Window)*/ ASSERT_REFS_CO(Window);
278
279 return co_IntSetForegroundAndFocusWindow(Window, Window, FALSE);
280 }
281
282 BOOL FASTCALL
283 co_IntMouseActivateWindow(PWND Wnd)
284 {
285 HWND Top;
286 PWND TopWindow;
287 USER_REFERENCE_ENTRY Ref;
288
289 ASSERT_REFS_CO(Wnd);
290
291 if(Wnd->style & WS_DISABLED)
292 {
293 BOOL Ret;
294 PWND TopWnd;
295 PWND DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
296 if(DesktopWindow)
297 {
298 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
299 if((TopWnd = UserGetWindowObject(Top)))
300 {
301 UserRefObjectCo(TopWnd, &Ref);
302 Ret = co_IntMouseActivateWindow(TopWnd);
303 UserDerefObjectCo(TopWnd);
304
305 return Ret;
306 }
307 }
308 return FALSE;
309 }
310
311
312 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
313 if (!TopWindow) return FALSE;
314
315 /* TMN: Check return valud from this function? */
316 UserRefObjectCo(TopWindow, &Ref);
317
318 co_IntSetForegroundAndFocusWindow(TopWindow, Wnd, TRUE);
319
320 UserDerefObjectCo(TopWindow);
321
322 return TRUE;
323 }
324
325 HWND FASTCALL
326 co_IntSetActiveWindow(PWND Wnd OPTIONAL)
327 {
328 PTHREADINFO pti;
329 PUSER_MESSAGE_QUEUE ThreadQueue;
330 HWND hWndPrev;
331 HWND hWnd = 0;
332 CBTACTIVATESTRUCT cbt;
333
334 if (Wnd)
335 ASSERT_REFS_CO(Wnd);
336
337 pti = PsGetCurrentThreadWin32Thread();
338 ThreadQueue = pti->MessageQueue;
339 ASSERT(ThreadQueue != 0);
340
341 if (Wnd != 0)
342 {
343 if ((!(Wnd->style & WS_VISIBLE) &&
344 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) ||
345 (Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
346 {
347 return ThreadQueue ? 0 : ThreadQueue->ActiveWindow;
348 }
349 hWnd = Wnd->head.h;
350 }
351
352 hWndPrev = ThreadQueue->ActiveWindow;
353 if (hWndPrev == hWnd)
354 {
355 return hWndPrev;
356 }
357
358 /* call CBT hook chain */
359 cbt.fMouse = FALSE;
360 cbt.hWndActive = hWndPrev;
361 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
362 {
363 DPRINT1("SetActiveWindow WH_CBT Call Hook return!\n");
364 return 0;
365 }
366 ThreadQueue->ActiveWindow = hWnd;
367
368 co_IntSendDeactivateMessages(hWndPrev, hWnd);
369 co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
370
371 /* FIXME */
372 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
373 return hWndPrev;
374 }
375
376 static
377 HWND FASTCALL
378 co_IntSetFocusWindow(PWND Window OPTIONAL)
379 {
380 HWND hWndPrev = 0;
381 PTHREADINFO pti;
382 PUSER_MESSAGE_QUEUE ThreadQueue;
383
384 if (Window)
385 ASSERT_REFS_CO(Window);
386
387 pti = PsGetCurrentThreadWin32Thread();
388 ThreadQueue = pti->MessageQueue;
389 ASSERT(ThreadQueue != 0);
390
391 hWndPrev = ThreadQueue->FocusWindow;
392
393 if (Window != 0)
394 {
395 if (hWndPrev == Window->head.h)
396 {
397 return hWndPrev;
398 }
399
400 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
401 {
402 DPRINT1("SetFocusWindow 1 WH_CBT Call Hook return!\n");
403 return 0;
404 }
405 ThreadQueue->FocusWindow = Window->head.h;
406
407 co_IntSendKillFocusMessages(hWndPrev, Window->head.h);
408 co_IntSendSetFocusMessages(hWndPrev, Window->head.h);
409 }
410 else
411 {
412 ThreadQueue->FocusWindow = 0;
413 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
414 {
415 DPRINT1("SetFocusWindow 2 WH_CBT Call Hook return!\n");
416 return 0;
417 }
418
419 co_IntSendKillFocusMessages(hWndPrev, 0);
420 }
421 return hWndPrev;
422 }
423
424
425 /*
426 * @implemented
427 */
428 HWND FASTCALL
429 UserGetForegroundWindow(VOID)
430 {
431 PUSER_MESSAGE_QUEUE ForegroundQueue;
432
433 ForegroundQueue = IntGetFocusMessageQueue();
434 return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
435 }
436
437
438 /*
439 * @implemented
440 */
441 HWND APIENTRY
442 NtUserGetForegroundWindow(VOID)
443 {
444 DECLARE_RETURN(HWND);
445
446 DPRINT("Enter NtUserGetForegroundWindow\n");
447 UserEnterExclusive();
448
449 RETURN( UserGetForegroundWindow());
450
451 CLEANUP:
452 DPRINT("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
453 UserLeave();
454 END_CLEANUP;
455 }
456
457
458 HWND FASTCALL UserGetActiveWindow(VOID)
459 {
460 PTHREADINFO pti;
461 PUSER_MESSAGE_QUEUE ThreadQueue;
462
463 pti = PsGetCurrentThreadWin32Thread();
464 ThreadQueue = pti->MessageQueue;
465 return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
466 }
467
468
469 HWND APIENTRY
470 NtUserSetActiveWindow(HWND hWnd)
471 {
472 USER_REFERENCE_ENTRY Ref;
473 DECLARE_RETURN(HWND);
474
475 DPRINT("Enter NtUserSetActiveWindow(%x)\n", hWnd);
476 UserEnterExclusive();
477
478 if (hWnd)
479 {
480 PWND Window;
481 PTHREADINFO pti;
482 PUSER_MESSAGE_QUEUE ThreadQueue;
483 HWND hWndPrev;
484
485 if (!(Window = UserGetWindowObject(hWnd)))
486 {
487 RETURN( 0);
488 }
489
490 pti = PsGetCurrentThreadWin32Thread();
491 ThreadQueue = pti->MessageQueue;
492
493 if (Window->head.pti->MessageQueue != ThreadQueue)
494 {
495 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
496 RETURN( 0);
497 }
498
499 UserRefObjectCo(Window, &Ref);
500 hWndPrev = co_IntSetActiveWindow(Window);
501 UserDerefObjectCo(Window);
502
503 RETURN( hWndPrev);
504 }
505 else
506 {
507 RETURN( co_IntSetActiveWindow(0));
508 }
509
510 CLEANUP:
511 DPRINT("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
512 UserLeave();
513 END_CLEANUP;
514 }
515
516 /*
517 * @implemented
518 */
519 HWND APIENTRY
520 IntGetCapture(VOID)
521 {
522 PTHREADINFO pti;
523 PUSER_MESSAGE_QUEUE ThreadQueue;
524 DECLARE_RETURN(HWND);
525
526 DPRINT("Enter IntGetCapture\n");
527
528 pti = PsGetCurrentThreadWin32Thread();
529 ThreadQueue = pti->MessageQueue;
530 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
531
532 CLEANUP:
533 DPRINT("Leave IntGetCapture, ret=%i\n",_ret_);
534 END_CLEANUP;
535 }
536
537
538 HWND FASTCALL
539 co_UserSetCapture(HWND hWnd)
540 {
541 PTHREADINFO pti;
542 PUSER_MESSAGE_QUEUE ThreadQueue;
543 PWND Window, pWnd;
544 HWND hWndPrev;
545
546 pti = PsGetCurrentThreadWin32Thread();
547 ThreadQueue = pti->MessageQueue;
548
549 if ((Window = UserGetWindowObject(hWnd)))
550 {
551 if (Window->head.pti->MessageQueue != ThreadQueue)
552 {
553 return NULL;
554 }
555 }
556
557 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
558
559 if (hWndPrev)
560 {
561 pWnd = UserGetWindowObject(hWndPrev);
562 if (pWnd)
563 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
564 }
565
566 /* also remove other windows if not capturing anymore */
567 if (hWnd == NULL)
568 {
569 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
570 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
571 }
572
573 if (Window)
574 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
575
576 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
577 ThreadQueue->CaptureWindow = hWnd;
578
579 return hWndPrev;
580 }
581
582 /*
583 * @implemented
584 */
585 HWND APIENTRY
586 NtUserSetCapture(HWND hWnd)
587 {
588 DECLARE_RETURN(HWND);
589
590 DPRINT("Enter NtUserSetCapture(%x)\n", hWnd);
591 UserEnterExclusive();
592
593 RETURN( co_UserSetCapture(hWnd));
594
595 CLEANUP:
596 DPRINT("Leave NtUserSetCapture, ret=%i\n",_ret_);
597 UserLeave();
598 END_CLEANUP;
599 }
600
601
602
603 HWND FASTCALL co_UserSetFocus(PWND Wnd OPTIONAL)
604 {
605 if (Wnd)
606 {
607 PTHREADINFO pti;
608 PUSER_MESSAGE_QUEUE ThreadQueue;
609 HWND hWndPrev;
610 PWND TopWnd;
611 USER_REFERENCE_ENTRY Ref;
612
613 ASSERT_REFS_CO(Wnd);
614
615 pti = PsGetCurrentThreadWin32Thread();
616 ThreadQueue = pti->MessageQueue;
617
618 if (Wnd->style & (WS_MINIMIZE | WS_DISABLED))
619 {
620 return( (ThreadQueue ? ThreadQueue->FocusWindow : 0));
621 }
622
623 if (Wnd->head.pti->MessageQueue != ThreadQueue)
624 {
625 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
626 return( 0);
627 }
628
629 TopWnd = UserGetAncestor(Wnd, GA_ROOT);
630 if (TopWnd && TopWnd->head.h != UserGetActiveWindow())
631 {
632 // PWND WndTops = UserGetWindowObject(hWndTop);
633 UserRefObjectCo(TopWnd, &Ref);
634 co_IntSetActiveWindow(TopWnd);
635 UserDerefObjectCo(TopWnd);
636 }
637
638 hWndPrev = co_IntSetFocusWindow(Wnd);
639
640 return( hWndPrev);
641 }
642 else
643 {
644 return( co_IntSetFocusWindow(NULL));
645 }
646
647 }
648
649
650 /*
651 * @implemented
652 */
653 HWND APIENTRY
654 NtUserSetFocus(HWND hWnd)
655 {
656 PWND Window;
657 USER_REFERENCE_ENTRY Ref;
658 DECLARE_RETURN(HWND);
659 HWND ret;
660
661 DPRINT("Enter NtUserSetFocus(%x)\n", hWnd);
662 UserEnterExclusive();
663
664 if (hWnd)
665 {
666 if (!(Window = UserGetWindowObject(hWnd)))
667 {
668 RETURN(NULL);
669 }
670
671 UserRefObjectCo(Window, &Ref);
672 ret = co_UserSetFocus(Window);
673 UserDerefObjectCo(Window);
674
675 RETURN(ret);
676 }
677 else
678 {
679 RETURN( co_UserSetFocus(0));
680 }
681
682 CLEANUP:
683 DPRINT("Leave NtUserSetFocus, ret=%i\n",_ret_);
684 UserLeave();
685 END_CLEANUP;
686 }
687
688 /* EOF */