[Win32k|User32]
[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 UserPostMessage( 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 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
169 }
170 }
171
172 VOID FASTCALL
173 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
174 {
175 if (hWnd)
176 {
177 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
178 }
179 }
180
181 HWND FASTCALL
182 IntFindChildWindowToOwner(PWND Root, PWND Owner)
183 {
184 HWND Ret;
185 PWND Child, OwnerWnd;
186
187 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
188 {
189 OwnerWnd = Child->spwndOwner;
190 if(!OwnerWnd)
191 continue;
192
193 if(OwnerWnd == Owner)
194 {
195 Ret = Child->head.h;
196 return Ret;
197 }
198 }
199
200 return NULL;
201 }
202
203 static BOOL FASTCALL
204 co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate)
205 {
206 HWND hWnd = Wnd->head.h;
207 HWND hWndPrev = NULL;
208 HWND hWndFocus = FocusWindow->head.h;
209 HWND hWndFocusPrev = NULL;
210 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
211
212 ASSERT_REFS_CO(Wnd);
213
214 DPRINT("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, hWndFocus, MouseActivate ? "TRUE" : "FALSE");
215
216 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
217 {
218 DPRINT("Failed - Child\n");
219 return FALSE;
220 }
221
222 if (0 == (Wnd->style & WS_VISIBLE) &&
223 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess)
224 {
225 DPRINT("Failed - Invisible\n");
226 return FALSE;
227 }
228
229 PrevForegroundQueue = IntGetFocusMessageQueue();
230 if (PrevForegroundQueue != 0)
231 {
232 hWndPrev = PrevForegroundQueue->ActiveWindow;
233 hWndFocusPrev = PrevForegroundQueue->FocusWindow;
234 }
235
236 if (hWndPrev == hWnd)
237 {
238 DPRINT("Failed - Same\n");
239 return TRUE;
240 }
241
242 /* FIXME: Call hooks. */
243
244 co_IntSendDeactivateMessages(hWndPrev, hWnd);
245 co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
246
247
248 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
249
250 if (Wnd->head.pti->MessageQueue)
251 {
252 Wnd->head.pti->MessageQueue->ActiveWindow = hWnd;
253 }
254
255 if (FocusWindow->head.pti->MessageQueue)
256 {
257 FocusWindow->head.pti->MessageQueue->FocusWindow = hWndFocus;
258 }
259
260 if (PrevForegroundQueue != Wnd->head.pti->MessageQueue)
261 {
262 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
263 }
264
265 co_IntSendSetFocusMessages(hWndFocusPrev, hWndFocus);
266 co_IntSendActivateMessages(hWndPrev, hWnd, MouseActivate);
267
268 return TRUE;
269 }
270
271 BOOL FASTCALL
272 co_IntSetForegroundWindow(PWND Window)//FIXME: can Window be NULL??
273 {
274 /*if (Window)*/ ASSERT_REFS_CO(Window);
275
276 return co_IntSetForegroundAndFocusWindow(Window, Window, FALSE);
277 }
278
279 BOOL FASTCALL
280 co_IntMouseActivateWindow(PWND Wnd)
281 {
282 HWND Top;
283 PWND TopWindow;
284 USER_REFERENCE_ENTRY Ref;
285
286 ASSERT_REFS_CO(Wnd);
287
288 if(Wnd->style & WS_DISABLED)
289 {
290 BOOL Ret;
291 PWND TopWnd;
292 PWND DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
293 if(DesktopWindow)
294 {
295 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
296 if((TopWnd = UserGetWindowObject(Top)))
297 {
298 UserRefObjectCo(TopWnd, &Ref);
299 Ret = co_IntMouseActivateWindow(TopWnd);
300 UserDerefObjectCo(TopWnd);
301
302 return Ret;
303 }
304 }
305 return FALSE;
306 }
307
308
309 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
310 if (!TopWindow) return FALSE;
311
312 /* TMN: Check return valud from this function? */
313 UserRefObjectCo(TopWindow, &Ref);
314
315 co_IntSetForegroundAndFocusWindow(TopWindow, Wnd, TRUE);
316
317 UserDerefObjectCo(TopWindow);
318
319 return TRUE;
320 }
321
322 HWND FASTCALL
323 co_IntSetActiveWindow(PWND Wnd OPTIONAL)
324 {
325 PTHREADINFO pti;
326 PUSER_MESSAGE_QUEUE ThreadQueue;
327 HWND hWndPrev;
328 HWND hWnd = 0;
329 CBTACTIVATESTRUCT cbt;
330
331 if (Wnd)
332 ASSERT_REFS_CO(Wnd);
333
334 pti = PsGetCurrentThreadWin32Thread();
335 ThreadQueue = pti->MessageQueue;
336 ASSERT(ThreadQueue != 0);
337
338 if (Wnd != 0)
339 {
340 if ((!(Wnd->style & WS_VISIBLE) &&
341 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) ||
342 (Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
343 {
344 return ThreadQueue ? 0 : ThreadQueue->ActiveWindow;
345 }
346 hWnd = Wnd->head.h;
347 }
348
349 hWndPrev = ThreadQueue->ActiveWindow;
350 if (hWndPrev == hWnd)
351 {
352 return hWndPrev;
353 }
354
355 /* call CBT hook chain */
356 cbt.fMouse = FALSE;
357 cbt.hWndActive = hWndPrev;
358 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
359 return 0;
360
361 ThreadQueue->ActiveWindow = hWnd;
362
363 co_IntSendDeactivateMessages(hWndPrev, hWnd);
364 co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
365
366 /* FIXME */
367 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
368 return hWndPrev;
369 }
370
371 static
372 HWND FASTCALL
373 co_IntSetFocusWindow(PWND Window OPTIONAL)
374 {
375 HWND hWndPrev = 0;
376 PTHREADINFO pti;
377 PUSER_MESSAGE_QUEUE ThreadQueue;
378
379 if (Window)
380 ASSERT_REFS_CO(Window);
381
382 pti = PsGetCurrentThreadWin32Thread();
383 ThreadQueue = pti->MessageQueue;
384 ASSERT(ThreadQueue != 0);
385
386 hWndPrev = ThreadQueue->FocusWindow;
387
388 if (Window != 0)
389 {
390 if (hWndPrev == Window->head.h)
391 {
392 return hWndPrev;
393 }
394
395 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
396 return 0;
397
398 ThreadQueue->FocusWindow = Window->head.h;
399
400 co_IntSendKillFocusMessages(hWndPrev, Window->head.h);
401 co_IntSendSetFocusMessages(hWndPrev, Window->head.h);
402 }
403 else
404 {
405 ThreadQueue->FocusWindow = 0;
406
407 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
408 return 0;
409
410 co_IntSendKillFocusMessages(hWndPrev, 0);
411 }
412 return hWndPrev;
413 }
414
415
416 /*
417 * @implemented
418 */
419 HWND FASTCALL
420 UserGetForegroundWindow(VOID)
421 {
422 PUSER_MESSAGE_QUEUE ForegroundQueue;
423
424 ForegroundQueue = IntGetFocusMessageQueue();
425 return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
426 }
427
428
429 /*
430 * @implemented
431 */
432 HWND APIENTRY
433 NtUserGetForegroundWindow(VOID)
434 {
435 DECLARE_RETURN(HWND);
436
437 DPRINT("Enter NtUserGetForegroundWindow\n");
438 UserEnterExclusive();
439
440 RETURN( UserGetForegroundWindow());
441
442 CLEANUP:
443 DPRINT("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
444 UserLeave();
445 END_CLEANUP;
446 }
447
448
449 HWND FASTCALL UserGetActiveWindow(VOID)
450 {
451 PTHREADINFO pti;
452 PUSER_MESSAGE_QUEUE ThreadQueue;
453
454 pti = PsGetCurrentThreadWin32Thread();
455 ThreadQueue = pti->MessageQueue;
456 return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
457 }
458
459
460 HWND APIENTRY
461 NtUserSetActiveWindow(HWND hWnd)
462 {
463 USER_REFERENCE_ENTRY Ref;
464 DECLARE_RETURN(HWND);
465
466 DPRINT("Enter NtUserSetActiveWindow(%x)\n", hWnd);
467 UserEnterExclusive();
468
469 if (hWnd)
470 {
471 PWND Window;
472 PTHREADINFO pti;
473 PUSER_MESSAGE_QUEUE ThreadQueue;
474 HWND hWndPrev;
475
476 if (!(Window = UserGetWindowObject(hWnd)))
477 {
478 RETURN( 0);
479 }
480
481 pti = PsGetCurrentThreadWin32Thread();
482 ThreadQueue = pti->MessageQueue;
483
484 if (Window->head.pti->MessageQueue != ThreadQueue)
485 {
486 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
487 RETURN( 0);
488 }
489
490 UserRefObjectCo(Window, &Ref);
491 hWndPrev = co_IntSetActiveWindow(Window);
492 UserDerefObjectCo(Window);
493
494 RETURN( hWndPrev);
495 }
496 else
497 {
498 RETURN( co_IntSetActiveWindow(0));
499 }
500
501 CLEANUP:
502 DPRINT("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
503 UserLeave();
504 END_CLEANUP;
505 }
506
507 /*
508 * @implemented
509 */
510 HWND APIENTRY
511 IntGetCapture(VOID)
512 {
513 PTHREADINFO pti;
514 PUSER_MESSAGE_QUEUE ThreadQueue;
515 DECLARE_RETURN(HWND);
516
517 DPRINT("Enter IntGetCapture\n");
518
519 pti = PsGetCurrentThreadWin32Thread();
520 ThreadQueue = pti->MessageQueue;
521 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
522
523 CLEANUP:
524 DPRINT("Leave IntGetCapture, ret=%i\n",_ret_);
525 END_CLEANUP;
526 }
527
528 /*
529 * @implemented
530 */
531 HWND APIENTRY
532 NtUserSetCapture(HWND hWnd)
533 {
534 PTHREADINFO pti;
535 PUSER_MESSAGE_QUEUE ThreadQueue;
536 PWND Window;
537 HWND hWndPrev;
538 DECLARE_RETURN(HWND);
539
540 DPRINT("Enter NtUserSetCapture(%x)\n", hWnd);
541 UserEnterExclusive();
542
543 pti = PsGetCurrentThreadWin32Thread();
544 ThreadQueue = pti->MessageQueue;
545
546 if((Window = UserGetWindowObject(hWnd)))
547 {
548 if(Window->head.pti->MessageQueue != ThreadQueue)
549 {
550 RETURN(NULL);
551 }
552 }
553
554 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
555
556 /* also remove other windows if not capturing anymore */
557 if(hWnd == NULL)
558 {
559 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
560 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
561 }
562
563 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
564 ThreadQueue->CaptureWindow = hWnd;
565
566 RETURN( hWndPrev);
567
568 CLEANUP:
569 DPRINT("Leave NtUserSetCapture, ret=%i\n",_ret_);
570 UserLeave();
571 END_CLEANUP;
572 }
573
574
575
576 HWND FASTCALL co_UserSetFocus(PWND Wnd OPTIONAL)
577 {
578 if (Wnd)
579 {
580 PTHREADINFO pti;
581 PUSER_MESSAGE_QUEUE ThreadQueue;
582 HWND hWndPrev;
583 PWND TopWnd;
584 USER_REFERENCE_ENTRY Ref;
585
586 ASSERT_REFS_CO(Wnd);
587
588 pti = PsGetCurrentThreadWin32Thread();
589 ThreadQueue = pti->MessageQueue;
590
591 if (Wnd->style & (WS_MINIMIZE | WS_DISABLED))
592 {
593 return( (ThreadQueue ? ThreadQueue->FocusWindow : 0));
594 }
595
596 if (Wnd->head.pti->MessageQueue != ThreadQueue)
597 {
598 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
599 return( 0);
600 }
601
602 TopWnd = UserGetAncestor(Wnd, GA_ROOT);
603 if (TopWnd && TopWnd->head.h != UserGetActiveWindow())
604 {
605 // PWND WndTops = UserGetWindowObject(hWndTop);
606 UserRefObjectCo(TopWnd, &Ref);
607 co_IntSetActiveWindow(TopWnd);
608 UserDerefObjectCo(TopWnd);
609 }
610
611 hWndPrev = co_IntSetFocusWindow(Wnd);
612
613 return( hWndPrev);
614 }
615 else
616 {
617 return( co_IntSetFocusWindow(NULL));
618 }
619
620 }
621
622
623 /*
624 * @implemented
625 */
626 HWND APIENTRY
627 NtUserSetFocus(HWND hWnd)
628 {
629 PWND Window;
630 USER_REFERENCE_ENTRY Ref;
631 DECLARE_RETURN(HWND);
632 HWND ret;
633
634 DPRINT("Enter NtUserSetFocus(%x)\n", hWnd);
635 UserEnterExclusive();
636
637 if (hWnd)
638 {
639 if (!(Window = UserGetWindowObject(hWnd)))
640 {
641 RETURN(NULL);
642 }
643
644 UserRefObjectCo(Window, &Ref);
645 ret = co_UserSetFocus(Window);
646 UserDerefObjectCo(Window);
647
648 RETURN(ret);
649 }
650 else
651 {
652 RETURN( co_UserSetFocus(0));
653 }
654
655 CLEANUP:
656 DPRINT("Leave NtUserSetFocus, ret=%i\n",_ret_);
657 UserLeave();
658 END_CLEANUP;
659 }
660
661 /* EOF */