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