Sync with trunk (r47116), hopefully without breaking anything.
[reactos.git] / 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_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 hWndFocusPrev = PrevForegroundQueue->FocusWindow;
231 }
232
233 if (hWndPrev == hWnd)
234 {
235 DPRINT("Failed - Same\n");
236 return TRUE;
237 }
238
239 /* FIXME: Call hooks. */
240
241 co_IntSendDeactivateMessages(hWndPrev, hWnd);
242 co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
243
244 IntSetFocusMessageQueue(Window->pti->MessageQueue);
245 if (Window->pti->MessageQueue)
246 {
247 Window->pti->MessageQueue->ActiveWindow = hWnd;
248 }
249
250 if (FocusWindow->pti->MessageQueue)
251 {
252 FocusWindow->pti->MessageQueue->FocusWindow = hWndFocus;
253 }
254
255 if (PrevForegroundQueue != Window->pti->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->pti->pEThread->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->pti->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->pti->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->pti->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 */