[Win32k]
[reactos.git] / reactos / win32ss / user / ntuser / focus.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Focus functions
5 * FILE: subsystems/win32/win32k/ntuser/focus.c
6 * PROGRAMER: ReactOS Team
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserFocus);
11
12 PUSER_MESSAGE_QUEUE gpqForeground = NULL;
13 PUSER_MESSAGE_QUEUE gpqForegroundPrev = NULL;
14 PTHREADINFO gptiForeground = NULL;
15 PPROCESSINFO gppiLockSFW = NULL;
16 ULONG guSFWLockCount = 0; // Rule #8, No menus are active. So should be zero.
17 PTHREADINFO ptiLastInput = NULL;
18
19 /*
20 Check locking of a process or one or more menus are active.
21 */
22 BOOL FASTCALL
23 IsFGLocked(VOID)
24 {
25 return (gppiLockSFW || guSFWLockCount);
26 }
27
28 HWND FASTCALL
29 IntGetCaptureWindow(VOID)
30 {
31 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
32 return ForegroundQueue != NULL ? ForegroundQueue->CaptureWindow : 0;
33 }
34
35 HWND FASTCALL
36 IntGetThreadFocusWindow(VOID)
37 {
38 PTHREADINFO pti;
39 PUSER_MESSAGE_QUEUE ThreadQueue;
40
41 pti = PsGetCurrentThreadWin32Thread();
42 ThreadQueue = pti->MessageQueue;
43 if (!ThreadQueue)
44 return NULL;
45 return ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
46 }
47
48 VOID FASTCALL
49 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
50 {
51 PWND WndPrev ;
52
53 if (hWndPrev && (WndPrev = UserGetWindowObject(hWndPrev)))
54 {
55 co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0);
56 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
57 MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
58 (LPARAM)hWnd);
59 }
60 }
61
62 BOOL FASTCALL
63 co_IntMakeWindowActive(PWND Window)
64 {
65 PWND spwndOwner;
66 if (Window)
67 { // Set last active for window and it's owner.
68 Window->spwndLastActive = Window;
69 spwndOwner = Window->spwndOwner;
70 while (spwndOwner)
71 {
72 spwndOwner->spwndLastActive = Window;
73 spwndOwner = spwndOwner->spwndOwner;
74 }
75 return TRUE;
76 }
77 ERR("MakeWindowActive Failed!\n");
78 return FALSE;
79 }
80
81 VOID FASTCALL
82 co_IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
83 {
84 USER_REFERENCE_ENTRY Ref, RefPrev;
85 PWND Window, WindowPrev = NULL;
86 HANDLE OldTID, NewTID;
87 PTHREADINFO ptiOld, ptiNew;
88
89 if ((Window = UserGetWindowObject(hWnd)))
90 {
91 UserRefObjectCo(Window, &Ref);
92
93 WindowPrev = UserGetWindowObject(hWndPrev);
94
95 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
96
97 /* Send palette messages */
98 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
99 co_IntPostOrSendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0))
100 {
101 UserSendNotifyMessage( HWND_BROADCAST,
102 WM_PALETTEISCHANGING,
103 (WPARAM)hWnd,
104 0);
105 }
106
107 if (Window->spwndPrev != NULL)
108 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0,
109 SWP_NOSIZE | SWP_NOMOVE);
110
111 if (!Window->spwndOwner && !IntGetParent(Window))
112 {
113 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd);
114 }
115
116 if (Window)
117 {
118 Window->state |= WNDS_ACTIVEFRAME;
119
120 if (Window->style & WS_MINIMIZE)
121 {
122 TRACE("Widow was minimized\n");
123 }
124 }
125
126 if (WindowPrev)
127 WindowPrev->state &= ~WNDS_ACTIVEFRAME;
128
129 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
130 NewTID = Window ? IntGetWndThreadId(Window) : NULL;
131 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
132 ptiNew = Window ? Window->head.pti : NULL;
133
134 TRACE("SendActiveMessage Old -> %x, New -> %x\n", OldTID, NewTID);
135
136 if (OldTID != NewTID)
137 {
138 PWND cWindow;
139 HWND *List, *phWnd;
140
141 List = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
142 if ( List )
143 {
144 if ( OldTID )
145 {
146 for (phWnd = List; *phWnd; ++phWnd)
147 {
148 cWindow = UserGetWindowObject(*phWnd);
149 if (cWindow && cWindow->head.pti == ptiOld)
150 { // FALSE if the window is being deactivated,
151 // ThreadId that owns the window being activated.
152 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
153 }
154 }
155 }
156 if ( NewTID )
157 {
158 for (phWnd = List; *phWnd; ++phWnd)
159 {
160 cWindow = UserGetWindowObject(*phWnd);
161 if (cWindow && cWindow->head.pti == ptiNew)
162 { // TRUE if the window is being activated,
163 // ThreadId that owns the window being deactivated.
164 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
165 }
166 }
167 }
168 ExFreePool(List);
169 }
170 }
171 if (WindowPrev)
172 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
173
174 UserDerefObjectCo(Window);
175
176 /* FIXME: IntIsWindow */
177 co_IntSendMessageNoWait(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == UserGetForegroundWindow()), 0);
178 /* FIXME: WA_CLICKACTIVE */
179 co_IntSendMessageNoWait(hWnd, WM_ACTIVATE,
180 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE,
181 Window->style & WS_MINIMIZE),
182 (LPARAM)hWndPrev);
183 }
184 }
185
186 VOID FASTCALL
187 co_IntSendKillFocusMessages(HWND hWndPrev, HWND hWnd)
188 {
189 if (hWndPrev)
190 {
191 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
192 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
193 }
194 }
195
196 VOID FASTCALL
197 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
198 {
199 if (hWnd)
200 {
201 PWND pWnd = UserGetWindowObject(hWnd);
202 if (pWnd)
203 {
204 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
205 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
206 }
207 }
208 }
209
210 HWND FASTCALL
211 IntFindChildWindowToOwner(PWND Root, PWND Owner)
212 {
213 HWND Ret;
214 PWND Child, OwnerWnd;
215
216 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
217 {
218 OwnerWnd = Child->spwndOwner;
219 if(!OwnerWnd)
220 continue;
221
222 if(OwnerWnd == Owner)
223 {
224 Ret = Child->head.h;
225 return Ret;
226 }
227 }
228
229 return NULL;
230 }
231
232 VOID FASTCALL
233 FindRemoveAsyncMsg(PWND Wnd)
234 {
235 PUSER_MESSAGE_QUEUE MessageQueue;
236 PUSER_SENT_MESSAGE Message;
237 PLIST_ENTRY Entry;
238
239 if (!Wnd) return;
240
241 MessageQueue = Wnd->head.pti->MessageQueue;
242
243 if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
244 {
245 // Scan sent queue messages to see if we received async messages.
246 Entry = MessageQueue->SentMessagesListHead.Flink;
247 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
248 do
249 {
250 if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
251 Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
252 Message->Msg.wParam == 0 )
253 {
254 TRACE("ASYNC SAW: Found one in the Sent Msg Queue! %p\n", Message->Msg.hwnd);
255 RemoveEntryList(Entry); // Purge the entry.
256 }
257 Entry = Message->ListEntry.Flink;
258 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
259 }
260 while (Entry != &MessageQueue->SentMessagesListHead);
261 }
262 }
263
264 /*
265 Can the system force foreground from one or more conditions.
266 */
267 BOOL FASTCALL
268 CanForceFG(PPROCESSINFO ppi)
269 {
270 if (!ptiLastInput ||
271 ptiLastInput->ppi == ppi ||
272 !gptiForeground ||
273 gptiForeground->ppi == ppi ||
274 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
275 gppiInputProvider == ppi ||
276 !gpqForeground
277 ) return TRUE;
278 return FALSE;
279 }
280
281 /*
282 MSDN:
283 The system restricts which processes can set the foreground window. A process
284 can set the foreground window only if one of the following conditions is true:
285
286 * The process is the foreground process.
287 * The process was started by the foreground process.
288 * The process received the last input event.
289 * There is no foreground process.
290 * The foreground process is being debugged.
291 * The foreground is not locked (see LockSetForegroundWindow).
292 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
293 * No menus are active.
294 */
295
296 static BOOL FASTCALL
297 co_IntSetForegroundAndFocusWindow(PWND Wnd, BOOL MouseActivate)
298 {
299 HWND hWnd = UserHMGetHandle(Wnd);
300 HWND hWndPrev = NULL;
301 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
302 PTHREADINFO pti;
303 BOOL fgRet = FALSE, Ret = FALSE;
304
305 ASSERT_REFS_CO(Wnd);
306
307 TRACE("SetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, MouseActivate ? "TRUE" : "FALSE");
308
309 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
310 pti = PsGetCurrentThreadWin32Thread();
311
312 if (PrevForegroundQueue)
313 { // Same Window Q as foreground just do active.
314 if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue)
315 {
316 if (pti->MessageQueue == PrevForegroundQueue)
317 { // Same WQ and TQ go active.
318 Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE);
319 }
320 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
321 { // Same WQ and it is active.
322 Ret = TRUE;
323 }
324 else
325 { // Same WQ as FG but not the same TQ send active.
326 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
327 Ret = TRUE;
328 }
329 return Ret;
330 }
331
332 hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0;
333 }
334
335 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
336 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
337 pti->ppi == ppiScrnSaver
338 )
339 {
340 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
341 gptiForeground = Wnd->head.pti;
342 /*
343 Henri Verbeet,
344 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
345 other thread after we already changed the foreground window back to our own
346 window.
347 */
348 FindRemoveAsyncMsg(Wnd); // Do this to fix test_SFW todos!
349 fgRet = TRUE;
350 }
351
352 // Fix FG Bounce with regedit.
353 if (hWndPrev != hWnd )
354 {
355 if (PrevForegroundQueue &&
356 fgRet &&
357 Wnd->head.pti->MessageQueue != PrevForegroundQueue &&
358 PrevForegroundQueue->spwndActive)
359 {
360 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
361 if (pti->MessageQueue == PrevForegroundQueue)
362 {
363 //ERR("SFGW: TI same as Prev TI\n");
364 co_IntSetActiveWindow(NULL, NULL, FALSE, TRUE);
365 }
366 else
367 co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
368 }
369 }
370
371 if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
372 {
373 Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE);
374 }
375 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
376 {
377 Ret = TRUE;
378 }
379 else
380 {
381 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
382 Ret = TRUE;
383 }
384
385 return Ret && fgRet;
386 }
387
388 BOOL FASTCALL
389 co_IntMouseActivateWindow(PWND Wnd)
390 {
391 HWND Top;
392 PWND TopWindow;
393 USER_REFERENCE_ENTRY Ref;
394
395 ASSERT_REFS_CO(Wnd);
396
397 if (Wnd->style & WS_DISABLED)
398 {
399 BOOL Ret;
400 PWND TopWnd;
401 PWND DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
402 if (DesktopWindow)
403 {
404 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
405 if ((TopWnd = UserGetWindowObject(Top)))
406 {
407 UserRefObjectCo(TopWnd, &Ref);
408 Ret = co_IntMouseActivateWindow(TopWnd);
409 UserDerefObjectCo(TopWnd);
410
411 return Ret;
412 }
413 }
414 return FALSE;
415 }
416
417 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
418 if (!TopWindow) return FALSE;
419
420 /* TMN: Check return valud from this function? */
421 UserRefObjectCo(TopWindow, &Ref);
422
423 co_IntSetForegroundAndFocusWindow(TopWindow, TRUE);
424
425 UserDerefObjectCo(TopWindow);
426
427 return TRUE;
428 }
429
430 BOOL FASTCALL
431 co_IntSetActiveWindow(PWND Wnd OPTIONAL, HWND * Prev, BOOL bMouse, BOOL bFocus)
432 {
433 PTHREADINFO pti;
434 PUSER_MESSAGE_QUEUE ThreadQueue;
435 HWND hWndPrev;
436 HWND hWnd = 0;
437 CBTACTIVATESTRUCT cbt;
438
439 if (Wnd)
440 {
441 ASSERT_REFS_CO(Wnd);
442 hWnd = UserHMGetHandle(Wnd);
443 }
444
445 pti = PsGetCurrentThreadWin32Thread();
446 ThreadQueue = pti->MessageQueue;
447 ASSERT(ThreadQueue != 0);
448
449 hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
450 if (Prev) *Prev = hWndPrev;
451 if (hWndPrev == hWnd) return TRUE;
452
453 if (Wnd)
454 {
455 if (ThreadQueue != Wnd->head.pti->MessageQueue)
456 {
457 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
458 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
459 if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
460 {
461 return co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
462 }
463 }
464
465 if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
466 }
467
468 /* Call CBT hook chain */
469 cbt.fMouse = bMouse;
470 cbt.hWndActive = hWndPrev;
471 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
472 {
473 ERR("SetActiveWindow WH_CBT Call Hook return!\n");
474 return FALSE;
475 }
476
477 co_IntSendDeactivateMessages(hWndPrev, hWnd);
478
479 if (Wnd) Wnd->state |= WNDS_BEINGACTIVATED;
480
481 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
482
483 /* check if the specified window can be set in the input data of a given queue */
484 if ( !Wnd || ThreadQueue == Wnd->head.pti->MessageQueue)
485 {
486 /* set the current thread active window */
487 if (!Wnd || co_IntMakeWindowActive(Wnd))
488 {
489 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
490 ThreadQueue->spwndActive = Wnd;
491 }
492 }
493
494 co_IntSendActivateMessages(hWndPrev, hWnd, bMouse);
495
496 /* now change focus if necessary */
497 if (bFocus)
498 {
499 /* Do not change focus if the window is no longer active */
500 if (ThreadQueue->spwndActive == Wnd)
501 {
502 if (!ThreadQueue->spwndFocus ||
503 !Wnd ||
504 UserGetAncestor(ThreadQueue->spwndFocus, GA_ROOT) != Wnd)
505 {
506 co_UserSetFocus(Wnd);
507 }
508 }
509 }
510
511 if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
512 return TRUE;
513 }
514
515 HWND FASTCALL
516 co_UserSetFocus(PWND Window)
517 {
518 HWND hWndPrev = 0;
519 PWND pwndTop;
520 PTHREADINFO pti;
521 PUSER_MESSAGE_QUEUE ThreadQueue;
522
523 if (Window)
524 ASSERT_REFS_CO(Window);
525
526 pti = PsGetCurrentThreadWin32Thread();
527 ThreadQueue = pti->MessageQueue;
528 ASSERT(ThreadQueue != 0);
529
530 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
531
532 if (Window != 0)
533 {
534 if (hWndPrev == UserHMGetHandle(Window))
535 {
536 return hWndPrev; /* Nothing to do */
537 }
538
539 if (Window->head.pti->MessageQueue != ThreadQueue)
540 {
541 ERR("SetFocus Must have the same Q!\n");
542 return 0;
543 }
544
545 /* Check if we can set the focus to this window */
546 pwndTop = Window;
547 for (;;)
548 {
549 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
550 if (!pwndTop->spwndParent || pwndTop->spwndParent == UserGetDesktopWindow())
551 {
552 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
553 break;
554 }
555 if (pwndTop->spwndParent == UserGetMessageWindow()) return 0;
556 pwndTop = pwndTop->spwndParent;
557 }
558
559 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
560 {
561 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
562 return 0;
563 }
564
565 /* Activate pwndTop if needed. */
566 if (pwndTop != ThreadQueue->spwndActive)
567 {
568 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
569 if (ThreadQueue != ForegroundQueue) // HACK see rule 2 & 3.
570 {
571 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE))
572 {
573 ERR("SetFocus Set Foreground and Focus Failed!\n");
574 return 0;
575 }
576 }
577
578 /* Set Active when it is needed. */
579 if (pwndTop != ThreadQueue->spwndActive)
580 {
581 if (!co_IntSetActiveWindow(pwndTop, NULL, FALSE, FALSE))
582 {
583 ERR("SetFocus Set Active Failed!\n");
584 return 0;
585 }
586 }
587
588 /* Abort if window destroyed */
589 if (Window->state2 & WNDS2_INDESTROY) return 0;
590 /* Do not change focus if the window is no longer active */
591 if (pwndTop != ThreadQueue->spwndActive)
592 {
593 ERR("SetFocus Top window did not go active!\n");
594 return 0;
595 }
596 }
597
598 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
599 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
600
601 /* check if the specified window can be set in the input data of a given queue */
602 if (ThreadQueue == Window->head.pti->MessageQueue)
603 /* set the current thread focus window */
604 ThreadQueue->spwndFocus = Window;
605
606 TRACE("Focus: %d -> %d\n", hWndPrev, Window->head.h);
607
608 co_IntSendKillFocusMessages(hWndPrev, Window->head.h);
609 co_IntSendSetFocusMessages(hWndPrev, Window->head.h);
610 }
611 else /* NULL hwnd passed in */
612 {
613 if (!hWndPrev) return 0; /* nothing to do */
614 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
615 {
616 ERR("SetFocusWindow 2 WH_CBT Call Hook return!\n");
617 return 0;
618 }
619
620 /* set the current thread focus window null */
621 ThreadQueue->spwndFocus = 0;
622
623 co_IntSendKillFocusMessages(hWndPrev, 0);
624 }
625 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
626 }
627
628 HWND FASTCALL
629 UserGetForegroundWindow(VOID)
630 {
631 PUSER_MESSAGE_QUEUE ForegroundQueue;
632
633 ForegroundQueue = IntGetFocusMessageQueue();
634 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
635 }
636
637 HWND FASTCALL UserGetActiveWindow(VOID)
638 {
639 PTHREADINFO pti;
640 PUSER_MESSAGE_QUEUE ThreadQueue;
641
642 pti = PsGetCurrentThreadWin32Thread();
643 ThreadQueue = pti->MessageQueue;
644 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
645 }
646
647 HWND APIENTRY
648 IntGetCapture(VOID)
649 {
650 PTHREADINFO pti;
651 PUSER_MESSAGE_QUEUE ThreadQueue;
652 DECLARE_RETURN(HWND);
653
654 TRACE("Enter IntGetCapture\n");
655
656 pti = PsGetCurrentThreadWin32Thread();
657 ThreadQueue = pti->MessageQueue;
658 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
659
660 CLEANUP:
661 TRACE("Leave IntGetCapture, ret=%i\n",_ret_);
662 END_CLEANUP;
663 }
664
665 HWND FASTCALL
666 co_UserSetCapture(HWND hWnd)
667 {
668 PTHREADINFO pti;
669 PUSER_MESSAGE_QUEUE ThreadQueue;
670 PWND Window, pWnd;
671 HWND hWndPrev;
672
673 pti = PsGetCurrentThreadWin32Thread();
674 ThreadQueue = pti->MessageQueue;
675
676 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
677 return NULL;
678
679 if ((Window = UserGetWindowObject(hWnd)))
680 {
681 if (Window->head.pti->MessageQueue != ThreadQueue)
682 {
683 return NULL;
684 }
685 }
686
687 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
688
689 if (hWndPrev)
690 {
691 pWnd = UserGetWindowObject(hWndPrev);
692 if (pWnd)
693 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
694 }
695
696 if (Window)
697 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
698
699 if (hWndPrev && hWndPrev != hWnd)
700 {
701 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
702
703 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
704
705 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
706 }
707
708 ThreadQueue->CaptureWindow = hWnd;
709
710 if (hWnd == NULL) // Release mode.
711 {
712 MOUSEINPUT mi;
713 /// These are HACKS!
714 /* Also remove other windows if not capturing anymore */
715 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
716 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
717 ///
718 /* Somebody may have missed some mouse movements */
719 mi.dx = 0;
720 mi.dy = 0;
721 mi.mouseData = 0;
722 mi.dwFlags = MOUSEEVENTF_MOVE;
723 mi.time = 0;
724 mi.dwExtraInfo = 0;
725 UserSendMouseInput(&mi, FALSE);
726 }
727 return hWndPrev;
728 }
729
730 /*
731 API Call
732 */
733 BOOL
734 FASTCALL
735 IntReleaseCapture(VOID)
736 {
737 PTHREADINFO pti;
738 PUSER_MESSAGE_QUEUE ThreadQueue;
739
740 pti = PsGetCurrentThreadWin32Thread();
741 ThreadQueue = pti->MessageQueue;
742
743 // Can not release inside WM_CAPTURECHANGED!!
744 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
745
746 co_UserSetCapture(NULL);
747
748 return TRUE;
749 }
750
751 /*
752 API Call
753 */
754 BOOL FASTCALL
755 co_IntSetForegroundWindow(PWND Window)
756 {
757 ASSERT_REFS_CO(Window);
758
759 return co_IntSetForegroundAndFocusWindow(Window, FALSE);
760 }
761
762 /*
763 API Call
764 */
765 BOOL FASTCALL
766 IntLockSetForegroundWindow(UINT uLockCode)
767 {
768 ULONG Err = ERROR_ACCESS_DENIED;
769 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
770 switch (uLockCode)
771 {
772 case LSFW_LOCK:
773 if ( CanForceFG(ppi) && !gppiLockSFW )
774 {
775 gppiLockSFW = ppi;
776 return TRUE;
777 }
778 break;
779 case LSFW_UNLOCK:
780 if ( gppiLockSFW == ppi)
781 {
782 gppiLockSFW = NULL;
783 return TRUE;
784 }
785 break;
786 default:
787 Err = ERROR_INVALID_PARAMETER;
788 }
789 EngSetLastError(Err);
790 return FALSE;
791 }
792
793 /*
794 API Call
795 */
796 BOOL FASTCALL
797 IntAllowSetForegroundWindow(DWORD dwProcessId)
798 {
799 PPROCESSINFO ppi, ppiCur;
800 PEPROCESS Process = NULL;
801
802 ppi = NULL;
803 if (dwProcessId != ASFW_ANY)
804 {
805 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)dwProcessId, &Process)))
806 {
807 EngSetLastError(ERROR_INVALID_PARAMETER);
808 return FALSE;
809 }
810 ppi = PsGetProcessWin32Process(Process);
811 if (!ppi)
812 {
813 ObDereferenceObject(Process);
814 return FALSE;
815 }
816 }
817 ppiCur = PsGetCurrentProcessWin32Process();
818 if (!CanForceFG(ppiCur))
819 {
820 if (Process) ObDereferenceObject(Process);
821 EngSetLastError(ERROR_ACCESS_DENIED);
822 return FALSE;
823 }
824 if (dwProcessId == ASFW_ANY)
825 { // All processes will be enabled to set the foreground window.
826 ptiLastInput = NULL;
827 }
828 else
829 { // Rule #3, last input event in force.
830 ptiLastInput = ppi->ptiList;
831 ObDereferenceObject(Process);
832 }
833 return TRUE;
834 }
835
836 /*
837 * @implemented
838 */
839 HWND APIENTRY
840 NtUserGetForegroundWindow(VOID)
841 {
842 DECLARE_RETURN(HWND);
843
844 TRACE("Enter NtUserGetForegroundWindow\n");
845 UserEnterExclusive();
846
847 RETURN( UserGetForegroundWindow());
848
849 CLEANUP:
850 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
851 UserLeave();
852 END_CLEANUP;
853 }
854
855 HWND APIENTRY
856 NtUserSetActiveWindow(HWND hWnd)
857 {
858 USER_REFERENCE_ENTRY Ref;
859 HWND hWndPrev;
860 PWND Window;
861 DECLARE_RETURN(HWND);
862
863 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd);
864 UserEnterExclusive();
865
866 Window = NULL;
867 if (hWnd)
868 {
869 if (!(Window = UserGetWindowObject(hWnd)))
870 {
871 RETURN( 0);
872 }
873 }
874
875 if (!Window ||
876 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
877 {
878 if (Window) UserRefObjectCo(Window, &Ref);
879 if (!co_IntSetActiveWindow(Window, &hWndPrev, FALSE, TRUE)) hWndPrev = NULL;
880 if (Window) UserDerefObjectCo(Window);
881 }
882 else
883 hWndPrev = NULL;
884
885 RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
886
887 CLEANUP:
888 TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
889 UserLeave();
890 END_CLEANUP;
891 }
892
893 /*
894 * @implemented
895 */
896 HWND APIENTRY
897 NtUserSetCapture(HWND hWnd)
898 {
899 DECLARE_RETURN(HWND);
900
901 TRACE("Enter NtUserSetCapture(%x)\n", hWnd);
902 UserEnterExclusive();
903
904 RETURN( co_UserSetCapture(hWnd));
905
906 CLEANUP:
907 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_);
908 UserLeave();
909 END_CLEANUP;
910 }
911
912 /*
913 * @implemented
914 */
915 HWND APIENTRY
916 NtUserSetFocus(HWND hWnd)
917 {
918 PWND Window;
919 USER_REFERENCE_ENTRY Ref;
920 DECLARE_RETURN(HWND);
921 HWND ret;
922
923 TRACE("Enter NtUserSetFocus(%x)\n", hWnd);
924 UserEnterExclusive();
925
926 if (hWnd)
927 {
928 if (!(Window = UserGetWindowObject(hWnd)))
929 {
930 RETURN(NULL);
931 }
932
933 UserRefObjectCo(Window, &Ref);
934 ret = co_UserSetFocus(Window);
935 UserDerefObjectCo(Window);
936
937 RETURN(ret);
938 }
939 else
940 {
941 RETURN( co_UserSetFocus(0));
942 }
943
944 CLEANUP:
945 TRACE("Leave NtUserSetFocus, ret=%i\n",_ret_);
946 UserLeave();
947 END_CLEANUP;
948 }
949
950 /* EOF */