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
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 Get capture window via foreground Queue.
32 IntGetCaptureWindow(VOID
)
34 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
35 return ( ForegroundQueue
? (ForegroundQueue
->spwndCapture
? UserHMGetHandle(ForegroundQueue
->spwndCapture
) : 0) : 0);
39 IntGetThreadFocusWindow(VOID
)
42 PUSER_MESSAGE_QUEUE ThreadQueue
;
44 pti
= PsGetCurrentThreadWin32Thread();
45 ThreadQueue
= pti
->MessageQueue
;
48 return ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
52 co_IntSendDeactivateMessages(HWND hWndPrev
, HWND hWnd
)
54 USER_REFERENCE_ENTRY RefPrev
;
57 LPARAM lParam
= hWnd
? (LPARAM
)hWnd
: 0;
59 if (hWndPrev
&& (WndPrev
= ValidateHwndNoErr(hWndPrev
)))
61 UserRefObjectCo(WndPrev
, &RefPrev
);
63 if (co_IntSendMessage(hWndPrev
, WM_NCACTIVATE
, FALSE
, lParam
))
65 co_IntSendMessage(hWndPrev
, WM_ACTIVATE
,
66 MAKEWPARAM(WA_INACTIVE
, (WndPrev
->style
& WS_MINIMIZE
) != 0),
70 WndPrev
->state
&= ~(WNDS_ACTIVEFRAME
|WNDS_HASCAPTION
);
74 ERR("Application is keeping itself Active to prevent the change!\n");
78 UserDerefObjectCo(WndPrev
);
84 co_IntMakeWindowActive(PWND Window
)
87 if (VerifyWnd(Window
))
88 { // Set last active for window and it's owner.
90 while (spwndOwner
->spwndOwner
)
92 spwndOwner
= spwndOwner
->spwndOwner
;
94 spwndOwner
->spwndLastActive
= Window
;
97 ERR("MakeWindowActive Failed!\n");
102 co_IntSendActivateMessages(PWND WindowPrev
, PWND Window
, BOOL MouseActivate
, BOOL Async
)
104 USER_REFERENCE_ENTRY Ref
, RefPrev
;
105 HANDLE OldTID
, NewTID
;
106 PTHREADINFO pti
, ptiOld
, ptiNew
;
109 //ERR("SendActivateMessages\n");
111 pti
= PsGetCurrentThreadWin32Thread();
115 UserRefObjectCo(Window
, &Ref
);
117 if (WindowPrev
) UserRefObjectCo(WindowPrev
, &RefPrev
);
119 /* Send palette messages */
120 if (gpsi
->PUSIFlags
& PUSIF_PALETTEDISPLAY
&&
121 //co_IntPostOrSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
122 co_IntSendMessage(UserHMGetHandle(Window
), WM_QUERYNEWPALETTE
, 0, 0))
124 UserSendNotifyMessage( HWND_BROADCAST
,
125 WM_PALETTEISCHANGING
,
126 (WPARAM
)UserHMGetHandle(Window
),
129 //// Fixes CORE-6434.
130 if (!(Window
->style
& WS_CHILD
))
132 PWND pwndTemp
= co_GetDesktopWindow(Window
)->spwndChild
;
134 while (pwndTemp
&& !(pwndTemp
->style
& WS_VISIBLE
)) pwndTemp
= pwndTemp
->spwndNext
;
136 if (Window
!= pwndTemp
|| (WindowPrev
&& !IntIsWindowVisible(WindowPrev
)))
138 if (!Async
|| pti
->MessageQueue
== gpqForeground
)
140 UINT flags
= SWP_NOSIZE
| SWP_NOMOVE
;
141 if (Window
== pwndTemp
) flags
|= SWP_NOACTIVATE
;
142 //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground);
143 co_WinPosSetWindowPos(Window
, HWND_TOP
, 0, 0, 0, 0, flags
);
148 //// CORE-1161 and CORE-6651
149 if (Window
->spwndPrev
)
151 HWND
*phwndTopLevel
, *phwndCurrent
;
152 PWND pwndCurrent
, pwndDesktop
;
154 pwndDesktop
= co_GetDesktopWindow(Window
);//UserGetDesktopWindow();
155 if (Window
->spwndParent
== pwndDesktop
)
157 phwndTopLevel
= IntWinListChildren(pwndDesktop
);
158 phwndCurrent
= phwndTopLevel
;
161 pwndCurrent
= UserGetWindowObject(*phwndCurrent
);
163 if (pwndCurrent
&& pwndCurrent
->spwndOwner
== Window
)
165 co_WinPosSetWindowPos(pwndCurrent
, HWND_TOP
, 0, 0, 0, 0, SWP_NOSIZE
|SWP_NOMOVE
|SWP_NOACTIVATE
);
169 ExFreePoolWithTag(phwndTopLevel
, USERTAG_WINDOWLIST
);
175 OldTID
= WindowPrev
? IntGetWndThreadId(WindowPrev
) : NULL
;
176 NewTID
= Window
? IntGetWndThreadId(Window
) : NULL
;
177 ptiOld
= WindowPrev
? WindowPrev
->head
.pti
: NULL
;
178 ptiNew
= Window
? Window
->head
.pti
: NULL
;
180 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
182 if (!(pti
->TIF_flags
& TIF_INACTIVATEAPPMSG
) &&
188 List
= IntWinListChildren(UserGetDesktopWindow());
193 ptiOld
->TIF_flags
|= TIF_INACTIVATEAPPMSG
;
194 // Note: Do not set pci flags, this does crash!
195 for (phWnd
= List
; *phWnd
; ++phWnd
)
197 cWindow
= ValidateHwndNoErr(*phWnd
);
198 if (cWindow
&& cWindow
->head
.pti
== ptiOld
)
199 { // FALSE if the window is being deactivated,
200 // ThreadId that owns the window being activated.
201 //ERR("SendActivateMessage Old\n");
202 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, FALSE
, (LPARAM
)NewTID
);
205 ptiOld
->TIF_flags
&= ~TIF_INACTIVATEAPPMSG
;
208 { //// Prevents a resource crash due to reentrance!
210 pti
->TIF_flags
|= TIF_INACTIVATEAPPMSG
;
212 for (phWnd
= List
; *phWnd
; ++phWnd
)
214 cWindow
= ValidateHwndNoErr(*phWnd
);
215 if (cWindow
&& cWindow
->head
.pti
== ptiNew
)
216 { // TRUE if the window is being activated,
217 // ThreadId that owns the window being deactivated.
218 //ERR("SendActivateMessage New\n");
219 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, TRUE
, (LPARAM
)OldTID
);
223 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
230 UserDerefObjectCo(WindowPrev
); // Now allow the previous window to die.
232 if (Window
->state
& WNDS_ACTIVEFRAME
)
233 { // If already active frame do not allow NCPaint.
234 //ERR("SendActivateMessage Is Active Frame!\n");
235 Window
->state
|= WNDS_NONCPAINT
;
238 if (Window
->style
& WS_MINIMIZE
)
240 TRACE("Widow was minimized\n");
243 co_IntMakeWindowActive(Window
);
245 co_IntSendMessage( UserHMGetHandle(Window
),
247 (WPARAM
)(Window
== (gpqForeground
? gpqForeground
->spwndActive
: NULL
)),
248 0); //(LPARAM)hWndPrev);
250 co_IntSendMessage( UserHMGetHandle(Window
),
252 MAKEWPARAM(MouseActivate
? WA_CLICKACTIVE
: WA_ACTIVE
, (Window
->style
& WS_MINIMIZE
) != 0),
253 (LPARAM
)(WindowPrev
? UserHMGetHandle(WindowPrev
) : 0));
255 if (Window
->spwndParent
== UserGetDesktopWindow() &&
256 Window
->spwndOwner
== NULL
&&
257 (!(Window
->ExStyle
& WS_EX_TOOLWINDOW
) ||
258 (Window
->ExStyle
& WS_EX_APPWINDOW
)))
260 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
261 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED
, (WPARAM
) UserHMGetHandle(Window
), FALSE
);
265 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED
, 0, FALSE
);
268 Window
->state
&= ~WNDS_NONCPAINT
;
270 UserDerefObjectCo(Window
);
276 IntSendFocusMessages( PTHREADINFO pti
, PWND pWnd
)
279 PUSER_MESSAGE_QUEUE ThreadQueue
= pti
->MessageQueue
; // Queue can change...
281 ThreadQueue
->QF_flags
&= ~QF_FOCUSNULLSINCEACTIVE
;
282 if (!pWnd
&& ThreadQueue
->spwndActive
)
284 ThreadQueue
->QF_flags
|= QF_FOCUSNULLSINCEACTIVE
;
287 pWndPrev
= ThreadQueue
->spwndFocus
;
289 /* check if the specified window can be set in the input data of a given queue */
290 if (!pWnd
|| ThreadQueue
== pWnd
->head
.pti
->MessageQueue
)
291 /* set the current thread focus window */
292 ThreadQueue
->spwndFocus
= pWnd
;
298 //co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0);
299 co_IntSendMessage(UserHMGetHandle(pWndPrev
), WM_KILLFOCUS
, (WPARAM
)UserHMGetHandle(pWnd
), 0);
301 if (ThreadQueue
->spwndFocus
== pWnd
)
303 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
304 //co_IntPostOrSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ? UserHMGetHandle(pWndPrev) : NULL), 0);
305 co_IntSendMessage(UserHMGetHandle(pWnd
), WM_SETFOCUS
, (WPARAM
)(pWndPrev
? UserHMGetHandle(pWndPrev
) : NULL
), 0);
312 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
313 //co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
314 co_IntSendMessage(UserHMGetHandle(pWndPrev
), WM_KILLFOCUS
, 0, 0);
320 FindRemoveAsyncMsg(PWND Wnd
, WPARAM wParam
)
323 PUSER_SENT_MESSAGE Message
;
330 Entry
= pti
->SentMessagesListHead
.Flink
;
331 while (Entry
!= &pti
->SentMessagesListHead
)
333 // Scan sent queue messages to see if we received async messages.
334 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
335 Entry
= Entry
->Flink
;
337 if (Message
->Msg
.message
== WM_ASYNC_SETACTIVEWINDOW
&&
338 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
) &&
339 Message
->Msg
.wParam
== wParam
)
341 WARN("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message
->Msg
.hwnd
, !!wParam
);
342 RemoveEntryList(&Message
->ListEntry
); // Purge the entry.
343 ClearMsgBitsMask(pti
, Message
->QS_Flags
);
344 InsertTailList(&usmList
, &Message
->ListEntry
);
345 /* Notify the sender. */
346 if (Message
->pkCompletionEvent
!= NULL
)
348 KeSetEvent(Message
->pkCompletionEvent
, IO_NO_INCREMENT
, FALSE
);
350 FreeUserMessage(Message
);
356 ToggleFGActivate(PTHREADINFO pti
)
359 PPROCESSINFO ppi
= pti
->ppi
;
361 Ret
= !!(pti
->TIF_flags
& TIF_ALLOWFOREGROUNDACTIVATE
);
364 pti
->TIF_flags
&= ~TIF_ALLOWFOREGROUNDACTIVATE
;
367 Ret
= !!(ppi
->W32PF_flags
& W32PF_ALLOWFOREGROUNDACTIVATE
);
370 ppi
->W32PF_flags
&= ~W32PF_ALLOWFOREGROUNDACTIVATE
;
371 //ERR("ToggleFGActivate is %d\n",Ret);
376 IsAllowedFGActive(PTHREADINFO pti
, PWND Wnd
)
378 // Not allowed if one or more,,
379 if (!ToggleFGActivate(pti
) || // bits not set,
380 pti
->rpdesk
!= gpdeskInputDesktop
|| // not current Desktop,
381 pti
->MessageQueue
== gpqForeground
|| // if already the queue foreground,
382 IsFGLocked() || // foreground is locked,
383 Wnd
->ExStyle
& WS_EX_NOACTIVATE
) // or,,, does not become the foreground window when the user clicks it.
387 //ERR("IsAllowedFGActive is TRUE\n");
392 Can the system force foreground from one or more conditions.
395 CanForceFG(PPROCESSINFO ppi
)
398 ptiLastInput
->ppi
== ppi
||
400 gptiForeground
->ppi
== ppi
||
401 ppi
->W32PF_flags
& (W32PF_ALLOWFOREGROUNDACTIVATE
| W32PF_SETFOREGROUNDALLOWED
) ||
402 gppiInputProvider
== ppi
||
405 //ERR("CanForceFG is FALSE\n");
411 The system restricts which processes can set the foreground window. A process
412 can set the foreground window only if one of the following conditions is true:
414 * The process is the foreground process.
415 * The process was started by the foreground process.
416 * The process received the last input event.
417 * There is no foreground process.
418 * The foreground process is being debugged.
419 * The foreground is not locked (see LockSetForegroundWindow).
420 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
421 * No menus are active.
425 co_IntSetForegroundAndFocusWindow(
427 _In_ BOOL MouseActivate
)
429 HWND hWnd
= Wnd
? UserHMGetHandle(Wnd
) : NULL
;
430 HWND hWndPrev
= NULL
;
431 PWND pWndPrev
= NULL
;
432 PUSER_MESSAGE_QUEUE PrevForegroundQueue
;
434 BOOL fgRet
= FALSE
, Ret
= FALSE
;
436 if (Wnd
) ASSERT_REFS_CO(Wnd
);
438 //ERR("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
440 PrevForegroundQueue
= IntGetFocusMessageQueue(); // Use this active desktop.
441 pti
= PsGetCurrentThreadWin32Thread();
443 if (PrevForegroundQueue
)
444 { // Same Window Q as foreground just do active.
445 if (Wnd
&& Wnd
->head
.pti
->MessageQueue
== PrevForegroundQueue
)
447 //ERR("Same Window Q as foreground just do active.\n");
448 if (pti
->MessageQueue
== PrevForegroundQueue
)
449 { // Same WQ and TQ go active.
450 //ERR("Same WQ and TQ go active.\n");
451 Ret
= co_IntSetActiveWindow(Wnd
, MouseActivate
, TRUE
, FALSE
);
453 else if (Wnd
->head
.pti
->MessageQueue
->spwndActive
== Wnd
)
454 { // Same WQ and it is active.
455 //ERR("Same WQ and it is active.\n");
459 { // Same WQ as FG but not the same TQ send active.
460 //ERR("Same WQ as FG but not the same TQ send active.\n");
461 co_IntSendMessage(hWnd
, WM_ASYNC_SETACTIVEWINDOW
, (WPARAM
)Wnd
, (LPARAM
)MouseActivate
);
467 hWndPrev
= PrevForegroundQueue
->spwndActive
? UserHMGetHandle(PrevForegroundQueue
->spwndActive
) : 0;
468 pWndPrev
= PrevForegroundQueue
->spwndActive
;
471 if ( (( !IsFGLocked() || pti
->ppi
== gppiInputProvider
) &&
472 ( CanForceFG(pti
->ppi
) || pti
->TIF_flags
& (TIF_SYSTEMTHREAD
|TIF_CSRSSTHREAD
|TIF_ALLOWFOREGROUNDACTIVATE
) )) ||
473 pti
->ppi
== ppiScrnSaver
477 //ToggleFGActivate(pti); // win.c line 2662 fail
480 IntSetFocusMessageQueue(Wnd
->head
.pti
->MessageQueue
);
481 gptiForeground
= Wnd
->head
.pti
;
482 //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
486 IntSetFocusMessageQueue(NULL
);
487 gptiForeground
= NULL
;
488 //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
492 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
493 other thread after we already changed the foreground window back to our own
497 FindRemoveAsyncMsg(Wnd
, 0); // Do this to fix test_SFW todos!
502 // Fix FG Bounce with regedit.
503 if (hWndPrev
!= hWnd
)
505 if (PrevForegroundQueue
&&
507 PrevForegroundQueue
->spwndActive
)
509 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
510 if (pti
->MessageQueue
== PrevForegroundQueue
)
512 //ERR("SFGW: TI same as Prev TI\n");
513 co_IntSetActiveWindow(NULL
, FALSE
, TRUE
, FALSE
);
517 //ERR("SFGW Deactivate: TI not same as Prev TI\n");
518 // No real reason to wait here.
519 co_IntSendMessageNoWait(hWndPrev
, WM_ASYNC_SETACTIVEWINDOW
, 0, 0 );
524 if (!Wnd
) return FALSE
; // Always return false.
526 if (pti
->MessageQueue
== Wnd
->head
.pti
->MessageQueue
)
528 //ERR("Same PQ and WQ go active.\n");
529 Ret
= co_IntSetActiveWindow(Wnd
, MouseActivate
, TRUE
, FALSE
);
531 else if (Wnd
->head
.pti
->MessageQueue
->spwndActive
== Wnd
)
533 //ERR("Same Active and Wnd.\n");
538 //ERR("Activate Not same PQ and WQ and Wnd.\n");
539 //// CORE-10785 fix hang, ROSTESTS-208 allows test to run.
540 //// co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
541 co_IntSendMessageNoWait(hWnd
, WM_ASYNC_SETACTIVEWINDOW
, (WPARAM
)Wnd
, (LPARAM
)MouseActivate
);
548 co_IntSetActiveWindow(PWND Wnd OPTIONAL
, BOOL bMouse
, BOOL bFocus
, BOOL Async
)
551 PUSER_MESSAGE_QUEUE ThreadQueue
;
552 PWND pWndChg
, WndPrev
; // State changes.
556 CBTACTIVATESTRUCT cbt
;
557 //ERR("co_IntSetActiveWindow 1\n");
561 hWnd
= UserHMGetHandle(Wnd
);
562 if ((Wnd
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
563 if (Wnd
== UserGetDesktopWindow()) return FALSE
;
564 //ERR("co_IntSetActiveWindow 1a hWnd 0x%p\n",hWnd);
567 //ERR("co_IntSetActiveWindow 2\n");
568 pti
= PsGetCurrentThreadWin32Thread();
569 ThreadQueue
= pti
->MessageQueue
;
570 ASSERT(ThreadQueue
!= 0);
572 hWndPrev
= ThreadQueue
->spwndActive
? UserHMGetHandle(ThreadQueue
->spwndActive
) : NULL
;
574 pWndChg
= ThreadQueue
->spwndActive
; // Keep to notify of a preemptive switch.
578 BOOL Ret
, DoFG
, AllowFG
;
580 if (Wnd
->state
& WNDS_BEINGACTIVATED
) return TRUE
;
583 return TRUE
; // Fix CORE-8780 and CORE-11979. See CORE-11324 for breakage.
586 if (ThreadQueue
== Wnd
->head
.pti
->MessageQueue
)
588 if (IsAllowedFGActive(pti
, Wnd
))
594 //ERR("co_IntSetActiveWindow 3 Go Out!\n");
597 AllowFG
= !pti
->cVisWindows
; // Nothing is visable.
598 //ERR("co_IntSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
600 else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
602 //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
603 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
604 //if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
605 if (!gpqForeground
|| gpqForeground
== ThreadQueue
)
613 if (pti
->TIF_flags
& TIF_ALLOWFOREGROUNDACTIVATE
|| pti
->cVisWindows
)
620 //ERR("co_IntSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
625 pti
->TIF_flags
|= TIF_ALLOWFOREGROUNDACTIVATE
;
626 //ERR("co_IntSetActiveWindow 3c FG set\n");
627 Ret
= co_IntSetForegroundAndFocusWindow(Wnd
, bMouse
);
630 pti
->TIF_flags
|= TIF_ALLOWFOREGROUNDACTIVATE
;
634 pti
->TIF_flags
&= ~TIF_ALLOWFOREGROUNDACTIVATE
;
640 /* Call CBT hook chain */
642 cbt
.hWndActive
= hWndPrev
;
643 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
645 ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
649 if ( ThreadQueue
->spwndActive
&& ThreadQueue
->spwndActive
->state
& WNDS_DESTROYED
)
650 ThreadQueue
->spwndActive
= NULL
;
652 ThreadQueue
->spwndActivePrev
= ThreadQueue
->spwndActive
;
654 WndPrev
= ThreadQueue
->spwndActive
; // Keep to save changing active.
658 if (ThreadQueue
== gpqForeground
) gpqForegroundPrev
= ThreadQueue
;
659 if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev
), hWnd
)) return FALSE
;
662 WndPrev
= ThreadQueue
->spwndActive
; // Again keep to save changing active.
664 // While in calling message proc or hook:
665 // Fail if a preemptive switch was made, current active not made previous,
666 // focus window is dead or no longer the same thread queue.
667 if ( ThreadQueue
->spwndActivePrev
!= ThreadQueue
->spwndActive
||
668 pWndChg
!= WndPrev
||
669 (Wnd
&& !VerifyWnd(Wnd
)) ||
670 ThreadQueue
!= pti
->MessageQueue
)
672 ERR("SetActiveWindow: Summary ERROR, active state changed!\n");
676 if (!WndPrev
) ThreadQueue
->QF_flags
&= ~QF_FOCUSNULLSINCEACTIVE
;
678 if (Wnd
) Wnd
->state
|= WNDS_BEINGACTIVATED
;
680 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND
, Wnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
681 //// Breaks Atl-Esc/Tab via User32.
682 ////FindRemoveAsyncMsg(Wnd,(WPARAM)Wnd); // Clear out activate ASYNC messages.
684 /* check if the specified window can be set in the input data of a given queue */
685 if ( !Wnd
|| ThreadQueue
== Wnd
->head
.pti
->MessageQueue
)
687 /* set the current thread active window */
688 ThreadQueue
->spwndActive
= Wnd
;
691 WndPrev
= VerifyWnd(ThreadQueue
->spwndActivePrev
); // Now should be set but verify it again.
693 InAAPM
= co_IntSendActivateMessages(WndPrev
, Wnd
, bMouse
, Async
);
695 /* now change focus if necessary */
696 //// Fixes CORE-6452 allows setting focus on window.
697 if (bFocus
&& !(ThreadQueue
->QF_flags
& QF_FOCUSNULLSINCEACTIVE
))
699 /* Do not change focus if the window is no longer active */
700 if (pti
->MessageQueue
->spwndActive
!= IntGetNonChildAncestor(pti
->MessageQueue
->spwndFocus
))
702 PWND pWndSend
= pti
->MessageQueue
->spwndActive
;
703 // Clear focus if the active window is minimized.
704 if (pWndSend
&& pti
->MessageQueue
->spwndActive
->style
& WS_MINIMIZE
) pWndSend
= NULL
;
705 // Send focus messages and if so, set the focus.
706 IntSendFocusMessages( pti
, pWndSend
);
712 pti
->TIF_flags
&= ~TIF_INACTIVATEAPPMSG
;
715 // FIXME: Used in the menu loop!!!
716 ThreadQueue
->QF_flags
|= QF_ACTIVATIONCHANGE
;
718 //ERR("co_IntSetActiveWindow Exit\n");
719 if (Wnd
) Wnd
->state
&= ~WNDS_BEINGACTIVATED
;
720 return (ThreadQueue
->spwndActive
== Wnd
);
724 co_IntMouseActivateWindow(PWND Wnd
)
726 TRACE("Mouse Active\n");
727 return co_IntSetForegroundAndFocusWindow(Wnd
, TRUE
);
731 UserSetActiveWindow(PWND Wnd
)
733 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
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!
752 Now Handle wines Msg.c test_SetActiveWindow( 0 )...
754 TRACE("USAW: Previous active window\n");
755 if ( gpqForegroundPrev
&&
756 gpqForegroundPrev
->spwndActivePrev
&&
757 (gpqForegroundPrev
->spwndActivePrev
->style
& (WS_VISIBLE
|WS_DISABLED
)) == WS_VISIBLE
&&
758 !(gpqForegroundPrev
->spwndActivePrev
->state2
& WNDS2_BOTTOMMOST
) &&
759 (Wnd
= VerifyWnd(gpqForegroundPrev
->spwndActivePrev
)) != NULL
)
761 TRACE("USAW:PAW hwnd %p\n",Wnd
?Wnd
->head
.h
:NULL
);
762 return co_IntSetActiveWindow(Wnd
, FALSE
, TRUE
, FALSE
);
765 // Activate anyone but the active window.
766 if ( pti
->MessageQueue
->spwndActive
&&
767 (Wnd
= VerifyWnd(pti
->MessageQueue
->spwndActive
)) != NULL
)
769 ERR("USAW:AOWM hwnd %p\n",Wnd
?Wnd
->head
.h
:NULL
);
770 if (!ActivateOtherWindowMin(Wnd
))
772 // Okay, now go find someone else to play with!
773 ERR("USAW: Going to WPAOW\n");
774 co_WinPosActivateOtherWindow(Wnd
);
779 TRACE("USAW: Nothing\n");
784 co_UserSetFocus(PWND Window
)
789 PUSER_MESSAGE_QUEUE ThreadQueue
;
792 ASSERT_REFS_CO(Window
);
794 pti
= PsGetCurrentThreadWin32Thread();
795 ThreadQueue
= pti
->MessageQueue
;
796 ASSERT(ThreadQueue
!= 0);
798 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window
? UserHMGetHandle(Window
) : 0, pti
);
800 hWndPrev
= ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
804 if (hWndPrev
== UserHMGetHandle(Window
))
806 return hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0; /* Nothing to do */
809 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
811 ERR("SetFocus Must have the same Q!\n");
815 /* Check if we can set the focus to this window */
816 //// Fixes wine win test_SetParent both "todo" line 3710 and 3720...
817 for (pwndTop
= Window
; pwndTop
; pwndTop
= pwndTop
->spwndParent
)
819 if (pwndTop
->style
& (WS_MINIMIZED
|WS_DISABLED
)) return 0;
820 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
821 if (pwndTop
->spwndParent
== NULL
) break;
824 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)Window
->head
.h
, (LPARAM
)hWndPrev
))
826 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
830 /* Activate pwndTop if needed. */
831 if (pwndTop
!= ThreadQueue
->spwndActive
)
833 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue(); // Keep it based on desktop.
834 if (ThreadQueue
!= ForegroundQueue
&& IsAllowedFGActive(pti
, pwndTop
)) // Rule 2 & 3.
836 //ERR("SetFocus: Set Foreground!\n");
837 if (!(pwndTop
->style
& WS_VISIBLE
))
839 pti
->ppi
->W32PF_flags
|= W32PF_ALLOWFOREGROUNDACTIVATE
;
841 if (!co_IntSetForegroundAndFocusWindow(pwndTop
, FALSE
))
843 ERR("SetFocus: Set Foreground and Focus Failed!\n");
848 /* Set Active when it is needed. */
849 if (pwndTop
!= ThreadQueue
->spwndActive
)
851 //ERR("SetFocus: Set Active!\n");
852 if (!co_IntSetActiveWindow(pwndTop
, FALSE
, FALSE
, FALSE
))
854 ERR("SetFocus: Set Active Failed!\n");
859 /* Abort if window destroyed */
860 if (Window
->state2
& WNDS2_INDESTROY
) return 0;
861 /* Do not change focus if the window is no longer active */
862 if (pwndTop
!= ThreadQueue
->spwndActive
)
864 ERR("SetFocus: Top window did not go active!\n");
869 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
870 hWndPrev
= ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
872 IntSendFocusMessages( pti
, Window
);
874 TRACE("Focus: %p -> %p\n", hWndPrev
, Window
->head
.h
);
876 else /* NULL hwnd passed in */
878 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)0, (LPARAM
)hWndPrev
))
880 ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
884 /* set the current thread focus window null */
885 IntSendFocusMessages( pti
, NULL
);
887 return hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0;
891 UserGetForegroundWindow(VOID
)
893 PUSER_MESSAGE_QUEUE ForegroundQueue
;
895 ForegroundQueue
= IntGetFocusMessageQueue();
896 return( ForegroundQueue
? (ForegroundQueue
->spwndActive
? UserHMGetHandle(ForegroundQueue
->spwndActive
) : 0) : 0);
899 HWND FASTCALL
UserGetActiveWindow(VOID
)
902 PUSER_MESSAGE_QUEUE ThreadQueue
;
904 pti
= PsGetCurrentThreadWin32Thread();
905 ThreadQueue
= pti
->MessageQueue
;
906 return( ThreadQueue
? (ThreadQueue
->spwndActive
? UserHMGetHandle(ThreadQueue
->spwndActive
) : 0) : 0);
913 PUSER_MESSAGE_QUEUE ThreadQueue
;
914 DECLARE_RETURN(HWND
);
916 TRACE("Enter IntGetCapture\n");
918 pti
= PsGetCurrentThreadWin32Thread();
919 ThreadQueue
= pti
->MessageQueue
;
920 RETURN( ThreadQueue
? (ThreadQueue
->spwndCapture
? UserHMGetHandle(ThreadQueue
->spwndCapture
) : 0) : 0);
923 TRACE("Leave IntGetCapture, ret=%p\n", _ret_
);
928 co_UserSetCapture(HWND hWnd
)
931 PUSER_MESSAGE_QUEUE ThreadQueue
;
932 PWND pWnd
, Window
= NULL
;
935 pti
= PsGetCurrentThreadWin32Thread();
936 ThreadQueue
= pti
->MessageQueue
;
938 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
)
941 if (hWnd
&& (Window
= UserGetWindowObject(hWnd
)))
943 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
945 ERR("Window Thread does not match Current!\n");
950 hWndPrev
= MsqSetStateWindow(pti
, MSQ_STATE_CAPTURE
, hWnd
);
954 pWnd
= UserGetWindowObject(hWndPrev
);
956 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
960 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART
, Window
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
963 // Only send the message if we have a previous Window!
964 // Fix msg_menu tracking popup menu and win test_capture_4!!!!
968 if (ThreadQueue
->MenuOwner
&& Window
) ThreadQueue
->QF_flags
|= QF_CAPTURELOCKED
;
970 co_IntSendMessage(hWndPrev
, WM_CAPTURECHANGED
, 0, (LPARAM
)hWnd
);
972 ThreadQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
975 if (hWnd
== NULL
) // Release mode.
979 /* Also remove other windows if not capturing anymore */
980 MsqSetStateWindow(pti
, MSQ_STATE_MENUOWNER
, NULL
);
981 MsqSetStateWindow(pti
, MSQ_STATE_MOVESIZE
, NULL
);
983 /* Somebody may have missed some mouse movements */
987 mi
.dwFlags
= MOUSEEVENTF_MOVE
;
990 UserSendMouseInput(&mi
, FALSE
);
1000 IntReleaseCapture(VOID
)
1003 PUSER_MESSAGE_QUEUE ThreadQueue
;
1005 pti
= PsGetCurrentThreadWin32Thread();
1006 ThreadQueue
= pti
->MessageQueue
;
1008 // Can not release inside WM_CAPTURECHANGED!!
1009 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
) return FALSE
;
1011 co_UserSetCapture(NULL
);
1020 co_IntSetForegroundWindow(PWND Window
)
1022 if (Window
) ASSERT_REFS_CO(Window
);
1024 return co_IntSetForegroundAndFocusWindow(Window
, FALSE
);
1031 co_IntSetForegroundWindowMouse(PWND Window
)
1033 if (Window
) ASSERT_REFS_CO(Window
);
1035 return co_IntSetForegroundAndFocusWindow(Window
, TRUE
);
1042 IntLockSetForegroundWindow(UINT uLockCode
)
1044 ULONG Err
= ERROR_ACCESS_DENIED
;
1045 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
1049 if ( CanForceFG(ppi
) && !gppiLockSFW
)
1056 if ( gppiLockSFW
== ppi
)
1063 Err
= ERROR_INVALID_PARAMETER
;
1065 EngSetLastError(Err
);
1073 IntAllowSetForegroundWindow(DWORD dwProcessId
)
1075 PPROCESSINFO ppi
, ppiCur
;
1076 PEPROCESS Process
= NULL
;
1079 if (dwProcessId
!= ASFW_ANY
)
1081 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)dwProcessId
, &Process
)))
1083 EngSetLastError(ERROR_INVALID_PARAMETER
);
1086 ppi
= PsGetProcessWin32Process(Process
);
1089 ObDereferenceObject(Process
);
1093 ppiCur
= PsGetCurrentProcessWin32Process();
1094 if (!CanForceFG(ppiCur
))
1096 if (Process
) ObDereferenceObject(Process
);
1097 EngSetLastError(ERROR_ACCESS_DENIED
);
1100 if (dwProcessId
== ASFW_ANY
)
1101 { // All processes will be enabled to set the foreground window.
1102 //ERR("ptiLastInput is CLEARED!!\n");
1103 ptiLastInput
= NULL
;
1106 { // Rule #3, last input event in force.
1107 ERR("ptiLastInput is SET!!\n");
1108 //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030.
1109 ObDereferenceObject(Process
);
1118 NtUserGetForegroundWindow(VOID
)
1120 DECLARE_RETURN(HWND
);
1122 TRACE("Enter NtUserGetForegroundWindow\n");
1123 UserEnterExclusive();
1125 RETURN( UserGetForegroundWindow());
1128 TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_
);
1134 NtUserSetActiveWindow(HWND hWnd
)
1136 USER_REFERENCE_ENTRY Ref
;
1139 DECLARE_RETURN(HWND
);
1141 TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd
);
1142 UserEnterExclusive();
1147 if (!(Window
= UserGetWindowObject(hWnd
)))
1149 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd
);
1155 Window
->head
.pti
->MessageQueue
== gptiCurrent
->MessageQueue
)
1157 hWndPrev
= gptiCurrent
->MessageQueue
->spwndActive
? UserHMGetHandle(gptiCurrent
->MessageQueue
->spwndActive
) : NULL
;
1158 if (Window
) UserRefObjectCo(Window
, &Ref
);
1159 UserSetActiveWindow(Window
);
1160 if (Window
) UserDerefObjectCo(Window
);
1161 RETURN( hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0 );
1166 TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_
);
1175 NtUserSetCapture(HWND hWnd
)
1177 DECLARE_RETURN(HWND
);
1179 TRACE("Enter NtUserSetCapture(%p)\n", hWnd
);
1180 UserEnterExclusive();
1182 RETURN( co_UserSetCapture(hWnd
));
1185 TRACE("Leave NtUserSetCapture, ret=%p\n", _ret_
);
1194 NtUserSetFocus(HWND hWnd
)
1197 USER_REFERENCE_ENTRY Ref
;
1198 DECLARE_RETURN(HWND
);
1201 TRACE("Enter NtUserSetFocus(%p)\n", hWnd
);
1202 UserEnterExclusive();
1206 if (!(Window
= UserGetWindowObject(hWnd
)))
1208 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd
);
1212 UserRefObjectCo(Window
, &Ref
);
1213 ret
= co_UserSetFocus(Window
);
1214 UserDerefObjectCo(Window
);
1220 RETURN( co_UserSetFocus(0));
1224 TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_
);