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