xref: /reactos/win32ss/user/ntuser/focus.c (revision 2196a06f)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Focus functions
5  * FILE:             win32ss/user/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 HWND ghwndOldFullscreen = NULL;
19 
20 /*
21   Check locking of a process or one or more menus are active.
22 */
23 BOOL FASTCALL
24 IsFGLocked(VOID)
25 {
26    return (gppiLockSFW || guSFWLockCount);
27 }
28 
29 /*
30   Get capture window via foreground Queue.
31 */
32 HWND FASTCALL
33 IntGetCaptureWindow(VOID)
34 {
35    PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
36    return ( ForegroundQueue ? (ForegroundQueue->spwndCapture ? UserHMGetHandle(ForegroundQueue->spwndCapture) : 0) : 0);
37 }
38 
39 HWND FASTCALL
40 IntGetThreadFocusWindow(VOID)
41 {
42    PTHREADINFO pti;
43    PUSER_MESSAGE_QUEUE ThreadQueue;
44 
45    pti = PsGetCurrentThreadWin32Thread();
46    ThreadQueue = pti->MessageQueue;
47    if (!ThreadQueue)
48      return NULL;
49    return ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
50 }
51 
52 BOOL FASTCALL IntIsWindowFullscreen(PWND Window)
53 {
54     RECTL rclAnd, rclMonitor, rclWindow;
55     PMONITOR pMonitor;
56 
57     if (!Window || !(Window->style & WS_VISIBLE) || (Window->style & WS_CHILD) ||
58         (Window->ExStyle & WS_EX_TOOLWINDOW) || !IntGetWindowRect(Window, &rclWindow))
59     {
60         return FALSE;
61     }
62 
63     pMonitor = UserGetPrimaryMonitor();
64     if (!pMonitor)
65     {
66         RECTL_vSetRect(&rclMonitor, 0, 0,
67                        UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN));
68     }
69     else
70     {
71         rclMonitor = *(LPRECTL)&pMonitor->rcMonitor;
72     }
73 
74     RECTL_bIntersectRect(&rclAnd, &rclMonitor, &rclWindow);
75     return RtlEqualMemory(&rclAnd, &rclMonitor, sizeof(RECTL));
76 }
77 
78 BOOL FASTCALL IntCheckFullscreen(PWND Window)
79 {
80     HWND hWnd;
81 
82     if (ghwndOldFullscreen && !IntIsWindowFullscreen(ValidateHwndNoErr(ghwndOldFullscreen)))
83         ghwndOldFullscreen = NULL;
84 
85     if (!IntIsWindowFullscreen(Window))
86         return FALSE;
87 
88     hWnd = UserHMGetHandle(Window);
89     if (ghwndOldFullscreen != hWnd)
90     {
91         co_IntShellHookNotify(HSHELL_RUDEAPPACTIVATED, (WPARAM)hWnd, TRUE);
92         ghwndOldFullscreen = hWnd;
93     }
94     return TRUE;
95 }
96 
97 VOID FASTCALL
98 UpdateShellHook(PWND Window)
99 {
100    if (IntCheckFullscreen(Window))
101        return;
102 
103    if ( Window->spwndParent == UserGetDesktopWindow() &&
104        (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
105          (Window->ExStyle & WS_EX_APPWINDOW)))
106    {
107        // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
108        co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (WPARAM) UserHMGetHandle(Window), FALSE);
109    }
110    else
111    {
112        co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, 0, FALSE);
113    }
114 }
115 
116 BOOL FASTCALL
117 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd, BOOL Clear)
118 {
119    USER_REFERENCE_ENTRY RefPrev;
120    PWND WndPrev;
121    BOOL Ret = TRUE;
122    LPARAM lParam = hWnd ? (LPARAM)hWnd : 0;
123 
124    if (hWndPrev && (WndPrev = ValidateHwndNoErr(hWndPrev)))
125    {
126       UserRefObjectCo(WndPrev, &RefPrev);
127 
128       if (co_IntSendMessage(hWndPrev, WM_NCACTIVATE, FALSE, lParam))
129       {
130          co_IntSendMessage(hWndPrev, WM_ACTIVATE,
131                     MAKEWPARAM(WA_INACTIVE, (WndPrev->style & WS_MINIMIZE) != 0),
132                     (LPARAM)hWnd);
133 
134          if (WndPrev && Clear)
135             WndPrev->state &= ~(WNDS_ACTIVEFRAME|WNDS_HASCAPTION);
136       }
137       else
138       {
139          ERR("Application is keeping itself Active to prevent the change!\n");
140          Ret = FALSE;
141       }
142 
143       UserDerefObjectCo(WndPrev);
144    }
145    return Ret;
146 }
147 
148 //
149 // Deactivating the foreground message queue.
150 //
151 // Release Active, Capture and Focus Windows associated with this message queue.
152 //
153 BOOL FASTCALL
154 IntDeactivateWindow(PTHREADINFO pti, HANDLE tid)
155 {
156    USER_REFERENCE_ENTRY Ref;
157    PTHREADINFO ptiPrev;
158    PWND pwndPrev;
159    BOOL InAAPM = FALSE;
160    PTHREADINFO ptiCurrent = PsGetCurrentThreadWin32Thread();
161 
162    if ( !pti->MessageQueue->spwndActive )
163    {
164       TRACE("IDAW E : Nothing to do, Active is NULL! pti 0x%p tid 0x%p\n",pti,tid);
165       return TRUE;
166    }
167 
168    TRACE("IDAW : pti 0x%p tid 0x%p\n",pti,tid);
169 
170    if (ptiCurrent != pti)
171    {
172       IntReferenceThreadInfo(pti);
173       IntReferenceThreadInfo(ptiCurrent);
174    }
175 
176    if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) )
177    {
178       pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
179       InAAPM = TRUE;
180    }
181 
182    //
183    // Check for Capture and release it.
184    //
185    if ( pti->MessageQueue->spwndCapture )
186    {
187       MSG msg;
188       PWND pwndCapture = pti->MessageQueue->spwndCapture;
189 
190       UserRefObjectCo(pwndCapture, &Ref);
191       co_IntSendMessage(UserHMGetHandle(pwndCapture), WM_CANCELMODE, 0, 0);
192       UserDerefObjectCo(pwndCapture);
193 
194       /* Generate mouse move message */
195       msg.message = WM_MOUSEMOVE;
196       msg.wParam = UserGetMouseButtonsState();
197       msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
198       msg.pt = gpsi->ptCursor;
199       co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
200    }
201 
202    //
203    // Check for Active and release it.
204    //
205    if ( pti->MessageQueue->spwndActive )
206    {
207       pwndPrev = pti->MessageQueue->spwndActive;
208       ptiPrev = pwndPrev->head.pti;
209 
210       if (!co_IntSendDeactivateMessages(UserHMGetHandle(pwndPrev), 0, TRUE))
211       {
212          if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
213          if (ptiCurrent != pti)
214          {
215             IntDereferenceThreadInfo(pti);
216             IntDereferenceThreadInfo(ptiCurrent);
217          }
218          return FALSE;
219       }
220 
221       if ( pti->MessageQueue->spwndActive == pwndPrev )
222       {
223           pti->MessageQueue->spwndActivePrev = pwndPrev;
224           pti->MessageQueue->spwndActive     = NULL;
225       }
226 
227       if (ptiPrev->TIF_flags & TIF_INCLEANUP) ptiPrev = NULL;
228    }
229    else
230    {
231       ptiPrev = pti;
232       pwndPrev = (PWND)-1; // Avoid zero Active window.
233    }
234 
235    if ( ptiPrev )
236    {
237       HANDLE OldTID = PsGetThreadId(ptiPrev->pEThread);
238       PWND cWindow;
239       HWND *List, *phWnd;
240 
241       List = IntWinListChildren(UserGetDesktopWindow());
242       if ( List )
243       {
244          if ( OldTID )
245          {
246             for (phWnd = List; *phWnd; ++phWnd)
247             {
248                cWindow = ValidateHwndNoErr(*phWnd);
249                if ( cWindow && cWindow->head.pti == ptiPrev )
250                { // FALSE if the window is being deactivated,
251                  // ThreadId that owns the window being activated.
252                  //ERR("IDW : WM_ACTIVATEAPP(0) hwnd %p tid Old %p New %p\n",UserHMGetHandle(cWindow),OldTID,tid);
253                  UserRefObjectCo(cWindow, &Ref);
254                  co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)tid);
255                  UserDerefObjectCo(cWindow);
256                }
257             }
258          }
259          ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
260       }
261    }
262 
263    //
264    // Now check for a change (Bounce), if Active same as previous window, release it too.
265    //
266    if ( pti->MessageQueue->spwndActive == pwndPrev )
267    {
268       if (!co_IntSendDeactivateMessages(UserHMGetHandle(pwndPrev), 0, FALSE))
269       {
270          if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
271          if (ptiCurrent != pti)
272          {
273             IntDereferenceThreadInfo(pti);
274             IntDereferenceThreadInfo(ptiCurrent);
275          }
276          return FALSE;
277       }
278 
279       if ( pti->MessageQueue->spwndActive == pwndPrev )
280       {
281           pti->MessageQueue->spwndActivePrev = pwndPrev;
282           pti->MessageQueue->spwndActive     = NULL;
283       }
284    }
285 
286    //
287    // Check for Focus and release it.
288    //
289    if ( pti->MessageQueue->spwndFocus )
290    {
291       PWND pwndFocus = pti->MessageQueue->spwndFocus;
292 
293       //
294       // Fix win.c:test_SetForegroundWindow:SetActiveWindow(0)!
295       //
296       pti->MessageQueue->spwndFocus = NULL; // Null out Focus.
297 
298       UserRefObjectCo(pwndFocus, &Ref);
299       co_IntSendMessage(UserHMGetHandle(pwndFocus), WM_KILLFOCUS, 0, 0);
300       UserDerefObjectCo(pwndFocus);
301    }
302 
303    if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
304    if (ptiCurrent != pti)
305    {
306       IntDereferenceThreadInfo(pti);
307       IntDereferenceThreadInfo(ptiCurrent);
308    }
309    return TRUE;
310 }
311 
312 //
313 // Activating another threads foreground window after a switch.
314 //
315 VOID FASTCALL
316 IntActivateWindow(PWND Wnd, PTHREADINFO pti, HANDLE tid, DWORD Type)
317 {
318    USER_REFERENCE_ENTRY Ref;
319    PUSER_MESSAGE_QUEUE pmq = pti->MessageQueue;
320 
321    if (Wnd)
322    {
323       Wnd = VerifyWnd(Wnd);
324 
325       if (!Wnd) return;
326 
327       UserRefObjectCo(Wnd, &Ref);
328 
329       if (!gpqForeground)
330       {
331           // No foreground queue set.
332           co_IntSetForegroundMessageQueue( Wnd, pti, (BOOL)Type, 0);
333       }
334       else
335       {
336           // Same Active and Wnd.
337           if ( pmq->spwndActive == Wnd )
338           {
339               WPARAM wParam = (Wnd->head.pti->MessageQueue == gpqForeground);
340 
341               co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, wParam, 0);
342 
343               if (wParam)
344               {
345                   UpdateShellHook(Wnd);
346 
347                   co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
348               }
349           }
350           else // Not the same, set the active Wnd.
351           {
352               co_IntSetActiveWindow(Wnd,(BOOL)Type,TRUE,TRUE);
353           }
354       }
355       UserDerefObjectCo(Wnd);
356    }
357    else // Handle no Wnd!
358    {
359       if ( tid &&                  // TID,
360            pmq->spwndActive &&     // Active WND not zero,
361            gpqForeground == pmq )  // Same message queues.
362       {
363            Wnd = pmq->spwndActive; // Use active window from current queue.
364 
365            UserRefObjectCo(Wnd, &Ref);
366 
367            co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, TRUE, 0);
368 
369            UpdateShellHook(Wnd);
370 
371            co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
372 
373            UserDerefObjectCo(Wnd);
374       }
375       else if (gpqForeground != pmq)
376       {
377            // Not the same message queue so clear flags for foreground switching.
378            pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
379            pti->ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
380       }
381    }
382 }
383 
384 BOOL FASTCALL
385 co_IntMakeWindowActive(PWND Window)
386 {
387    PWND spwndOwner;
388    if (VerifyWnd(Window))
389    {  // Set last active for window and it's owner.
390       spwndOwner = Window;
391       while (spwndOwner->spwndOwner)
392       {
393          spwndOwner = spwndOwner->spwndOwner;
394       }
395       spwndOwner->spwndLastActive = Window;
396       return TRUE;
397    }
398    ERR("MakeWindowActive Failed!\n");
399    return FALSE;
400 }
401 
402 BOOL FASTCALL
403 co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOOL Async)
404 {
405    USER_REFERENCE_ENTRY Ref, RefPrev, RefCall;
406    HANDLE OldTID, NewTID;
407    PTHREADINFO pti, ptiOld, ptiNew;
408    BOOL InAAPM = FALSE;
409 
410    //ERR("SendActivateMessages\n");
411 
412    pti = PsGetCurrentThreadWin32Thread();
413 
414    if (Window)
415    {
416       UserRefObjectCo(Window, &Ref);
417 
418       if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
419 
420       pti->MessageQueue->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED;
421 
422       /* Send palette messages */
423       if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
424           //co_IntPostOrSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
425           co_IntSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
426       {
427          UserSendNotifyMessage( HWND_BROADCAST,
428                                 WM_PALETTEISCHANGING,
429                                (WPARAM)UserHMGetHandle(Window),
430                                 0);
431       }
432       //// Fixes CORE-6434.
433       if (!(Window->style & WS_CHILD))
434       {
435          PWND pwndTemp = co_GetDesktopWindow(Window)->spwndChild;
436 
437          while (pwndTemp && !(pwndTemp->style & WS_VISIBLE)) pwndTemp = pwndTemp->spwndNext;
438 
439          if (Window != pwndTemp || (WindowPrev && !IntIsWindowVisible(WindowPrev)))
440          {
441             if (!Async || pti->MessageQueue == gpqForeground)
442             {
443                UINT flags = SWP_NOSIZE | SWP_NOMOVE;
444                if (Window == pwndTemp) flags |= SWP_NOACTIVATE;
445                //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground);
446                co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, flags);
447             }
448          }
449       }
450       ////
451       //// CORE-1161 and CORE-6651
452       if (Window->spwndPrev)
453       {
454          HWND *phwndTopLevel, *phwndCurrent;
455          PWND pwndCurrent, pwndDesktop;
456 
457          pwndDesktop = co_GetDesktopWindow(Window);//UserGetDesktopWindow();
458          if (Window->spwndParent == pwndDesktop )
459          {
460             phwndTopLevel = IntWinListChildren(pwndDesktop);
461             phwndCurrent = phwndTopLevel;
462             while(*phwndCurrent)
463             {
464                 pwndCurrent = UserGetWindowObject(*phwndCurrent);
465 
466                 if (pwndCurrent && pwndCurrent->spwndOwner == Window )
467                 {
468                     co_WinPosSetWindowPos(pwndCurrent, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
469                 }
470                 phwndCurrent++;
471             }
472             ExFreePoolWithTag(phwndTopLevel, USERTAG_WINDOWLIST);
473           }
474       }
475       ////
476    }
477 
478    OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
479    NewTID = Window ? IntGetWndThreadId(Window) : NULL;
480    ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
481    ptiNew = Window ? Window->head.pti : NULL;
482 
483    //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
484 
485    if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
486         (OldTID != NewTID) )
487    {
488       PWND cWindow;
489       HWND *List, *phWnd;
490 
491       List = IntWinListChildren(UserGetDesktopWindow());
492       if ( List )
493       {
494          if ( OldTID )
495          {
496             ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
497             // Note: Do not set pci flags, this does crash!
498             for (phWnd = List; *phWnd; ++phWnd)
499             {
500                cWindow = ValidateHwndNoErr(*phWnd);
501                if (cWindow && cWindow->head.pti == ptiOld)
502                { // FALSE if the window is being deactivated,
503                  // ThreadId that owns the window being activated.
504                  //ERR("SAM : WM_ACTIVATEAPP(0) tid Old %p New %p\n",OldTID,NewTID);
505                  UserRefObjectCo(cWindow, &RefCall);
506                  co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
507                  UserDerefObjectCo(cWindow);
508                }
509             }
510             ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
511          }
512          if ( NewTID )
513          {  //// Prevents a resource crash due to reentrance!
514             InAAPM = TRUE;
515             pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
516             ////
517             for (phWnd = List; *phWnd; ++phWnd)
518             {
519                cWindow = ValidateHwndNoErr(*phWnd);
520                if (cWindow && cWindow->head.pti == ptiNew)
521                { // TRUE if the window is being activated,
522                  // ThreadId that owns the window being deactivated.
523                  //ERR("SAM : WM_ACTIVATEAPP(1) hwnd %p tid New %p Old %p\n",UserHMGetHandle(cWindow),NewTID,OldTID);
524                  UserRefObjectCo(cWindow, &RefCall);
525                  co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
526                  UserDerefObjectCo(cWindow);
527                }
528             }
529          }
530          ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
531       }
532    }
533 
534    if (Window)
535    {
536       if (WindowPrev)
537          UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
538 
539       if (Window->state & WNDS_ACTIVEFRAME)
540       {  // If already active frame do not allow NCPaint.
541          //ERR("SendActivateMessage Is Active Frame!\n");
542          Window->state |= WNDS_NONCPAINT;
543       }
544 
545       if (Window->style & WS_MINIMIZE)
546       {
547          TRACE("Widow was minimized\n");
548       }
549 
550       co_IntMakeWindowActive(Window);
551 
552       co_IntSendMessage( UserHMGetHandle(Window),
553                          WM_NCACTIVATE,
554                         (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)),
555                          0);
556 
557       co_IntSendMessage( UserHMGetHandle(Window),
558                          WM_ACTIVATE,
559                          MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, (Window->style & WS_MINIMIZE) != 0),
560                         (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0));
561 
562       if (Window->style & WS_VISIBLE)
563          UpdateShellHook(Window);
564 
565       Window->state &= ~WNDS_NONCPAINT;
566 
567       UserDerefObjectCo(Window);
568    }
569    return InAAPM;
570 }
571 
572 VOID FASTCALL
573 IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
574 {
575    PWND pWndPrev;
576    PUSER_MESSAGE_QUEUE ThreadQueue = pti->MessageQueue; // Queue can change...
577 
578    ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
579    if (!pWnd && ThreadQueue->spwndActive)
580    {
581       ThreadQueue->QF_flags |= QF_FOCUSNULLSINCEACTIVE;
582    }
583 
584    pWndPrev = ThreadQueue->spwndFocus;
585 
586    /* check if the specified window can be set in the input data of a given queue */
587    if (!pWnd || ThreadQueue == pWnd->head.pti->MessageQueue)
588       /* set the current thread focus window */
589       ThreadQueue->spwndFocus = pWnd;
590 
591    if (pWnd)
592    {
593       if (pWndPrev)
594       {
595          co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0);
596       }
597       if (ThreadQueue->spwndFocus == pWnd)
598       {
599          IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
600 
601          co_IntSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ? UserHMGetHandle(pWndPrev) : NULL), 0);
602       }
603    }
604    else
605    {
606       if (pWndPrev)
607       {
608          IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
609 
610          co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
611       }
612    }
613 }
614 
615 BOOL FASTCALL
616 FindRemoveEventMsg(PTHREADINFO pti, DWORD Event, DWORD EventLast)
617 {
618    PUSER_MESSAGE Message;
619    PLIST_ENTRY Entry;
620    BOOL Ret = FALSE;
621 
622    Entry = pti->PostedMessagesListHead.Flink;
623    while (Entry != &pti->PostedMessagesListHead)
624    {
625       // Scan posted queue messages to see if we received async messages.
626       Message = CONTAINING_RECORD(Entry, USER_MESSAGE, ListEntry);
627       Entry = Entry->Flink;
628 
629       if (Message->dwQEvent == EventLast)
630       {
631          //ERR("Event D/SAW: Last Activate/Deactivate %d\n", EventLast);
632          return Ret;
633       }
634 
635       if (Message->dwQEvent == Event)
636       {
637          //ERR("Event D/SAW: Found one in the Post Msg Queue! Activate/Deactivate %d\n", Event);
638          ClearMsgBitsMask(pti, Message->QS_Flags);
639          MsqDestroyMessage(Message);
640          Ret = TRUE;
641       }
642    }
643    return Ret;
644 }
645 
646 BOOL FASTCALL
647 ToggleFGActivate(PTHREADINFO pti)
648 {
649    BOOL Ret;
650    PPROCESSINFO ppi = pti->ppi;
651 
652    Ret = !!(pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE);
653    if (Ret)
654    {
655       pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
656    }
657    else
658       Ret = !!(ppi->W32PF_flags & W32PF_ALLOWFOREGROUNDACTIVATE);
659 
660    if (Ret)
661       ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
662    //ERR("ToggleFGActivate is %d\n",Ret);
663    return Ret;
664 }
665 
666 BOOL FASTCALL
667 IsAllowedFGActive(PTHREADINFO pti, PWND Wnd)
668 {
669    // Not allowed if one or more,,
670    if (!ToggleFGActivate(pti) ||              // bits not set,
671         pti->rpdesk != gpdeskInputDesktop ||  // not current Desktop,
672         pti->MessageQueue == gpqForeground || // if already the queue foreground,
673         IsFGLocked() ||                       // foreground is locked,
674         Wnd->ExStyle & WS_EX_NOACTIVATE )     // or,,, does not become the foreground window when the user clicks it.
675    {
676       return FALSE;
677    }
678    //ERR("IsAllowedFGActive is TRUE\n");
679    return TRUE;
680 }
681 
682 /*
683    Can the system force foreground from one or more conditions.
684  */
685 BOOL FASTCALL
686 CanForceFG(PPROCESSINFO ppi)
687 {
688    if (!ptiLastInput ||
689         ptiLastInput->ppi == ppi ||
690        !gptiForeground ||
691         gptiForeground->ppi == ppi ||
692         ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
693         gppiInputProvider == ppi ||
694        !gpqForeground
695       ) return TRUE;
696    //ERR("CanForceFG is FALSE\n");
697    return FALSE;
698 }
699 
700 //
701 //  Switching out foreground message queues.
702 //
703 BOOL FASTCALL
704 co_IntSetForegroundMessageQueue(
705     _In_opt_ PWND Wnd,
706     _In_ PTHREADINFO pti,
707     _In_ BOOL MouseActivate,
708     _In_ DWORD Type )
709 {
710    PTHREADINFO ptiChg, ptiPrev;
711    PUSER_MESSAGE_QUEUE pumq, pumqChg, pumqPrev;
712    BOOL Removed, Ret = TRUE;
713 
714    if (Wnd && !VerifyWnd(Wnd))
715    {
716       return FALSE;
717    }
718 
719    if ( !gptiForeground || gptiForeground->TIF_flags & TIF_INCLEANUP )
720       ptiPrev = NULL;
721    else
722       ptiPrev = gptiForeground;
723 
724    if (Wnd)
725    {
726       ptiChg = Wnd->head.pti;
727       IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
728       gptiForeground = Wnd->head.pti;
729       //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
730    }
731    else
732    {
733       ptiChg = NULL;
734       IntSetFocusMessageQueue(NULL);
735       gptiForeground = NULL;
736       //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
737    }
738 
739    //
740    // Process the changing out of the message queues.
741    //
742    if (gpqForegroundPrev != gpqForeground)
743    {
744       pumqPrev = NULL;
745       if ( ptiPrev && !(ptiPrev->TIF_flags & TIF_INCLEANUP) )
746       {
747          pumqPrev = ptiPrev->MessageQueue;
748       }
749 
750       pumq = pti ? pti->MessageQueue : NULL;
751 
752       // Deactivate the previous message queue.
753       if (pumqPrev)
754       {
755           if ( pumq != pumqPrev )
756           {
757               MSG Msg;
758               HWND hWndPrev = pumqPrev->spwndActive ? UserHMGetHandle(pumqPrev->spwndActive) : NULL;
759               HANDLE tid = gptiForeground ? PsGetThreadId(gptiForeground->pEThread) : NULL; // TID from changing Window PTI.
760 
761               Msg.message = WM_ASYNC_SETACTIVEWINDOW;
762               Msg.hwnd = hWndPrev;
763               Msg.wParam = (WPARAM)pumqPrev->spwndActive;
764               Msg.lParam = 0;
765               Msg.time = 0;
766               //ERR("SFWAMQ : DAW P pti 0x%p tid 0x%p hWndPrev 0x%p\n",ptiPrev,tid,hWndPrev);
767               MsqPostMessage(ptiPrev, &Msg, FALSE, QS_EVENT, POSTEVENT_DAW, (LONG_PTR)tid);
768           }
769       }
770 
771       pumqChg = NULL;
772       if ( ptiChg && !(ptiChg->TIF_flags & TIF_INCLEANUP) )
773       {
774          pumqChg = ptiChg->MessageQueue;
775       }
776 
777       pumq = pti ? pti->MessageQueue : NULL;
778 
779       // Activate changing message queue.
780       if (pumqChg)
781       {
782          /*
783             Henri Verbeet,
784             What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
785             other thread after we already changed the foreground window back to our own
786             window.
787           */
788           //ERR("SFWAMQ : 1\n");
789           Removed = FindRemoveEventMsg(ptiChg, POSTEVENT_DAW, POSTEVENT_NONE);
790 
791           if (pumqChg != pumq)
792           {
793               MSG Msg;
794               HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
795               HANDLE tid = ptiPrev ? PsGetThreadId(ptiPrev->pEThread) : NULL;
796 
797               if (Removed) pumqChg->QF_flags |= QF_EVENTDEACTIVATEREMOVED;
798 
799               Msg.message = WM_ASYNC_SETACTIVEWINDOW;
800               Msg.hwnd = hWnd;
801               Msg.wParam = (WPARAM)Wnd;
802               Msg.lParam = (LPARAM)tid; //// Fixme! Type flags?
803               Msg.time = 0;
804               //ERR("SFWAMQ : SAW P pti 0x%p tid 0x%p hWnd 0x%p\n",ptiChg,tid,hWnd);
805               MsqPostMessage(ptiChg, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)Type|MouseActivate);
806           }
807           else // Current message queue same as changed message queue.
808           {
809               if (pumq->spwndActive == Wnd)
810               {
811                  co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, TRUE, (LPARAM)UserHMGetHandle(Wnd));
812 
813                  UpdateShellHook(Wnd);
814 
815                  co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
816               }
817               else
818               {
819                  //ERR("SFWAMQ : SAW I pti 0x%p hWnd 0x%p\n",ptiChg,Wnd->head.h);
820                  Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE/*Type*/, FALSE);
821                  //if (!Ret) ERR("SFWAMQ : ISAW : return error\n");
822                  return Ret;
823               }
824           }
825       }
826 
827       // Handle same message queue after switch out.
828       pumqPrev = NULL;
829       if ( ptiPrev && !(ptiPrev->TIF_flags & TIF_INCLEANUP) )
830       {
831          pumqPrev = ptiPrev->MessageQueue;
832       }
833       pumq = pti ? pti->MessageQueue : NULL;
834 
835       if ( pumqPrev && pumq == pumqPrev )
836       {
837           HANDLE tid = Wnd ? PsGetThreadId(Wnd->head.pti->pEThread) : NULL;
838           //ERR("SFWAMQ : DAW I pti 0x%p tid 0x%p hWnd 0x%p\n",ptiPrev,tid,Wnd ? Wnd->head.h : 0);
839           IntDeactivateWindow(pti, tid);
840       }
841    }
842    return Ret;
843 }
844 
845 /*
846    MSDN:
847    The system restricts which processes can set the foreground window. A process
848    can set the foreground window only if one of the following conditions is true:
849 
850     * The process is the foreground process.
851     * The process was started by the foreground process.
852     * The process received the last input event.
853     * There is no foreground process.
854     * The foreground process is being debugged.
855     * The foreground is not locked (see LockSetForegroundWindow).
856     * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
857     * No menus are active.
858 */
859 static
860 BOOL FASTCALL
861 co_IntSetForegroundAndFocusWindow(
862     _In_opt_ PWND Wnd,
863     _In_ BOOL MouseActivate,
864     _In_ BOOL bFlash )
865 {
866    HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
867    PUSER_MESSAGE_QUEUE PrevForegroundQueue;
868    PTHREADINFO pti;
869    BOOL Ret = FALSE;
870 
871    if (Wnd) ASSERT_REFS_CO(Wnd);
872 
873    TRACE("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
874 
875    PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
876    pti = PsGetCurrentThreadWin32Thread();
877 
878    if (Wnd && PrevForegroundQueue)
879    {  // Same Window Q as foreground just do active.
880       if (Wnd->head.pti->MessageQueue == PrevForegroundQueue)
881       {
882          //ERR("Same Window Q as foreground just do active.\n");
883          if (pti->MessageQueue == PrevForegroundQueue)
884          { // Same WQ and TQ go active.
885             //ERR("Same WQ and TQ go active.\n");
886             Ret = IntUserSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
887          }
888          else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
889          { // Same WQ and it is active.
890             //ERR("Same WQ and it is active.\n");
891             Ret = TRUE;
892          }
893          else
894          { // Same WQ as FG but not the same TQ send active.
895             //ERR("Same WQ as FG but not the same TQ send active.\n");
896             MSG Msg;
897             PTHREADINFO ptiNew = Wnd->head.pti;
898 
899             Msg.message = WM_ASYNC_SETACTIVEWINDOW;
900             Msg.hwnd = hWnd;
901             Msg.wParam = (WPARAM)Wnd;
902             Msg.lParam = 0;
903             Msg.time = 0;
904             //ERR("SFAFW 1 : SAW P pti 0x%p hWnd 0x%p\n",ptiNew,hWnd);
905             MsqPostMessage(ptiNew, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)MouseActivate);
906 
907             Ret = TRUE;
908          }
909          return Ret;
910       }
911    }
912 
913    if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
914          ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
915         pti->ppi == ppiScrnSaver
916       )
917    {
918 
919       ToggleFGActivate(pti);
920 
921       return co_IntSetForegroundMessageQueue( Wnd, pti, MouseActivate, 0 );
922    }
923 
924    if (!Wnd) return FALSE; // No window, always return FALSE.
925 
926    //// if (bFlash) FIXME : handle flash!!!
927 
928    if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
929    {
930        //ERR("Same PQ and WQ go active.\n");
931        Ret = IntUserSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
932        //if (!Ret) ERR("ISFAFW : IUSAW : return error\n");
933    }
934    else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
935    {
936        TRACE("Same Active and Wnd.\n"); // Leave this for now.
937    }
938    else
939    {
940        //ERR("Activate Not same PQ and WQ and Wnd.\n");
941        //// CORE-10785 fix hang, ROSTESTS-208 allows test to run.
942        MSG Msg;
943        PTHREADINFO ptiNew = Wnd->head.pti;
944 
945        Msg.message = WM_ASYNC_SETACTIVEWINDOW;
946        Msg.hwnd = hWnd;
947        Msg.wParam = (WPARAM)Wnd;
948        Msg.lParam = 0;
949        Msg.time = 0;
950        //ERR("SFAFW 2 : SAW P pti 0x%p hWnd 0x%p\n",ptiNew,hWnd);
951        MsqPostMessage(ptiNew, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)MouseActivate);
952    }
953    // Always return FALSE.
954    return FALSE;
955 }
956 
957 //
958 // Set the Active Window.
959 //
960 BOOL FASTCALL
961 co_IntSetActiveWindow(
962    _In_ PWND Wnd,
963    _In_ BOOL bMouse,
964    _In_ BOOL bFocus,
965    _In_ BOOL Async )
966 {
967    PTHREADINFO pti;
968    PUSER_MESSAGE_QUEUE ThreadQueue;
969    PWND pWndChg, WndPrev; // State changes.
970    HWND hWndPrev;
971    HWND hWnd = 0;
972    BOOL InAAPM;
973    CBTACTIVATESTRUCT cbt;
974 
975    //ERR("co_IntSetActiveWindow 1\n");
976 
977    pti = PsGetCurrentThreadWin32Thread();
978    ThreadQueue = pti->MessageQueue;
979    ASSERT(ThreadQueue != 0);
980 
981    hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
982 
983    pWndChg = ThreadQueue->spwndActive; // Keep to notify of a preemptive switch.
984 
985    if ( !Wnd || Wnd == UserGetDesktopWindow() )
986    {
987       //ERR("ISAW : NULL %p\n",Wnd);
988       return FALSE;
989    }
990 
991    ASSERT_REFS_CO(Wnd);
992    hWnd = UserHMGetHandle(Wnd);
993    //ERR("co_IntSetActiveWindow 2 hWnd 0x%p\n",hWnd);
994 
995    /* check if the specified window can be set in the input data of a given queue */
996    if ( ThreadQueue != Wnd->head.pti->MessageQueue )
997    {
998       //ERR("ISAW : Must have the same Message Queue\n");
999       return FALSE;
1000    }
1001 
1002    if (!VerifyWnd(Wnd))
1003    {
1004       //ERR("ISAW : Window is in Destroy!\n");
1005       return FALSE;
1006    }
1007 
1008    if ( Wnd == pWndChg )
1009    {
1010       //ERR("ISAW : Nothing to do\n");
1011       return TRUE; // Fix CORE-8780 and CORE-11979. See CORE-11324 for breakage.
1012    }
1013 
1014    if ( Wnd->state & WNDS_BEINGACTIVATED ) return TRUE;
1015 
1016    /* Call CBT hook chain */
1017    cbt.fMouse     = bMouse;
1018    cbt.hWndActive = hWndPrev;
1019    if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
1020    {
1021       ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
1022       return FALSE;
1023    }
1024 
1025    ThreadQueue->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED;
1026 
1027    if ( ThreadQueue->spwndActive && ThreadQueue->spwndActive->state & WNDS_DESTROYED )
1028       ThreadQueue->spwndActive = NULL;
1029    else
1030       ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
1031 
1032    WndPrev = ThreadQueue->spwndActive; // Keep to save changing active.
1033 
1034    if (WndPrev)
1035    {
1036       if (ThreadQueue == gpqForeground) gpqForegroundPrev = ThreadQueue;
1037       if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev), hWnd, TRUE)) return FALSE;
1038    }
1039 
1040    WndPrev = ThreadQueue->spwndActive; // Again keep to save changing active.
1041 
1042    // While in calling message proc or hook:
1043    // Fail if a preemptive switch was made, current active not made previous,
1044    // focus window is dead or no longer the same thread queue.
1045    if ( ThreadQueue->spwndActivePrev != ThreadQueue->spwndActive ||
1046         pWndChg != WndPrev ||
1047         (Wnd && !VerifyWnd(Wnd)) ||
1048         ThreadQueue != pti->MessageQueue )
1049    {
1050       ERR("SetActiveWindow: Summary ERROR, active state changed!\n");
1051       return FALSE;
1052    }
1053 
1054    if (!WndPrev) ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
1055 
1056    /* set the current thread active window */
1057    ThreadQueue->spwndActive = Wnd;
1058 
1059    // Set state flag to prevent recursions.
1060    Wnd->state |= WNDS_BEINGACTIVATED;
1061 
1062    IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1063 
1064    // Clear out activate EVENT messages.
1065    FindRemoveEventMsg(pti, POSTEVENT_SAW, POSTEVENT_DAW);
1066 
1067    WndPrev = VerifyWnd(ThreadQueue->spwndActivePrev); // Now should be set but verify it again.
1068 
1069    InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async);
1070 
1071    /* now change focus if necessary */
1072    //// Fixes CORE-6452 allows setting focus on window.
1073    if (bFocus && !(ThreadQueue->QF_flags & QF_FOCUSNULLSINCEACTIVE))
1074    {
1075       /* Do not change focus if the window is no longer active */
1076       if (pti->MessageQueue->spwndActive != IntGetNonChildAncestor(pti->MessageQueue->spwndFocus))
1077       {
1078          PWND pWndSend = pti->MessageQueue->spwndActive;
1079          // Clear focus if the active window is minimized.
1080          if (pWndSend && pti->MessageQueue->spwndActive->style & WS_MINIMIZE) pWndSend = NULL;
1081          // Send focus messages and if so, set the focus.
1082          IntSendFocusMessages( pti, pWndSend);
1083       }
1084    }
1085    ////
1086    if (InAAPM)
1087    {
1088       pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
1089    }
1090 
1091    // Checked in MENU_TrackMenu
1092    ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
1093 
1094    //ERR("co_IntSetActiveWindow Exit\n");
1095    Wnd->state &= ~WNDS_BEINGACTIVATED;
1096    return (ThreadQueue->spwndActive == Wnd);
1097 }
1098 
1099 //
1100 // Set the Active Window.
1101 //
1102 // Window is not optional!
1103 //
1104 BOOL FASTCALL
1105 IntUserSetActiveWindow(
1106    _In_ PWND Wnd,
1107    _In_ BOOL bMouse,
1108    _In_ BOOL bFocus,
1109    _In_ BOOL Async)
1110 {
1111    PTHREADINFO pti;
1112    PUSER_MESSAGE_QUEUE ThreadQueue;
1113 
1114    //ERR("IntUserSetActiveWindow 1\n");
1115    ASSERT_REFS_CO(Wnd);
1116    if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1117    //ERR("IntUserSetActiveWindow 1a hWnd 0x%p\n",UserHMGetHandle(Wnd));
1118 
1119    //ERR("IntUserSetActiveWindow 2\n");
1120    pti = PsGetCurrentThreadWin32Thread();
1121    ThreadQueue = pti->MessageQueue;
1122    ASSERT(ThreadQueue != 0);
1123 
1124    while (Wnd)
1125    {
1126       BOOL Ret, DoFG, AllowFG;
1127 
1128       if (ThreadQueue == Wnd->head.pti->MessageQueue)
1129       {
1130          if (IsAllowedFGActive(pti, Wnd))
1131          {
1132              DoFG = TRUE;
1133          }
1134          else
1135          {
1136              //ERR("IntUserSetActiveWindow 3 Go Out!\n");
1137              break;
1138          }
1139          AllowFG = !pti->cVisWindows; // Nothing is visable.
1140          //ERR("IntUserSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
1141       }
1142       else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
1143       {
1144          //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
1145          // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
1146          if (!gpqForeground || gpqForeground == ThreadQueue)
1147          {
1148             DoFG = TRUE;
1149          }
1150          else
1151             DoFG = FALSE;
1152          if (DoFG)
1153          {
1154             if (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE || pti->cVisWindows)
1155                AllowFG = TRUE;
1156             else
1157                AllowFG = FALSE;
1158          }
1159          else
1160             AllowFG = FALSE;
1161          //ERR("IntUserSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
1162       }
1163       Ret = FALSE;
1164       if (DoFG)
1165       {
1166          pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
1167          //ERR("IntUserSetActiveWindow 3c FG set\n");
1168          Ret = co_IntSetForegroundAndFocusWindow(Wnd, bMouse, TRUE);
1169          if (AllowFG)
1170          {
1171             pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
1172          }
1173          else
1174          {
1175             pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
1176          }
1177       }
1178       return Ret;
1179    }
1180 
1181    return co_IntSetActiveWindow(Wnd, bMouse, bFocus, Async);
1182 }
1183 
1184 BOOL FASTCALL
1185 co_IntMouseActivateWindow(PWND Wnd)
1186 {
1187    TRACE("Mouse Active\n");
1188    return co_IntSetForegroundAndFocusWindow(Wnd, TRUE, TRUE);
1189 }
1190 
1191 BOOL FASTCALL
1192 UserSetActiveWindow( _In_opt_ PWND Wnd )
1193 {
1194   PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1195 
1196   if (Wnd)
1197   {
1198      if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1199 
1200      return IntUserSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
1201   }
1202   /*
1203      Yes your eye are not deceiving you~!
1204 
1205      First part of wines Win.c test_SetActiveWindow:
1206 
1207      flush_events( TRUE );
1208      ShowWindow(hwnd, SW_HIDE);
1209      SetFocus(0);
1210      SetActiveWindow(0);
1211      check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
1212 
1213      Now Handle wines Msg.c test_SetActiveWindow( 0 )...
1214   */
1215   TRACE("USAW: Previous active window\n");
1216   if (  gpqForegroundPrev &&
1217         gpqForegroundPrev->spwndActivePrev &&
1218        (gpqForegroundPrev->spwndActivePrev->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE  &&
1219       !(gpqForegroundPrev->spwndActivePrev->state2 & WNDS2_BOTTOMMOST) &&
1220        (Wnd = VerifyWnd(gpqForegroundPrev->spwndActivePrev)) != NULL )
1221   {
1222      TRACE("USAW:PAW hwnd %p\n",Wnd?Wnd->head.h:NULL);
1223      return IntUserSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
1224   }
1225 
1226   // Activate anyone but the active window.
1227   if ( pti->MessageQueue->spwndActive &&
1228       (Wnd = VerifyWnd(pti->MessageQueue->spwndActive)) != NULL )
1229   {
1230       //ERR("USAW:AOWM hwnd %p\n",Wnd?Wnd->head.h:NULL);
1231       if (!ActivateOtherWindowMin(Wnd))
1232       {
1233          // Okay, now go find someone else to play with!
1234          //ERR("USAW: Going to WPAOW\n");
1235          co_WinPosActivateOtherWindow(Wnd);
1236       }
1237       return TRUE;
1238   }
1239 
1240   TRACE("USAW: Nothing\n");
1241   return FALSE;
1242 }
1243 
1244 HWND FASTCALL
1245 co_UserSetFocus(PWND Window)
1246 {
1247    HWND hWndPrev = 0;
1248    PWND pwndTop;
1249    PTHREADINFO pti;
1250    PUSER_MESSAGE_QUEUE ThreadQueue;
1251 
1252    if (Window)
1253       ASSERT_REFS_CO(Window);
1254 
1255    pti = PsGetCurrentThreadWin32Thread();
1256    ThreadQueue = pti->MessageQueue;
1257    ASSERT(ThreadQueue != 0);
1258 
1259    TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window ? UserHMGetHandle(Window) : 0, pti );
1260 
1261    hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
1262 
1263    if (Window != 0)
1264    {
1265       if (hWndPrev == UserHMGetHandle(Window))
1266       {
1267          return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0; /* Nothing to do */
1268       }
1269 
1270       if (Window->head.pti->MessageQueue != ThreadQueue)
1271       {
1272          ERR("SetFocus Must have the same Q!\n");
1273          return 0;
1274       }
1275 
1276       /* Check if we can set the focus to this window */
1277       //// Fixes wine win test_SetParent both "todo" line 3710 and 3720...
1278       for (pwndTop = Window; pwndTop; pwndTop = pwndTop->spwndParent)
1279       {
1280          if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
1281          if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
1282          if (pwndTop->spwndParent == NULL) break;
1283       }
1284       ////
1285       if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
1286       {
1287          ERR("SetFocus 1 WH_CBT Call Hook return!\n");
1288          return 0;
1289       }
1290 
1291       /* Activate pwndTop if needed. */
1292       if (pwndTop != ThreadQueue->spwndActive)
1293       {
1294          PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
1295          if (ThreadQueue != ForegroundQueue && IsAllowedFGActive(pti, pwndTop)) // Rule 2 & 3.
1296          {
1297             //ERR("SetFocus: Set Foreground!\n");
1298             if (!(pwndTop->style & WS_VISIBLE))
1299             {
1300                 pti->ppi->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE;
1301             }
1302             if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE, TRUE))
1303             {
1304                ERR("SetFocus: Set Foreground and Focus Failed!\n");
1305                return 0;
1306             }
1307          }
1308 
1309          /* Set Active when it is needed. */
1310          if (pwndTop != ThreadQueue->spwndActive)
1311          {
1312             //ERR("SetFocus: Set Active! %p\n",pwndTop?UserHMGetHandle(pwndTop):0);
1313             if (!co_IntSetActiveWindow(pwndTop, FALSE, FALSE, FALSE))
1314             {
1315                ERR("SetFocus: Set Active Failed!\n");
1316                return 0;
1317             }
1318          }
1319 
1320          /* Abort if window destroyed */
1321          if (Window->state2 & WNDS2_INDESTROY) return 0;
1322          /* Do not change focus if the window is no longer active */
1323          if (pwndTop != ThreadQueue->spwndActive)
1324          {
1325             ERR("SetFocus: Top window did not go active!\n");
1326             return 0;
1327          }
1328       }
1329 
1330       // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
1331       hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
1332 
1333       IntSendFocusMessages( pti, Window);
1334 
1335       TRACE("Focus: %p -> %p\n", hWndPrev, Window->head.h);
1336    }
1337    else /* NULL hwnd passed in */
1338    {
1339       if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
1340       {
1341          ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
1342          return 0;
1343       }
1344       //ERR("SetFocus: Set Focus NULL\n");
1345       /* set the current thread focus window null */
1346       IntSendFocusMessages( pti, NULL);
1347    }
1348    return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
1349 }
1350 
1351 HWND FASTCALL
1352 UserGetForegroundWindow(VOID)
1353 {
1354    PUSER_MESSAGE_QUEUE ForegroundQueue;
1355 
1356    ForegroundQueue = IntGetFocusMessageQueue();
1357    return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
1358 }
1359 
1360 HWND FASTCALL UserGetActiveWindow(VOID)
1361 {
1362    PTHREADINFO pti;
1363    PUSER_MESSAGE_QUEUE ThreadQueue;
1364 
1365    pti = PsGetCurrentThreadWin32Thread();
1366    ThreadQueue = pti->MessageQueue;
1367    return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
1368 }
1369 
1370 HWND APIENTRY
1371 IntGetCapture(VOID)
1372 {
1373    PTHREADINFO pti;
1374    PUSER_MESSAGE_QUEUE ThreadQueue;
1375    DECLARE_RETURN(HWND);
1376 
1377    TRACE("Enter IntGetCapture\n");
1378 
1379    pti = PsGetCurrentThreadWin32Thread();
1380    ThreadQueue = pti->MessageQueue;
1381    RETURN( ThreadQueue ? (ThreadQueue->spwndCapture ? UserHMGetHandle(ThreadQueue->spwndCapture) : 0) : 0);
1382 
1383 CLEANUP:
1384    TRACE("Leave IntGetCapture, ret=%p\n", _ret_);
1385    END_CLEANUP;
1386 }
1387 
1388 HWND FASTCALL
1389 co_UserSetCapture(HWND hWnd)
1390 {
1391    PTHREADINFO pti;
1392    PUSER_MESSAGE_QUEUE ThreadQueue;
1393    PWND pWnd, Window = NULL;
1394    HWND hWndPrev;
1395 
1396    pti = PsGetCurrentThreadWin32Thread();
1397    ThreadQueue = pti->MessageQueue;
1398 
1399    if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
1400       return NULL;
1401 
1402    if (hWnd && (Window = UserGetWindowObject(hWnd)))
1403    {
1404       if (Window->head.pti->MessageQueue != ThreadQueue)
1405       {
1406          ERR("Window Thread does not match Current!\n");
1407          return NULL;
1408       }
1409    }
1410 
1411    hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd);
1412 
1413    if (hWndPrev)
1414    {
1415       pWnd = UserGetWindowObject(hWndPrev);
1416       if (pWnd)
1417          IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1418    }
1419 
1420    if (Window)
1421       IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1422 
1423    //
1424    // Only send the message if we have a previous Window!
1425    // Fix msg_menu tracking popup menu and win test_capture_4!!!!
1426    //
1427    if (hWndPrev)
1428    {
1429       if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
1430 
1431       co_IntSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
1432 
1433       ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
1434    }
1435 
1436    if (hWnd == NULL) // Release mode.
1437    {
1438       MOUSEINPUT mi;
1439    /// These are HACKS!
1440       /* Also remove other windows if not capturing anymore */
1441       MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
1442       MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
1443    ///
1444       /* Somebody may have missed some mouse movements */
1445       mi.dx = 0;
1446       mi.dy = 0;
1447       mi.mouseData = 0;
1448       mi.dwFlags = MOUSEEVENTF_MOVE;
1449       mi.time = 0;
1450       mi.dwExtraInfo = 0;
1451       UserSendMouseInput(&mi, FALSE);
1452    }
1453    return hWndPrev;
1454 }
1455 
1456 /*
1457   API Call
1458 */
1459 BOOL
1460 FASTCALL
1461 IntReleaseCapture(VOID)
1462 {
1463    PTHREADINFO pti;
1464    PUSER_MESSAGE_QUEUE ThreadQueue;
1465 
1466    pti = PsGetCurrentThreadWin32Thread();
1467    ThreadQueue = pti->MessageQueue;
1468 
1469    // Can not release inside WM_CAPTURECHANGED!!
1470    if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
1471 
1472    co_UserSetCapture(NULL);
1473 
1474    return TRUE;
1475 }
1476 
1477 /*
1478   API Call
1479 */
1480 BOOL FASTCALL
1481 co_IntSetForegroundWindow(PWND Window)
1482 {
1483    if (Window) ASSERT_REFS_CO(Window);
1484 
1485    return co_IntSetForegroundAndFocusWindow(Window, FALSE, TRUE);
1486 }
1487 
1488 /*
1489   API Call
1490 */
1491 BOOL FASTCALL
1492 co_IntSetForegroundWindowMouse(PWND Window)
1493 {
1494    if (Window) ASSERT_REFS_CO(Window);
1495 
1496    return co_IntSetForegroundAndFocusWindow(Window, TRUE, FALSE);
1497 }
1498 
1499 /*
1500   API Call
1501 */
1502 BOOL FASTCALL
1503 IntLockSetForegroundWindow(UINT uLockCode)
1504 {
1505    ULONG Err = ERROR_ACCESS_DENIED;
1506    PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1507    switch (uLockCode)
1508    {
1509       case LSFW_LOCK:
1510          if ( CanForceFG(ppi) && !gppiLockSFW )
1511          {
1512             gppiLockSFW = ppi;
1513             return TRUE;
1514          }
1515          break;
1516       case LSFW_UNLOCK:
1517          if ( gppiLockSFW == ppi)
1518          {
1519             gppiLockSFW = NULL;
1520             return TRUE;
1521          }
1522          break;
1523       default:
1524          Err = ERROR_INVALID_PARAMETER;
1525    }
1526    EngSetLastError(Err);
1527    return FALSE;
1528 }
1529 
1530 /*
1531   API Call
1532 */
1533 BOOL FASTCALL
1534 IntAllowSetForegroundWindow(DWORD dwProcessId)
1535 {
1536    PPROCESSINFO ppi, ppiCur;
1537    PEPROCESS Process = NULL;
1538 
1539    ppi = NULL;
1540    if (dwProcessId != ASFW_ANY)
1541    {
1542       if (!NT_SUCCESS(PsLookupProcessByProcessId(UlongToHandle(dwProcessId), &Process)))
1543       {
1544          EngSetLastError(ERROR_INVALID_PARAMETER);
1545          return FALSE;
1546       }
1547       ppi = PsGetProcessWin32Process(Process);
1548       if (!ppi)
1549       {
1550          ObDereferenceObject(Process);
1551          return FALSE;
1552       }
1553    }
1554    ppiCur = PsGetCurrentProcessWin32Process();
1555    if (!CanForceFG(ppiCur))
1556    {
1557       if (Process) ObDereferenceObject(Process);
1558       EngSetLastError(ERROR_ACCESS_DENIED);
1559       return FALSE;
1560    }
1561    if (dwProcessId == ASFW_ANY)
1562    {  // All processes will be enabled to set the foreground window.
1563       //ERR("ptiLastInput is CLEARED!!\n");
1564       ptiLastInput = NULL;
1565    }
1566    else
1567    {  // Rule #3, last input event in force.
1568       ERR("ptiLastInput is SET!!\n");
1569       //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030.
1570       ObDereferenceObject(Process);
1571    }
1572    return TRUE;
1573 }
1574 
1575 /*
1576  * @implemented
1577  */
1578 HWND APIENTRY
1579 NtUserGetForegroundWindow(VOID)
1580 {
1581    DECLARE_RETURN(HWND);
1582 
1583    TRACE("Enter NtUserGetForegroundWindow\n");
1584    UserEnterExclusive();
1585 
1586    RETURN( UserGetForegroundWindow());
1587 
1588 CLEANUP:
1589    TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_);
1590    UserLeave();
1591    END_CLEANUP;
1592 }
1593 
1594 HWND APIENTRY
1595 NtUserSetActiveWindow(HWND hWnd)
1596 {
1597    USER_REFERENCE_ENTRY Ref;
1598    HWND hWndPrev;
1599    PWND Window;
1600    DECLARE_RETURN(HWND);
1601 
1602    TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd);
1603    UserEnterExclusive();
1604 
1605    Window = NULL;
1606    if (hWnd)
1607    {
1608       if (!(Window = UserGetWindowObject(hWnd)))
1609       {
1610          ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd);
1611          RETURN( NULL);
1612       }
1613    }
1614 
1615    if (!Window ||
1616         Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
1617    {
1618       hWndPrev = gptiCurrent->MessageQueue->spwndActive ? UserHMGetHandle(gptiCurrent->MessageQueue->spwndActive) : NULL;
1619       if (Window) UserRefObjectCo(Window, &Ref);
1620       UserSetActiveWindow(Window);
1621       if (Window) UserDerefObjectCo(Window);
1622       RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
1623    }
1624    RETURN( NULL);
1625 
1626 CLEANUP:
1627    TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_);
1628    UserLeave();
1629    END_CLEANUP;
1630 }
1631 
1632 /*
1633  * @implemented
1634  */
1635 HWND APIENTRY
1636 NtUserSetCapture(HWND hWnd)
1637 {
1638    DECLARE_RETURN(HWND);
1639 
1640    TRACE("Enter NtUserSetCapture(%p)\n", hWnd);
1641    UserEnterExclusive();
1642 
1643    RETURN( co_UserSetCapture(hWnd));
1644 
1645 CLEANUP:
1646    TRACE("Leave NtUserSetCapture, ret=%p\n", _ret_);
1647    UserLeave();
1648    END_CLEANUP;
1649 }
1650 
1651 /*
1652  * @implemented
1653  */
1654 HWND APIENTRY
1655 NtUserSetFocus(HWND hWnd)
1656 {
1657    PWND Window;
1658    USER_REFERENCE_ENTRY Ref;
1659    DECLARE_RETURN(HWND);
1660    HWND ret;
1661 
1662    TRACE("Enter NtUserSetFocus(%p)\n", hWnd);
1663    UserEnterExclusive();
1664 
1665    if (hWnd)
1666    {
1667       if (!(Window = UserGetWindowObject(hWnd)))
1668       {
1669          ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd);
1670          RETURN(NULL);
1671       }
1672 
1673       UserRefObjectCo(Window, &Ref);
1674       ret = co_UserSetFocus(Window);
1675       UserDerefObjectCo(Window);
1676 
1677       RETURN(ret);
1678    }
1679    else
1680    {
1681       RETURN( co_UserSetFocus(0));
1682    }
1683 
1684 CLEANUP:
1685    TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_);
1686    UserLeave();
1687    END_CLEANUP;
1688 }
1689 
1690 /* EOF */
1691