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
)
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 co_WinPosSetWindowPos(Window
, HWND_TOP
, 0, 0, 0, 0, flags
);
140 OldTID
= WindowPrev
? IntGetWndThreadId(WindowPrev
) : NULL
;
141 NewTID
= IntGetWndThreadId(Window
);
142 ptiOld
= WindowPrev
? WindowPrev
->head
.pti
: NULL
;
143 ptiNew
= Window
->head
.pti
;
145 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
147 if (!(pti
->TIF_flags
& TIF_INACTIVATEAPPMSG
) &&
148 (!WindowPrev
|| OldTID
!= NewTID
) )
153 List
= IntWinListChildren(UserGetDesktopWindow());
158 ptiOld
->TIF_flags
|= TIF_INACTIVATEAPPMSG
;
159 ptiOld
->pClientInfo
->dwTIFlags
= ptiOld
->TIF_flags
;
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
;
171 ptiOld
->pClientInfo
->dwTIFlags
= ptiOld
->TIF_flags
;
174 { //// Prevents a resource crash due to reentrance!
176 pti
->TIF_flags
|= TIF_INACTIVATEAPPMSG
;
177 pti
->pClientInfo
->dwTIFlags
= pti
->TIF_flags
;
179 for (phWnd
= List
; *phWnd
; ++phWnd
)
181 cWindow
= ValidateHwndNoErr(*phWnd
);
182 if (cWindow
&& cWindow
->head
.pti
== ptiNew
)
183 { // TRUE if the window is being activated,
184 // ThreadId that owns the window being deactivated.
185 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, TRUE
, (LPARAM
)OldTID
);
189 ExFreePoolWithTag(List
, USERTAG_WINDOWLIST
);
193 UserDerefObjectCo(WindowPrev
); // Now allow the previous window to die.
195 if (Window
->state
& WNDS_ACTIVEFRAME
)
196 { // If already active frame do not allow NCPaint.
197 //ERR("SendActivateMessage Is Active Frame!\n");
198 Window
->state
|= WNDS_NONCPAINT
;
201 if (Window
->style
& WS_MINIMIZE
)
203 TRACE("Widow was minimized\n");
206 co_IntMakeWindowActive(Window
);
208 UserDerefObjectCo(Window
);
210 /* FIXME: IntIsWindow */
211 co_IntSendMessageNoWait( UserHMGetHandle(Window
),
213 (WPARAM
)(Window
== gpqForeground
->spwndActive
),
214 0); //(LPARAM)hWndPrev);
216 co_IntSendMessageNoWait( UserHMGetHandle(Window
),
218 MAKEWPARAM(MouseActivate
? WA_CLICKACTIVE
: WA_ACTIVE
, Window
->style
& WS_MINIMIZE
),
219 (LPARAM
)(WindowPrev
? UserHMGetHandle(WindowPrev
) : 0));
221 if (!Window
->spwndOwner
&& !IntGetParent(Window
))
223 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
224 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED
, (WPARAM
) UserHMGetHandle(Window
), FALSE
);
227 Window
->state
&= ~WNDS_NONCPAINT
;
234 IntSendFocusMessages( PTHREADINFO pti
, PWND pWnd
)
237 PUSER_MESSAGE_QUEUE ThreadQueue
= pti
->MessageQueue
; // Queue can change...
239 ThreadQueue
->QF_flags
&= ~QF_FOCUSNULLSINCEACTIVE
;
240 if (!pWnd
&& ThreadQueue
->spwndActive
)
242 ThreadQueue
->QF_flags
|= QF_FOCUSNULLSINCEACTIVE
;
245 pWndPrev
= ThreadQueue
->spwndFocus
;
247 /* check if the specified window can be set in the input data of a given queue */
248 if (!pWnd
|| ThreadQueue
== pWnd
->head
.pti
->MessageQueue
)
249 /* set the current thread focus window */
250 ThreadQueue
->spwndFocus
= pWnd
;
256 co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev
), WM_KILLFOCUS
, (WPARAM
)UserHMGetHandle(pWnd
), 0);
258 if (ThreadQueue
->spwndFocus
== pWnd
)
260 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
261 co_IntPostOrSendMessage(UserHMGetHandle(pWnd
), WM_SETFOCUS
, (WPARAM
)(pWndPrev
? UserHMGetHandle(pWndPrev
) : NULL
), 0);
268 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
269 co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev
), WM_KILLFOCUS
, 0, 0);
275 IntFindChildWindowToOwner(PWND Root
, PWND Owner
)
278 PWND Child
, OwnerWnd
;
280 for(Child
= Root
->spwndChild
; Child
; Child
= Child
->spwndNext
)
282 OwnerWnd
= Child
->spwndOwner
;
286 if(OwnerWnd
== Owner
)
297 FindRemoveAsyncMsg(PWND Wnd
)
299 PUSER_MESSAGE_QUEUE MessageQueue
;
300 PUSER_SENT_MESSAGE Message
;
305 MessageQueue
= Wnd
->head
.pti
->MessageQueue
;
307 if (!IsListEmpty(&MessageQueue
->SentMessagesListHead
))
309 // Scan sent queue messages to see if we received async messages.
310 Entry
= MessageQueue
->SentMessagesListHead
.Flink
;
311 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
314 if (Message
->Msg
.message
== WM_ASYNC_SETACTIVEWINDOW
&&
315 Message
->Msg
.hwnd
== UserHMGetHandle(Wnd
) &&
316 Message
->Msg
.wParam
== 0 )
318 TRACE("ASYNC SAW: Found one in the Sent Msg Queue! %p\n", Message
->Msg
.hwnd
);
319 RemoveEntryList(Entry
); // Purge the entry.
321 Entry
= Message
->ListEntry
.Flink
;
322 Message
= CONTAINING_RECORD(Entry
, USER_SENT_MESSAGE
, ListEntry
);
324 while (Entry
!= &MessageQueue
->SentMessagesListHead
);
329 Can the system force foreground from one or more conditions.
332 CanForceFG(PPROCESSINFO ppi
)
335 ptiLastInput
->ppi
== ppi
||
337 gptiForeground
->ppi
== ppi
||
338 ppi
->W32PF_flags
& (W32PF_ALLOWFOREGROUNDACTIVATE
| W32PF_SETFOREGROUNDALLOWED
) ||
339 gppiInputProvider
== ppi
||
347 The system restricts which processes can set the foreground window. A process
348 can set the foreground window only if one of the following conditions is true:
350 * The process is the foreground process.
351 * The process was started by the foreground process.
352 * The process received the last input event.
353 * There is no foreground process.
354 * The foreground process is being debugged.
355 * The foreground is not locked (see LockSetForegroundWindow).
356 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
357 * No menus are active.
361 co_IntSetForegroundAndFocusWindow(
363 _In_ BOOL MouseActivate
)
366 HWND hWndPrev
= NULL
;
367 PUSER_MESSAGE_QUEUE PrevForegroundQueue
;
369 BOOL fgRet
= FALSE
, Ret
= FALSE
;
372 NT_ASSERT(Wnd
!= NULL
);
374 hWnd
= UserHMGetHandle(Wnd
);
376 TRACE("SetForegroundAndFocusWindow(%x, %s)\n", hWnd
, (MouseActivate
? "TRUE" : "FALSE"));
378 PrevForegroundQueue
= IntGetFocusMessageQueue(); // Use this active desktop.
379 pti
= PsGetCurrentThreadWin32Thread();
381 if (PrevForegroundQueue
)
382 { // Same Window Q as foreground just do active.
383 //ERR("Same Window Q as foreground just do active.\n");
384 if (Wnd
&& Wnd
->head
.pti
->MessageQueue
== PrevForegroundQueue
)
386 if (pti
->MessageQueue
== PrevForegroundQueue
)
387 { // Same WQ and TQ go active.
388 //ERR("Same WQ and TQ go active.\n");
389 Ret
= co_IntSetActiveWindow(Wnd
, NULL
, MouseActivate
, TRUE
, FALSE
);
391 else if (Wnd
->head
.pti
->MessageQueue
->spwndActive
== Wnd
)
392 { // Same WQ and it is active.
393 //ERR("Same WQ and it is active.\n");
397 { // Same WQ as FG but not the same TQ send active.
398 //ERR("Same WQ as FG but not the same TQ send active.\n");
399 co_IntSendMessageNoWait(hWnd
, WM_ASYNC_SETACTIVEWINDOW
, (WPARAM
)Wnd
, (LPARAM
)MouseActivate
);
405 hWndPrev
= PrevForegroundQueue
->spwndActive
? UserHMGetHandle(PrevForegroundQueue
->spwndActive
) : 0;
408 if ( (( !IsFGLocked() || pti
->ppi
== gppiInputProvider
) &&
409 ( CanForceFG(pti
->ppi
) || pti
->TIF_flags
& (TIF_SYSTEMTHREAD
|TIF_CSRSSTHREAD
|TIF_ALLOWFOREGROUNDACTIVATE
) )) ||
410 pti
->ppi
== ppiScrnSaver
413 IntSetFocusMessageQueue(Wnd
->head
.pti
->MessageQueue
);
414 gptiForeground
= Wnd
->head
.pti
;
415 TRACE("Set Foreground pti 0x%p Q 0x%p\n",Wnd
->head
.pti
, Wnd
->head
.pti
->MessageQueue
);
418 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
419 other thread after we already changed the foreground window back to our own
422 FindRemoveAsyncMsg(Wnd
); // Do this to fix test_SFW todos!
426 // Fix FG Bounce with regedit.
427 if (hWndPrev
!= hWnd
)
429 if (PrevForegroundQueue
&&
431 Wnd
->head
.pti
->MessageQueue
!= PrevForegroundQueue
&&
432 PrevForegroundQueue
->spwndActive
)
434 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
435 if (pti
->MessageQueue
== PrevForegroundQueue
)
437 //ERR("SFGW: TI same as Prev TI\n");
438 co_IntSetActiveWindow(NULL
, NULL
, FALSE
, TRUE
, FALSE
);
441 co_IntSendMessageNoWait(hWndPrev
, WM_ASYNC_SETACTIVEWINDOW
, 0, 0 );
445 if (pti
->MessageQueue
== Wnd
->head
.pti
->MessageQueue
)
447 Ret
= co_IntSetActiveWindow(Wnd
, NULL
, MouseActivate
, TRUE
, FALSE
);
449 else if (Wnd
->head
.pti
->MessageQueue
->spwndActive
== Wnd
)
455 co_IntSendMessageNoWait(hWnd
, WM_ASYNC_SETACTIVEWINDOW
, (WPARAM
)Wnd
, (LPARAM
)MouseActivate
);
463 co_IntMouseActivateWindow(PWND Wnd
)
467 USER_REFERENCE_ENTRY Ref
;
471 if (Wnd
->style
& WS_DISABLED
)
475 PWND DesktopWindow
= UserGetDesktopWindow();
478 Top
= IntFindChildWindowToOwner(DesktopWindow
, Wnd
);
479 if ((TopWnd
= ValidateHwndNoErr(Top
)))
481 UserRefObjectCo(TopWnd
, &Ref
);
482 Ret
= co_IntMouseActivateWindow(TopWnd
);
483 UserDerefObjectCo(TopWnd
);
491 TopWindow
= UserGetAncestor(Wnd
, GA_ROOT
);
492 //if (TopWindow) {ERR("MAW 2 pWnd %p hWnd %p\n",TopWindow,TopWindow->head.h);}
493 if (!TopWindow
) return FALSE
;
495 /* TMN: Check return value from this function? */
496 UserRefObjectCo(TopWindow
, &Ref
);
497 co_IntSetForegroundAndFocusWindow(TopWindow
, TRUE
);
498 UserDerefObjectCo(TopWindow
);
503 co_IntSetActiveWindow(PWND Wnd OPTIONAL
, HWND
* Prev
, BOOL bMouse
, BOOL bFocus
, BOOL Async
)
506 PUSER_MESSAGE_QUEUE ThreadQueue
;
507 PWND pWndChg
, WndPrev
; // State changes.
511 CBTACTIVATESTRUCT cbt
;
516 hWnd
= UserHMGetHandle(Wnd
);
517 if ((Wnd
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
518 if (Wnd
== UserGetDesktopWindow()) return FALSE
;
521 pti
= PsGetCurrentThreadWin32Thread();
522 ThreadQueue
= pti
->MessageQueue
;
523 ASSERT(ThreadQueue
!= 0);
525 hWndPrev
= ThreadQueue
->spwndActive
? UserHMGetHandle(ThreadQueue
->spwndActive
) : NULL
;
526 if (Prev
) *Prev
= hWndPrev
;
527 if (hWndPrev
== hWnd
) return TRUE
;
529 pWndChg
= ThreadQueue
->spwndActive
; // Keep to notify of a preemptive switch.
533 if (ThreadQueue
!= Wnd
->head
.pti
->MessageQueue
)
535 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
536 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
537 if (!ForegroundQueue
|| ForegroundQueue
== ThreadQueue
)
539 return co_IntSetForegroundAndFocusWindow(Wnd
, bMouse
);
543 if (Wnd
->state
& WNDS_BEINGACTIVATED
) return TRUE
;
546 /* Call CBT hook chain */
548 cbt
.hWndActive
= hWndPrev
;
549 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
551 ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
555 if ( ThreadQueue
->spwndActive
&& ThreadQueue
->spwndActive
->state
& WNDS_DESTROYED
)
556 ThreadQueue
->spwndActive
= NULL
;
558 ThreadQueue
->spwndActivePrev
= ThreadQueue
->spwndActive
;
560 WndPrev
= ThreadQueue
->spwndActive
; // Keep to save changing active.
564 if (ThreadQueue
== gpqForeground
) gpqForegroundPrev
= ThreadQueue
;
565 if (!co_IntSendDeactivateMessages(hWndPrev
, hWnd
)) return FALSE
;
568 // While in calling message proc or hook:
569 // Fail if a preemptive switch was made, current active not made previous,
570 // focus window is dead or no longer the same thread queue.
571 if ( ThreadQueue
->spwndActivePrev
!= ThreadQueue
->spwndActive
||
572 pWndChg
!= ThreadQueue
->spwndActive
||
573 (Wnd
&& !VerifyWnd(Wnd
)) ||
574 ThreadQueue
!= pti
->MessageQueue
)
576 ERR("SetActiveWindow: Summery ERROR, active state changed!\n");
580 if (!WndPrev
) ThreadQueue
->QF_flags
&= ~QF_FOCUSNULLSINCEACTIVE
;
582 if (Wnd
) Wnd
->state
|= WNDS_BEINGACTIVATED
;
584 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND
, Wnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
586 /* check if the specified window can be set in the input data of a given queue */
587 if ( !Wnd
|| ThreadQueue
== Wnd
->head
.pti
->MessageQueue
)
589 /* set the current thread active window */
590 ThreadQueue
->spwndActive
= Wnd
;
593 InAAPM
= co_IntSendActivateMessages(WndPrev
, Wnd
, bMouse
, Async
);
595 /* now change focus if necessary */
596 if (bFocus
&& !(ThreadQueue
->QF_flags
& QF_FOCUSNULLSINCEACTIVE
))
598 /* Do not change focus if the window is no longer active */
599 if (ThreadQueue
->spwndActive
== Wnd
)
601 if (!ThreadQueue
->spwndFocus
||
603 UserGetAncestor(ThreadQueue
->spwndFocus
, GA_ROOT
) != Wnd
)
605 co_UserSetFocus(Wnd
);
612 pti
->TIF_flags
&= ~TIF_INACTIVATEAPPMSG
;
613 pti
->pClientInfo
->dwTIFlags
= pti
->TIF_flags
;
616 // FIXME: Used in the menu loop!!!
617 //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
619 if (Wnd
) Wnd
->state
&= ~WNDS_BEINGACTIVATED
;
620 return (ThreadQueue
->spwndActive
== Wnd
);
624 co_UserSetFocus(PWND Window
)
629 PUSER_MESSAGE_QUEUE ThreadQueue
;
632 ASSERT_REFS_CO(Window
);
634 pti
= PsGetCurrentThreadWin32Thread();
635 ThreadQueue
= pti
->MessageQueue
;
636 ASSERT(ThreadQueue
!= 0);
638 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window
? UserHMGetHandle(Window
) : 0, pti
);
640 hWndPrev
= ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
644 if (hWndPrev
== UserHMGetHandle(Window
))
646 return hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0; /* Nothing to do */
649 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
651 ERR("SetFocus Must have the same Q!\n");
655 /* Check if we can set the focus to this window */
659 if (pwndTop
->style
& (WS_MINIMIZED
|WS_DISABLED
)) return 0;
660 if (!pwndTop
->spwndParent
|| pwndTop
->spwndParent
== UserGetDesktopWindow())
662 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return 0;
665 if (pwndTop
->spwndParent
== UserGetMessageWindow()) return 0;
666 pwndTop
= pwndTop
->spwndParent
;
669 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)Window
->head
.h
, (LPARAM
)hWndPrev
))
671 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
675 /* Activate pwndTop if needed. */
676 if (pwndTop
!= ThreadQueue
->spwndActive
)
678 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue(); // Keep it based on desktop.
679 if (ThreadQueue
!= ForegroundQueue
) // HACK see rule 2 & 3.
681 if (!co_IntSetForegroundAndFocusWindow(pwndTop
, FALSE
))
683 ERR("SetFocus: Set Foreground and Focus Failed!\n");
688 /* Set Active when it is needed. */
689 if (pwndTop
!= ThreadQueue
->spwndActive
)
691 if (!co_IntSetActiveWindow(pwndTop
, NULL
, FALSE
, FALSE
, FALSE
))
693 ERR("SetFocus: Set Active Failed!\n");
698 /* Abort if window destroyed */
699 if (Window
->state2
& WNDS2_INDESTROY
) return 0;
700 /* Do not change focus if the window is no longer active */
701 if (pwndTop
!= ThreadQueue
->spwndActive
)
703 ERR("SetFocus: Top window did not go active!\n");
708 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
709 hWndPrev
= ThreadQueue
->spwndFocus
? UserHMGetHandle(ThreadQueue
->spwndFocus
) : 0;
711 IntSendFocusMessages( pti
, Window
);
713 TRACE("Focus: %d -> %d\n", hWndPrev
, Window
->head
.h
);
715 else /* NULL hwnd passed in */
717 // if (!hWndPrev) return 0; /* nothing to do */
719 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)0, (LPARAM
)hWndPrev
))
721 ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
725 /* set the current thread focus window null */
726 IntSendFocusMessages( pti
, NULL
);
728 return hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0;
732 UserGetForegroundWindow(VOID
)
734 PUSER_MESSAGE_QUEUE ForegroundQueue
;
736 ForegroundQueue
= IntGetFocusMessageQueue();
737 return( ForegroundQueue
? (ForegroundQueue
->spwndActive
? UserHMGetHandle(ForegroundQueue
->spwndActive
) : 0) : 0);
740 HWND FASTCALL
UserGetActiveWindow(VOID
)
743 PUSER_MESSAGE_QUEUE ThreadQueue
;
745 pti
= PsGetCurrentThreadWin32Thread();
746 ThreadQueue
= pti
->MessageQueue
;
747 return( ThreadQueue
? (ThreadQueue
->spwndActive
? UserHMGetHandle(ThreadQueue
->spwndActive
) : 0) : 0);
754 PUSER_MESSAGE_QUEUE ThreadQueue
;
755 DECLARE_RETURN(HWND
);
757 TRACE("Enter IntGetCapture\n");
759 pti
= PsGetCurrentThreadWin32Thread();
760 ThreadQueue
= pti
->MessageQueue
;
761 RETURN( ThreadQueue
? (ThreadQueue
->spwndCapture
? UserHMGetHandle(ThreadQueue
->spwndCapture
) : 0) : 0);
764 TRACE("Leave IntGetCapture, ret=%i\n",_ret_
);
769 co_UserSetCapture(HWND hWnd
)
772 PUSER_MESSAGE_QUEUE ThreadQueue
;
773 PWND pWnd
, Window
= NULL
;
776 pti
= PsGetCurrentThreadWin32Thread();
777 ThreadQueue
= pti
->MessageQueue
;
779 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
)
782 if (hWnd
&& (Window
= UserGetWindowObject(hWnd
)))
784 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
790 hWndPrev
= MsqSetStateWindow(ThreadQueue
, MSQ_STATE_CAPTURE
, hWnd
);
794 pWnd
= UserGetWindowObject(hWndPrev
);
796 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
800 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART
, Window
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
802 if (hWndPrev
&& hWndPrev
!= hWnd
)
804 if (ThreadQueue
->MenuOwner
&& Window
) ThreadQueue
->QF_flags
|= QF_CAPTURELOCKED
;
806 co_IntPostOrSendMessage(hWndPrev
, WM_CAPTURECHANGED
, 0, (LPARAM
)hWnd
);
808 ThreadQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
811 ThreadQueue
->spwndCapture
= Window
;
813 if (hWnd
== NULL
) // Release mode.
817 /* Also remove other windows if not capturing anymore */
818 MsqSetStateWindow(ThreadQueue
, MSQ_STATE_MENUOWNER
, NULL
);
819 MsqSetStateWindow(ThreadQueue
, MSQ_STATE_MOVESIZE
, NULL
);
821 /* Somebody may have missed some mouse movements */
825 mi
.dwFlags
= MOUSEEVENTF_MOVE
;
828 UserSendMouseInput(&mi
, FALSE
);
838 IntReleaseCapture(VOID
)
841 PUSER_MESSAGE_QUEUE ThreadQueue
;
843 pti
= PsGetCurrentThreadWin32Thread();
844 ThreadQueue
= pti
->MessageQueue
;
846 // Can not release inside WM_CAPTURECHANGED!!
847 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
) return FALSE
;
849 co_UserSetCapture(NULL
);
858 co_IntSetForegroundWindow(PWND Window
)
860 ASSERT_REFS_CO(Window
);
862 return co_IntSetForegroundAndFocusWindow(Window
, FALSE
);
869 co_IntSetForegroundWindowMouse(PWND Window
)
871 if (Window
) ASSERT_REFS_CO(Window
);
873 return co_IntSetForegroundAndFocusWindow(Window
, TRUE
);
880 IntLockSetForegroundWindow(UINT uLockCode
)
882 ULONG Err
= ERROR_ACCESS_DENIED
;
883 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
887 if ( CanForceFG(ppi
) && !gppiLockSFW
)
894 if ( gppiLockSFW
== ppi
)
901 Err
= ERROR_INVALID_PARAMETER
;
903 EngSetLastError(Err
);
911 IntAllowSetForegroundWindow(DWORD dwProcessId
)
913 PPROCESSINFO ppi
, ppiCur
;
914 PEPROCESS Process
= NULL
;
917 if (dwProcessId
!= ASFW_ANY
)
919 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE
)dwProcessId
, &Process
)))
921 EngSetLastError(ERROR_INVALID_PARAMETER
);
924 ppi
= PsGetProcessWin32Process(Process
);
927 ObDereferenceObject(Process
);
931 ppiCur
= PsGetCurrentProcessWin32Process();
932 if (!CanForceFG(ppiCur
))
934 if (Process
) ObDereferenceObject(Process
);
935 EngSetLastError(ERROR_ACCESS_DENIED
);
938 if (dwProcessId
== ASFW_ANY
)
939 { // All processes will be enabled to set the foreground window.
943 { // Rule #3, last input event in force.
944 ptiLastInput
= ppi
->ptiList
;
945 ObDereferenceObject(Process
);
954 NtUserGetForegroundWindow(VOID
)
956 DECLARE_RETURN(HWND
);
958 TRACE("Enter NtUserGetForegroundWindow\n");
959 UserEnterExclusive();
961 RETURN( UserGetForegroundWindow());
964 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_
);
970 NtUserSetActiveWindow(HWND hWnd
)
972 USER_REFERENCE_ENTRY Ref
;
975 DECLARE_RETURN(HWND
);
977 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd
);
978 UserEnterExclusive();
983 if (!(Window
= UserGetWindowObject(hWnd
)))
985 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd
);
991 Window
->head
.pti
->MessageQueue
== gptiCurrent
->MessageQueue
)
993 hWndPrev
= gptiCurrent
->MessageQueue
->spwndActive
? UserHMGetHandle(gptiCurrent
->MessageQueue
->spwndActive
) : NULL
;
994 if (Window
) UserRefObjectCo(Window
, &Ref
);
995 co_IntSetActiveWindow(Window
, NULL
, FALSE
, TRUE
, FALSE
);
996 if (Window
) UserDerefObjectCo(Window
);
997 RETURN( hWndPrev
? (IntIsWindow(hWndPrev
) ? hWndPrev
: 0) : 0 );
1002 TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_
);
1011 NtUserSetCapture(HWND hWnd
)
1013 DECLARE_RETURN(HWND
);
1015 TRACE("Enter NtUserSetCapture(%x)\n", hWnd
);
1016 UserEnterExclusive();
1018 RETURN( co_UserSetCapture(hWnd
));
1021 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_
);
1030 NtUserSetFocus(HWND hWnd
)
1033 USER_REFERENCE_ENTRY Ref
;
1034 DECLARE_RETURN(HWND
);
1037 TRACE("Enter NtUserSetFocus(%x)\n", hWnd
);
1038 UserEnterExclusive();
1042 if (!(Window
= UserGetWindowObject(hWnd
)))
1044 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd
);
1048 UserRefObjectCo(Window
, &Ref
);
1049 ret
= co_UserSetFocus(Window
);
1050 UserDerefObjectCo(Window
);
1056 RETURN( co_UserSetFocus(0));
1060 TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_
);