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