2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Focus functions
5 * FILE: subsystems/win32/win32k/ntuser/focus.c
6 * PROGRAMER: ReactOS Team
10 DBG_DEFAULT_CHANNEL(UserFocus
);
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
;
20 Check locking of a process or one or more menus are active.
25 return (gppiLockSFW
|| guSFWLockCount
);
29 IntGetCaptureWindow(VOID
)
31 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
32 return ( ForegroundQueue
? (ForegroundQueue
->spwndCapture
? UserHMGetHandle(ForegroundQueue
->spwndCapture
) : 0) : 0);
36 IntGetThreadFocusWindow(VOID
)
39 PUSER_MESSAGE_QUEUE ThreadQueue
;
41 pti
= PsGetCurrentThreadWin32Thread();
42 ThreadQueue
= pti
->MessageQueue
;
45 return ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
49 co_IntSendDeactivateMessages(HWND hWndPrev
, HWND hWnd
)
51 USER_REFERENCE_ENTRY RefPrev
;
55 if (hWndPrev
&& (WndPrev
= ValidateHwndNoErr(hWndPrev
)))
57 UserRefObjectCo(WndPrev
, &RefPrev
);
59 if (co_IntSendMessageNoWait(hWndPrev
, WM_NCACTIVATE
, FALSE
, 0)) //(LPARAM)hWnd))
61 co_IntSendMessageNoWait(hWndPrev
, WM_ACTIVATE
,
62 MAKEWPARAM(WA_INACTIVE
, WndPrev
->style
& WS_MINIMIZE
),
66 WndPrev
->state
&= ~WNDS_ACTIVEFRAME
;
70 ERR("Application is keeping itself Active to prevent the change!\n");
74 UserDerefObjectCo(WndPrev
);
80 co_IntMakeWindowActive(PWND Window
)
83 if (VerifyWnd(Window
))
84 { // Set last active for window and it's owner.
86 while (spwndOwner
->spwndOwner
)
88 spwndOwner
= spwndOwner
->spwndOwner
;
90 spwndOwner
->spwndLastActive
= Window
;
93 ERR("MakeWindowActive Failed!\n");
98 co_IntSendActivateMessages(PWND WindowPrev
, PWND Window
, BOOL MouseActivate
, BOOL Async
)
100 USER_REFERENCE_ENTRY Ref
, RefPrev
;
101 HANDLE OldTID
, NewTID
;
102 PTHREADINFO pti
, ptiOld
, ptiNew
;
107 pti
= PsGetCurrentThreadWin32Thread();
109 UserRefObjectCo(Window
, &Ref
);
111 if (WindowPrev
) UserRefObjectCo(WindowPrev
, &RefPrev
);
113 /* Send palette messages */
114 if (gpsi
->PUSIFlags
& PUSIF_PALETTEDISPLAY
&&
115 co_IntPostOrSendMessage(UserHMGetHandle(Window
), WM_QUERYNEWPALETTE
, 0, 0))
117 UserSendNotifyMessage( HWND_BROADCAST
,
118 WM_PALETTEISCHANGING
,
119 (WPARAM
)UserHMGetHandle(Window
),
123 if (!(Window
->style
& WS_CHILD
))
125 PWND pwndTemp
= co_GetDesktopWindow(Window
)->spwndChild
;
127 while (pwndTemp
&& !(pwndTemp
->style
& WS_VISIBLE
)) pwndTemp
= pwndTemp
->spwndNext
;
129 if (Window
!= pwndTemp
|| (WindowPrev
&& !IntIsWindowVisible(WindowPrev
)))
131 if (!Async
|| pti
->MessageQueue
== gpqForeground
)
133 UINT flags
= SWP_NOSIZE
| SWP_NOMOVE
;
134 if (Window
== pwndTemp
) flags
|= SWP_NOACTIVATE
;
135 //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground);
136 co_WinPosSetWindowPos(Window
, HWND_TOP
, 0, 0, 0, 0, flags
);
141 OldTID
= WindowPrev
? IntGetWndThreadId(WindowPrev
) : NULL
;
142 NewTID
= IntGetWndThreadId(Window
);
143 ptiOld
= WindowPrev
? WindowPrev
->head
.pti
: NULL
;
144 ptiNew
= Window
->head
.pti
;
146 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
148 if (!(pti
->TIF_flags
& TIF_INACTIVATEAPPMSG
) &&
149 (!WindowPrev
|| OldTID
!= NewTID
) )
154 List
= IntWinListChildren(UserGetDesktopWindow());
159 ptiOld
->TIF_flags
|= TIF_INACTIVATEAPPMSG
;
160 // Note: Do not set pci flags, this does crash!
161 for (phWnd
= List
; *phWnd
; ++phWnd
)
163 cWindow
= ValidateHwndNoErr(*phWnd
);
164 if (cWindow
&& cWindow
->head
.pti
== ptiOld
)
165 { // FALSE if the window is being deactivated,
166 // ThreadId that owns the window being activated.
167 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, FALSE
, (LPARAM
)NewTID
);
170 ptiOld
->TIF_flags
&= ~TIF_INACTIVATEAPPMSG
;
173 { //// Prevents a resource crash due to reentrance!
175 pti
->TIF_flags
|= TIF_INACTIVATEAPPMSG
;
177 for (phWnd
= List
; *phWnd
; ++phWnd
)
179 cWindow
= ValidateHwndNoErr(*phWnd
);
180 if (cWindow
&& cWindow
->head
.pti
== ptiNew
)
181 { // TRUE if the window is being activated,
182 // ThreadId that owns the window being deactivated.
183 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, TRUE
, (LPARAM
)OldTID
);
187 ExFreePool(List
);//ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
191 UserDerefObjectCo(WindowPrev
); // Now allow the previous window to die.
193 if (Window
->state
& WNDS_ACTIVEFRAME
)
194 { // If already active frame do not allow NCPaint.
195 //ERR("SendActivateMessage Is Active Frame!\n");
196 Window
->state
|= WNDS_NONCPAINT
;
199 if (Window
->style
& WS_MINIMIZE
)
201 TRACE("Widow was minimized\n");
204 co_IntMakeWindowActive(Window
);
206 /* FIXME: IntIsWindow */
208 co_IntSendMessageNoWait( UserHMGetHandle(Window
),
210 (WPARAM
)(Window
== (gpqForeground
? gpqForeground
->spwndActive
: NULL
)),
211 0); //(LPARAM)hWndPrev);
213 co_IntSendMessageNoWait( UserHMGetHandle(Window
),
215 MAKEWPARAM(MouseActivate
? WA_CLICKACTIVE
: WA_ACTIVE
, Window
->style
& WS_MINIMIZE
),
216 (LPARAM
)(WindowPrev
? UserHMGetHandle(WindowPrev
) : 0));
218 if (!Window
->spwndOwner
&& !IntGetParent(Window
))
220 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
221 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED
, (WPARAM
) UserHMGetHandle(Window
), FALSE
);
224 Window
->state
&= ~WNDS_NONCPAINT
;
226 UserDerefObjectCo(Window
);
232 IntSendFocusMessages( PTHREADINFO pti
, PWND pWnd
)
235 PUSER_MESSAGE_QUEUE ThreadQueue
= pti
->MessageQueue
; // Queue can change...
237 ThreadQueue
->QF_flags
&= ~QF_FOCUSNULLSINCEACTIVE
;
238 if (!pWnd
&& ThreadQueue
->spwndActive
)
240 ThreadQueue
->QF_flags
|= QF_FOCUSNULLSINCEACTIVE
;
243 pWndPrev
= ThreadQueue
->spwndFocus
;
245 /* check if the specified window can be set in the input data of a given queue */
246 if (!pWnd
|| ThreadQueue
== pWnd
->head
.pti
->MessageQueue
)
247 /* set the current thread focus window */
248 ThreadQueue
->spwndFocus
= pWnd
;
254 co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev
), WM_KILLFOCUS
, (WPARAM
)UserHMGetHandle(pWnd
), 0);
256 if (ThreadQueue
->spwndFocus
== pWnd
)
258 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
259 co_IntPostOrSendMessage(UserHMGetHandle(pWnd
), WM_SETFOCUS
, (WPARAM
)(pWndPrev
? UserHMGetHandle(pWndPrev
) : NULL
), 0);
266 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
267 co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev
), WM_KILLFOCUS
, 0, 0);
273 IntFindChildWindowToOwner(PWND Root
, PWND Owner
)
276 PWND Child
, OwnerWnd
;
278 for(Child
= Root
->spwndChild
; Child
; Child
= Child
->spwndNext
)
280 OwnerWnd
= Child
->spwndOwner
;
284 if(OwnerWnd
== Owner
)
295 FindRemoveAsyncMsg(PWND Wnd
, WPARAM wParam
)
298 PUSER_SENT_MESSAGE Message
;
305 if (!IsListEmpty(&pti
->SentMessagesListHead
))
307 // Scan sent queue messages to see if we received async messages.
308 Entry
= pti
->SentMessagesListHead
.Flink
;
309 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
312 if (IsListEmpty(Entry
)) return;
313 if (!Message
) return;
314 Entry
= Message
->ListEntry
.Flink
;
316 if (Message
->Msg
.message
== WM_ASYNC_SETACTIVEWINDOW
&&
317 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
) &&
318 Message
->Msg
.wParam
== wParam
)
320 ERR("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message
->Msg
.hwnd
,!!wParam
);
321 RemoveEntryList(&Message
->ListEntry
); // Purge the entry.
322 ExFreePoolWithTag(Message
, TAG_USRMSG
);
324 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
326 while (Entry
!= &pti
->SentMessagesListHead
);
331 ToggleFGActivate(PTHREADINFO pti
)
334 PPROCESSINFO ppi
= pti
->ppi
;
336 Ret
= !!(pti
->TIF_flags
& TIF_ALLOWFOREGROUNDACTIVATE
);
339 pti
->TIF_flags
&= ~TIF_ALLOWFOREGROUNDACTIVATE
;
342 Ret
= !!(ppi
->W32PF_flags
& W32PF_ALLOWFOREGROUNDACTIVATE
);
345 ppi
->W32PF_flags
&= ~W32PF_ALLOWFOREGROUNDACTIVATE
;
346 //ERR("ToggleFGActivate is %d\n",Ret);
351 IsAllowedFGActive(PTHREADINFO pti
, PWND Wnd
)
353 // Not allowed if one or more,,
354 if (!ToggleFGActivate(pti
) || // bits not set,
355 pti
->rpdesk
!= gpdeskInputDesktop
|| // not current Desktop,
356 pti
->MessageQueue
== gpqForeground
|| // if already the queue foreground,
357 IsFGLocked() || // foreground is locked,
358 Wnd
->ExStyle
& WS_EX_NOACTIVATE
) // or,,, does not become the foreground window when the user clicks it.
362 //ERR("IsAllowedFGActive is TRUE\n");
367 Can the system force foreground from one or more conditions.
370 CanForceFG(PPROCESSINFO ppi
)
373 ptiLastInput
->ppi
== ppi
||
375 gptiForeground
->ppi
== ppi
||
376 ppi
->W32PF_flags
& (W32PF_ALLOWFOREGROUNDACTIVATE
| W32PF_SETFOREGROUNDALLOWED
) ||
377 gppiInputProvider
== ppi
||
380 //ERR("CanForceFG is FALSE\n");
386 The system restricts which processes can set the foreground window. A process
387 can set the foreground window only if one of the following conditions is true:
389 * The process is the foreground process.
390 * The process was started by the foreground process.
391 * The process received the last input event.
392 * There is no foreground process.
393 * The foreground process is being debugged.
394 * The foreground is not locked (see LockSetForegroundWindow).
395 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
396 * No menus are active.
400 co_IntSetForegroundAndFocusWindow(
402 _In_ BOOL MouseActivate
)
404 HWND hWnd
= Wnd
? UserHMGetHandle(Wnd
) : NULL
;
405 HWND hWndPrev
= NULL
;
406 PWND pWndPrev
= NULL
;
407 PUSER_MESSAGE_QUEUE PrevForegroundQueue
;
409 BOOL fgRet
= FALSE
, Ret
= FALSE
;
411 if (Wnd
) ASSERT_REFS_CO(Wnd
);
413 //ERR("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
415 PrevForegroundQueue
= IntGetFocusMessageQueue(); // Use this active desktop.
416 pti
= PsGetCurrentThreadWin32Thread();
418 if (PrevForegroundQueue
)
419 { // Same Window Q as foreground just do active.
420 if (Wnd
&& Wnd
->head
.pti
->MessageQueue
== PrevForegroundQueue
)
422 //ERR("Same Window Q as foreground just do active.\n");
423 if (pti
->MessageQueue
== PrevForegroundQueue
)
424 { // Same WQ and TQ go active.
425 //ERR("Same WQ and TQ go active.\n");
426 Ret
= co_IntSetActiveWindow(Wnd
, MouseActivate
, TRUE
, FALSE
);
428 else if (Wnd
->head
.pti
->MessageQueue
->spwndActive
== Wnd
)
429 { // Same WQ and it is active.
430 //ERR("Same WQ and it is active.\n");
434 { // Same WQ as FG but not the same TQ send active.
435 //ERR("Same WQ as FG but not the same TQ send active.\n");
436 co_IntSendMessage(hWnd
, WM_ASYNC_SETACTIVEWINDOW
, (WPARAM
)Wnd
, (LPARAM
)MouseActivate
);
442 hWndPrev
= PrevForegroundQueue
->spwndActive
? UserHMGetHandle(PrevForegroundQueue
->spwndActive
) : 0;
443 pWndPrev
= PrevForegroundQueue
->spwndActive
;
446 if ( (( !IsFGLocked() || pti
->ppi
== gppiInputProvider
) &&
447 ( CanForceFG(pti
->ppi
) || pti
->TIF_flags
& (TIF_SYSTEMTHREAD
|TIF_CSRSSTHREAD
|TIF_ALLOWFOREGROUNDACTIVATE
) )) ||
448 pti
->ppi
== ppiScrnSaver
452 //ToggleFGActivate(pti); // win.c line 2662 fail
455 IntSetFocusMessageQueue(Wnd
->head
.pti
->MessageQueue
);
456 gptiForeground
= Wnd
->head
.pti
;
457 //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
461 IntSetFocusMessageQueue(NULL
);
462 gptiForeground
= NULL
;
463 //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
467 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
468 other thread after we already changed the foreground window back to our own
472 FindRemoveAsyncMsg(Wnd
, 0); // Do this to fix test_SFW todos!
477 // Fix FG Bounce with regedit.
478 if (hWndPrev
!= hWnd
)
480 if (PrevForegroundQueue
&&
482 PrevForegroundQueue
->spwndActive
)
484 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
485 if (pti
->MessageQueue
== PrevForegroundQueue
)
487 //ERR("SFGW: TI same as Prev TI\n");
488 co_IntSetActiveWindow(NULL
, FALSE
, TRUE
, FALSE
);
492 //ERR("SFGW Deactivate: TI not same as Prev TI\n");
493 // No real reason to wait here.
494 co_IntSendMessageNoWait(hWndPrev
, WM_ASYNC_SETACTIVEWINDOW
, 0, 0 );
499 if (!Wnd
) return FALSE
; // Always return false.
501 if (pti
->MessageQueue
== Wnd
->head
.pti
->MessageQueue
)
503 //ERR("Same PQ and WQ go active.\n");
504 Ret
= co_IntSetActiveWindow(Wnd
, MouseActivate
, TRUE
, FALSE
);
506 else if (Wnd
->head
.pti
->MessageQueue
->spwndActive
== Wnd
)
508 //ERR("Same Active and Wnd.\n");
513 //ERR("Activate Not same PQ and WQ and Wnd.\n");
514 co_IntSendMessageNoWait(hWnd
, WM_ASYNC_SETACTIVEWINDOW
, (WPARAM
)Wnd
, (LPARAM
)MouseActivate
);
521 co_IntMouseActivateWindow(PWND Wnd
)
525 USER_REFERENCE_ENTRY Ref
;
529 if (Wnd
->style
& WS_DISABLED
)
533 PWND DesktopWindow
= UserGetDesktopWindow();
536 Top
= IntFindChildWindowToOwner(DesktopWindow
, Wnd
);
537 if ((TopWnd
= ValidateHwndNoErr(Top
)))
539 UserRefObjectCo(TopWnd
, &Ref
);
540 Ret
= co_IntMouseActivateWindow(TopWnd
);
541 UserDerefObjectCo(TopWnd
);
549 TopWindow
= UserGetAncestor(Wnd
, GA_ROOT
);
550 //if (TopWindow) {ERR("MAW 2 pWnd %p hWnd %p\n",TopWindow,TopWindow->head.h);}
551 if (!TopWindow
) return FALSE
;
553 /* TMN: Check return value from this function? */
554 UserRefObjectCo(TopWindow
, &Ref
);
555 co_IntSetForegroundAndFocusWindow(TopWindow
, TRUE
);
556 UserDerefObjectCo(TopWindow
);
561 co_IntSetActiveWindow(PWND Wnd OPTIONAL
, BOOL bMouse
, BOOL bFocus
, BOOL Async
)
564 PUSER_MESSAGE_QUEUE ThreadQueue
;
565 PWND pWndChg
, WndPrev
; // State changes.
569 CBTACTIVATESTRUCT cbt
;
570 //ERR("co_IntSetActiveWindow 1\n");
574 hWnd
= UserHMGetHandle(Wnd
);
575 if ((Wnd
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
576 if (Wnd
== UserGetDesktopWindow()) return FALSE
;
577 //ERR("co_IntSetActiveWindow 1a hWnd 0x%p\n",hWnd);
580 //ERR("co_IntSetActiveWindow 2\n");
581 pti
= PsGetCurrentThreadWin32Thread();
582 ThreadQueue
= pti
->MessageQueue
;
583 ASSERT(ThreadQueue
!= 0);
585 hWndPrev
= ThreadQueue
->spwndActive
? UserHMGetHandle(ThreadQueue
->spwndActive
) : NULL
;
587 pWndChg
= ThreadQueue
->spwndActive
; // Keep to notify of a preemptive switch.
591 BOOL Ret
, DoFG
, AllowFG
;
593 if (Wnd
->state
& WNDS_BEINGACTIVATED
) return TRUE
;
595 if (ThreadQueue
== Wnd
->head
.pti
->MessageQueue
)
597 if (IsAllowedFGActive(pti
, Wnd
))
603 //ERR("co_IntSetActiveWindow 3 Go Out!\n");
606 AllowFG
= !pti
->cVisWindows
; // Nothing is visable.
607 //ERR("co_IntSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
609 else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
611 //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
612 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
613 //if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
614 if (!gpqForeground
|| gpqForeground
== ThreadQueue
)
622 if (pti
->TIF_flags
& TIF_ALLOWFOREGROUNDACTIVATE
|| pti
->cVisWindows
)
629 //ERR("co_IntSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
634 pti
->TIF_flags
|= TIF_ALLOWFOREGROUNDACTIVATE
;
635 //ERR("co_IntSetActiveWindow 3c FG set\n");
636 Ret
= co_IntSetForegroundAndFocusWindow(Wnd
, bMouse
);
639 pti
->TIF_flags
|= TIF_ALLOWFOREGROUNDACTIVATE
;
643 pti
->TIF_flags
&= ~TIF_ALLOWFOREGROUNDACTIVATE
;
649 /* Call CBT hook chain */
651 cbt
.hWndActive
= hWndPrev
;
652 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
654 ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
658 if ( ThreadQueue
->spwndActive
&& ThreadQueue
->spwndActive
->state
& WNDS_DESTROYED
)
659 ThreadQueue
->spwndActive
= NULL
;
661 ThreadQueue
->spwndActivePrev
= ThreadQueue
->spwndActive
;
663 WndPrev
= ThreadQueue
->spwndActive
; // Keep to save changing active.
667 if (ThreadQueue
== gpqForeground
) gpqForegroundPrev
= ThreadQueue
;
668 if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev
), hWnd
)) return FALSE
;
671 WndPrev
= ThreadQueue
->spwndActive
; // Again keep to save changing active.
673 // While in calling message proc or hook:
674 // Fail if a preemptive switch was made, current active not made previous,
675 // focus window is dead or no longer the same thread queue.
676 if ( ThreadQueue
->spwndActivePrev
!= ThreadQueue
->spwndActive
||
677 pWndChg
!= WndPrev
||
678 (Wnd
&& !VerifyWnd(Wnd
)) ||
679 ThreadQueue
!= pti
->MessageQueue
)
681 ERR("SetActiveWindow: Summery ERROR, active state changed!\n");
685 if (!WndPrev
) ThreadQueue
->QF_flags
&= ~QF_FOCUSNULLSINCEACTIVE
;
687 if (Wnd
) Wnd
->state
|= WNDS_BEINGACTIVATED
;
689 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND
, Wnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
690 //// Breaks Atl-Esc/Tab via User32.
691 ////FindRemoveAsyncMsg(Wnd,(WPARAM)Wnd); // Clear out activate ASYNC messages.
693 /* check if the specified window can be set in the input data of a given queue */
694 if ( !Wnd
|| ThreadQueue
== Wnd
->head
.pti
->MessageQueue
)
696 /* set the current thread active window */
697 ThreadQueue
->spwndActive
= Wnd
;
700 WndPrev
= VerifyWnd(ThreadQueue
->spwndActivePrev
); // Now should be set but verify it again.
702 InAAPM
= co_IntSendActivateMessages(WndPrev
, Wnd
, bMouse
, Async
);
704 /* now change focus if necessary */
705 if (bFocus
&& !(ThreadQueue
->QF_flags
& QF_FOCUSNULLSINCEACTIVE
))
707 /* Do not change focus if the window is no longer active */
708 if (ThreadQueue
->spwndActive
== Wnd
)
710 if (!ThreadQueue
->spwndFocus
||
712 UserGetAncestor(ThreadQueue
->spwndFocus
, GA_ROOT
) != Wnd
)
714 co_UserSetFocus(Wnd
);
721 pti
->TIF_flags
&= ~TIF_INACTIVATEAPPMSG
;
724 // FIXME: Used in the menu loop!!!
725 //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
727 //ERR("co_IntSetActiveWindow Exit\n");
728 if (Wnd
) Wnd
->state
&= ~WNDS_BEINGACTIVATED
;
729 return (ThreadQueue
->spwndActive
== Wnd
);
733 UserSetActiveWindow(PWND Wnd
)
735 if (Wnd
) // Must have a window!
737 if ((Wnd
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
739 return co_IntSetActiveWindow(Wnd
, FALSE
, TRUE
, FALSE
);
742 Yes your eye are not deceiving you~!
744 First part of wines Win.c test_SetActiveWindow:
746 flush_events( TRUE );
747 ShowWindow(hwnd, SW_HIDE);
750 check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
757 co_UserSetFocus(PWND Window
)
762 PUSER_MESSAGE_QUEUE ThreadQueue
;
765 ASSERT_REFS_CO(Window
);
767 pti
= PsGetCurrentThreadWin32Thread();
768 ThreadQueue
= pti
->MessageQueue
;
769 ASSERT(ThreadQueue
!= 0);
771 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window
? UserHMGetHandle(Window
) : 0, pti
);
773 hWndPrev
= ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
777 if (hWndPrev
== UserHMGetHandle(Window
))
779 return hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0; /* Nothing to do */
782 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
784 ERR("SetFocus Must have the same Q!\n");
788 /* Check if we can set the focus to this window */
789 for (pwndTop
= Window
; pwndTop
!= NULL
; pwndTop
= pwndTop
->spwndParent
)
791 if (pwndTop
->style
& (WS_MINIMIZED
|WS_DISABLED
)) return 0;
792 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
795 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)Window
->head
.h
, (LPARAM
)hWndPrev
))
797 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
801 /* Activate pwndTop if needed. */
802 if (pwndTop
!= ThreadQueue
->spwndActive
)
804 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue(); // Keep it based on desktop.
805 if (ThreadQueue
!= ForegroundQueue
&& IsAllowedFGActive(pti
, pwndTop
)) // Rule 2 & 3.
807 //ERR("SetFocus: Set Foreground!\n");
808 if (!(pwndTop
->style
& WS_VISIBLE
))
810 pti
->ppi
->W32PF_flags
|= W32PF_ALLOWFOREGROUNDACTIVATE
;
812 if (!co_IntSetForegroundAndFocusWindow(pwndTop
, FALSE
))
814 ERR("SetFocus: Set Foreground and Focus Failed!\n");
819 /* Set Active when it is needed. */
820 if (pwndTop
!= ThreadQueue
->spwndActive
)
822 //ERR("SetFocus: Set Active!\n");
823 if (!co_IntSetActiveWindow(pwndTop
, FALSE
, FALSE
, FALSE
))
825 ERR("SetFocus: Set Active Failed!\n");
830 /* Abort if window destroyed */
831 if (Window
->state2
& WNDS2_INDESTROY
) return 0;
832 /* Do not change focus if the window is no longer active */
833 if (pwndTop
!= ThreadQueue
->spwndActive
)
835 ERR("SetFocus: Top window did not go active!\n");
840 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
841 hWndPrev
= ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
843 IntSendFocusMessages( pti
, Window
);
845 TRACE("Focus: %p -> %p\n", hWndPrev
, Window
->head
.h
);
847 else /* NULL hwnd passed in */
849 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)0, (LPARAM
)hWndPrev
))
851 ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
855 /* set the current thread focus window null */
856 IntSendFocusMessages( pti
, NULL
);
858 return hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0;
862 UserGetForegroundWindow(VOID
)
864 PUSER_MESSAGE_QUEUE ForegroundQueue
;
866 ForegroundQueue
= IntGetFocusMessageQueue();
867 return( ForegroundQueue
? (ForegroundQueue
->spwndActive
? UserHMGetHandle(ForegroundQueue
->spwndActive
) : 0) : 0);
870 HWND FASTCALL
UserGetActiveWindow(VOID
)
873 PUSER_MESSAGE_QUEUE ThreadQueue
;
875 pti
= PsGetCurrentThreadWin32Thread();
876 ThreadQueue
= pti
->MessageQueue
;
877 return( ThreadQueue
? (ThreadQueue
->spwndActive
? UserHMGetHandle(ThreadQueue
->spwndActive
) : 0) : 0);
884 PUSER_MESSAGE_QUEUE ThreadQueue
;
885 DECLARE_RETURN(HWND
);
887 TRACE("Enter IntGetCapture\n");
889 pti
= PsGetCurrentThreadWin32Thread();
890 ThreadQueue
= pti
->MessageQueue
;
891 RETURN( ThreadQueue
? (ThreadQueue
->spwndCapture
? UserHMGetHandle(ThreadQueue
->spwndCapture
) : 0) : 0);
894 TRACE("Leave IntGetCapture, ret=%p\n", _ret_
);
899 co_UserSetCapture(HWND hWnd
)
902 PUSER_MESSAGE_QUEUE ThreadQueue
;
903 PWND pWnd
, Window
= NULL
;
906 pti
= PsGetCurrentThreadWin32Thread();
907 ThreadQueue
= pti
->MessageQueue
;
909 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
)
912 if (hWnd
&& (Window
= UserGetWindowObject(hWnd
)))
914 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
920 hWndPrev
= MsqSetStateWindow(pti
, MSQ_STATE_CAPTURE
, hWnd
);
924 pWnd
= UserGetWindowObject(hWndPrev
);
926 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
930 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART
, Window
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
932 if (hWndPrev
&& hWndPrev
!= hWnd
)
934 if (ThreadQueue
->MenuOwner
&& Window
) ThreadQueue
->QF_flags
|= QF_CAPTURELOCKED
;
936 co_IntPostOrSendMessage(hWndPrev
, WM_CAPTURECHANGED
, 0, (LPARAM
)hWnd
);
938 ThreadQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
941 ThreadQueue
->spwndCapture
= Window
;
943 if (hWnd
== NULL
) // Release mode.
947 /* Also remove other windows if not capturing anymore */
948 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
949 MsqSetStateWindow(pti
, MSQ_STATE_MOVESIZE
, NULL
);
951 /* Somebody may have missed some mouse movements */
955 mi
.dwFlags
= MOUSEEVENTF_MOVE
;
958 UserSendMouseInput(&mi
, FALSE
);
968 IntReleaseCapture(VOID
)
971 PUSER_MESSAGE_QUEUE ThreadQueue
;
973 pti
= PsGetCurrentThreadWin32Thread();
974 ThreadQueue
= pti
->MessageQueue
;
976 // Can not release inside WM_CAPTURECHANGED!!
977 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
) return FALSE
;
979 co_UserSetCapture(NULL
);
988 co_IntSetForegroundWindow(PWND Window
)
990 if (Window
) ASSERT_REFS_CO(Window
);
992 return co_IntSetForegroundAndFocusWindow(Window
, FALSE
);
999 co_IntSetForegroundWindowMouse(PWND Window
)
1001 if (Window
) ASSERT_REFS_CO(Window
);
1003 return co_IntSetForegroundAndFocusWindow(Window
, TRUE
);
1010 IntLockSetForegroundWindow(UINT uLockCode
)
1012 ULONG Err
= ERROR_ACCESS_DENIED
;
1013 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
1017 if ( CanForceFG(ppi
) && !gppiLockSFW
)
1024 if ( gppiLockSFW
== ppi
)
1031 Err
= ERROR_INVALID_PARAMETER
;
1033 EngSetLastError(Err
);
1041 IntAllowSetForegroundWindow(DWORD dwProcessId
)
1043 PPROCESSINFO ppi
, ppiCur
;
1044 PEPROCESS Process
= NULL
;
1047 if (dwProcessId
!= ASFW_ANY
)
1049 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)dwProcessId
, &Process
)))
1051 EngSetLastError(ERROR_INVALID_PARAMETER
);
1054 ppi
= PsGetProcessWin32Process(Process
);
1057 ObDereferenceObject(Process
);
1061 ppiCur
= PsGetCurrentProcessWin32Process();
1062 if (!CanForceFG(ppiCur
))
1064 if (Process
) ObDereferenceObject(Process
);
1065 EngSetLastError(ERROR_ACCESS_DENIED
);
1068 if (dwProcessId
== ASFW_ANY
)
1069 { // All processes will be enabled to set the foreground window.
1070 //ERR("ptiLastInput is CLEARED!!\n");
1071 ptiLastInput
= NULL
;
1074 { // Rule #3, last input event in force.
1075 ERR("ptiLastInput is SET!!\n");
1076 //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030.
1077 ObDereferenceObject(Process
);
1086 NtUserGetForegroundWindow(VOID
)
1088 DECLARE_RETURN(HWND
);
1090 TRACE("Enter NtUserGetForegroundWindow\n");
1091 UserEnterExclusive();
1093 RETURN( UserGetForegroundWindow());
1096 TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_
);
1102 NtUserSetActiveWindow(HWND hWnd
)
1104 USER_REFERENCE_ENTRY Ref
;
1107 DECLARE_RETURN(HWND
);
1109 TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd
);
1110 UserEnterExclusive();
1115 if (!(Window
= UserGetWindowObject(hWnd
)))
1117 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd
);
1123 Window
->head
.pti
->MessageQueue
== gptiCurrent
->MessageQueue
)
1125 hWndPrev
= gptiCurrent
->MessageQueue
->spwndActive
? UserHMGetHandle(gptiCurrent
->MessageQueue
->spwndActive
) : NULL
;
1126 if (Window
) UserRefObjectCo(Window
, &Ref
);
1127 UserSetActiveWindow(Window
);
1128 if (Window
) UserDerefObjectCo(Window
);
1129 RETURN( hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0 );
1134 TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_
);
1143 NtUserSetCapture(HWND hWnd
)
1145 DECLARE_RETURN(HWND
);
1147 TRACE("Enter NtUserSetCapture(%p)\n", hWnd
);
1148 UserEnterExclusive();
1150 RETURN( co_UserSetCapture(hWnd
));
1153 TRACE("Leave NtUserSetCapture, ret=%p\n", _ret_
);
1162 NtUserSetFocus(HWND hWnd
)
1165 USER_REFERENCE_ENTRY Ref
;
1166 DECLARE_RETURN(HWND
);
1169 TRACE("Enter NtUserSetFocus(%p)\n", hWnd
);
1170 UserEnterExclusive();
1174 if (!(Window
= UserGetWindowObject(hWnd
)))
1176 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd
);
1180 UserRefObjectCo(Window
, &Ref
);
1181 ret
= co_UserSetFocus(Window
);
1182 UserDerefObjectCo(Window
);
1188 RETURN( co_UserSetFocus(0));
1192 TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_
);