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