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