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