2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Focus functions
5 * FILE: subsystem/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
;
16 IntGetCaptureWindow(VOID
)
18 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
19 return ForegroundQueue
!= NULL
? ForegroundQueue
->CaptureWindow
: 0;
23 IntGetFocusWindow(VOID
)
25 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
26 return ForegroundQueue
!= NULL
? ForegroundQueue
->FocusWindow
: 0;
30 IntGetThreadFocusWindow(VOID
)
33 PUSER_MESSAGE_QUEUE ThreadQueue
;
35 pti
= PsGetCurrentThreadWin32Thread();
36 ThreadQueue
= pti
->MessageQueue
;
37 return ThreadQueue
!= NULL
? ThreadQueue
->FocusWindow
: 0;
41 co_IntSendDeactivateMessages(HWND hWndPrev
, HWND hWnd
)
45 if (hWndPrev
&& (WndPrev
= UserGetWindowObject(hWndPrev
)))
47 co_IntSendMessageNoWait(hWndPrev
, WM_NCACTIVATE
, FALSE
, 0);
48 co_IntSendMessageNoWait(hWndPrev
, WM_ACTIVATE
,
49 MAKEWPARAM(WA_INACTIVE
, WndPrev
->style
& WS_MINIMIZE
),
55 co_IntSendActivateMessages(HWND hWndPrev
, HWND hWnd
, BOOL MouseActivate
)
57 USER_REFERENCE_ENTRY Ref
, RefPrev
;
58 PWND Window
, WindowPrev
= NULL
;
60 if ((Window
= UserGetWindowObject(hWnd
)))
62 UserRefObjectCo(Window
, &Ref
);
64 WindowPrev
= UserGetWindowObject(hWndPrev
);
66 if (WindowPrev
) UserRefObjectCo(WindowPrev
, &RefPrev
);
68 /* Send palette messages */
69 if (gpsi
->PUSIFlags
& PUSIF_PALETTEDISPLAY
&&
70 co_IntPostOrSendMessage(hWnd
, WM_QUERYNEWPALETTE
, 0, 0))
72 UserSendNotifyMessage( HWND_BROADCAST
,
78 if (Window
->spwndPrev
!= NULL
)
79 co_WinPosSetWindowPos(Window
, HWND_TOP
, 0, 0, 0, 0,
80 SWP_NOSIZE
| SWP_NOMOVE
);
82 if (!Window
->spwndOwner
&& !IntGetParent(Window
))
84 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED
, (LPARAM
) hWnd
);
88 { // Set last active for window and it's owner.
89 Window
->hWndLastActive
= hWnd
;
90 if (Window
->spwndOwner
)
91 Window
->spwndOwner
->hWndLastActive
= hWnd
;
92 Window
->state
|= WNDS_ACTIVEFRAME
;
96 WindowPrev
->state
&= ~WNDS_ACTIVEFRAME
;
98 if (Window
&& WindowPrev
)
102 HANDLE OldTID
= IntGetWndThreadId(WindowPrev
);
103 HANDLE NewTID
= IntGetWndThreadId(Window
);
105 TRACE("SendActiveMessage Old -> %x, New -> %x\n", OldTID
, NewTID
);
106 if (Window
->style
& WS_MINIMIZE
)
108 TRACE("Widow was minimized\n");
111 if (OldTID
!= NewTID
)
113 List
= IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
116 for (phWnd
= List
; *phWnd
; ++phWnd
)
118 cWindow
= UserGetWindowObject(*phWnd
);
120 if (cWindow
&& (IntGetWndThreadId(cWindow
) == OldTID
))
121 { // FALSE if the window is being deactivated,
122 // ThreadId that owns the window being activated.
123 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, FALSE
, (LPARAM
)NewTID
);
126 for (phWnd
= List
; *phWnd
; ++phWnd
)
128 cWindow
= UserGetWindowObject(*phWnd
);
129 if (cWindow
&& (IntGetWndThreadId(cWindow
) == NewTID
))
130 { // TRUE if the window is being activated,
131 // ThreadId that owns the window being deactivated.
132 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, TRUE
, (LPARAM
)OldTID
);
138 UserDerefObjectCo(WindowPrev
); // Now allow the previous window to die.
141 UserDerefObjectCo(Window
);
143 /* FIXME: IntIsWindow */
144 co_IntSendMessageNoWait(hWnd
, WM_NCACTIVATE
, (WPARAM
)(hWnd
== UserGetForegroundWindow()), 0);
145 /* FIXME: WA_CLICKACTIVE */
146 co_IntSendMessageNoWait(hWnd
, WM_ACTIVATE
,
147 MAKEWPARAM(MouseActivate
? WA_CLICKACTIVE
: WA_ACTIVE
,
148 Window
->style
& WS_MINIMIZE
),
154 co_IntSendKillFocusMessages(HWND hWndPrev
, HWND hWnd
)
158 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
159 co_IntPostOrSendMessage(hWndPrev
, WM_KILLFOCUS
, (WPARAM
)hWnd
, 0);
164 co_IntSendSetFocusMessages(HWND hWndPrev
, HWND hWnd
)
168 PWND pWnd
= UserGetWindowObject(hWnd
);
169 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
170 co_IntPostOrSendMessage(hWnd
, WM_SETFOCUS
, (WPARAM
)hWndPrev
, 0);
175 IntFindChildWindowToOwner(PWND Root
, PWND Owner
)
178 PWND Child
, OwnerWnd
;
180 for(Child
= Root
->spwndChild
; Child
; Child
= Child
->spwndNext
)
182 OwnerWnd
= Child
->spwndOwner
;
186 if(OwnerWnd
== Owner
)
198 The system restricts which processes can set the foreground window. A process
199 can set the foreground window only if one of the following conditions is true:
201 * The process is the foreground process.
202 * The process was started by the foreground process.
203 * The process received the last input event.
204 * There is no foreground process.
205 * The foreground process is being debugged.
206 * The foreground is not locked (see LockSetForegroundWindow).
207 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
208 * No menus are active.
211 co_IntSetForegroundAndFocusWindow(PWND Wnd
, PWND FocusWindow
, BOOL MouseActivate
)
213 CBTACTIVATESTRUCT cbt
;
214 HWND hWnd
= Wnd
->head
.h
;
215 HWND hWndPrev
= NULL
;
216 HWND hWndFocus
= FocusWindow
->head
.h
;
217 HWND hWndFocusPrev
= NULL
;
218 PUSER_MESSAGE_QUEUE PrevForegroundQueue
;
222 TRACE("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd
, hWndFocus
, MouseActivate
? "TRUE" : "FALSE");
224 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
226 TRACE("Failed - Child\n");
230 if (0 == (Wnd
->style
& WS_VISIBLE
) &&
231 Wnd
->head
.pti
->pEThread
->ThreadsProcess
!= CsrProcess
)
233 ERR("Failed - Invisible\n");
237 PrevForegroundQueue
= IntGetFocusMessageQueue();
238 if (PrevForegroundQueue
!= 0)
240 hWndPrev
= PrevForegroundQueue
->ActiveWindow
;
241 hWndFocusPrev
= PrevForegroundQueue
->FocusWindow
;
244 if (hWndPrev
== hWnd
)
246 TRACE("Failed - Same\n");
250 /* call CBT hook chain */
251 cbt
.fMouse
= MouseActivate
;
252 cbt
.hWndActive
= hWndPrev
;
253 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
255 ERR("IntSetForegroundAndFocusWindow WH_CBT Call Hook return!\n");
259 co_IntSendDeactivateMessages(hWndPrev
, hWnd
);
260 co_IntSendKillFocusMessages(hWndFocusPrev
, hWndFocus
);
263 IntSetFocusMessageQueue(Wnd
->head
.pti
->MessageQueue
);
265 if (Wnd
->head
.pti
->MessageQueue
)
267 Wnd
->head
.pti
->MessageQueue
->ActiveWindow
= hWnd
;
270 if (FocusWindow
->head
.pti
->MessageQueue
)
272 FocusWindow
->head
.pti
->MessageQueue
->FocusWindow
= hWndFocus
;
275 if (PrevForegroundQueue
!= Wnd
->head
.pti
->MessageQueue
)
277 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
280 co_IntSendSetFocusMessages(hWndFocusPrev
, hWndFocus
);
281 co_IntSendActivateMessages(hWndPrev
, hWnd
, MouseActivate
);
287 co_IntSetForegroundWindow(PWND Window
)//FIXME: can Window be NULL??
289 /*if (Window)*/ ASSERT_REFS_CO(Window
);
291 return co_IntSetForegroundAndFocusWindow(Window
, Window
, FALSE
);
295 co_IntMouseActivateWindow(PWND Wnd
)
299 USER_REFERENCE_ENTRY Ref
;
303 if(Wnd
->style
& WS_DISABLED
)
307 PWND DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
310 Top
= IntFindChildWindowToOwner(DesktopWindow
, Wnd
);
311 if((TopWnd
= UserGetWindowObject(Top
)))
313 UserRefObjectCo(TopWnd
, &Ref
);
314 Ret
= co_IntMouseActivateWindow(TopWnd
);
315 UserDerefObjectCo(TopWnd
);
324 TopWindow
= UserGetAncestor(Wnd
, GA_ROOT
);
325 if (!TopWindow
) return FALSE
;
327 /* TMN: Check return valud from this function? */
328 UserRefObjectCo(TopWindow
, &Ref
);
330 co_IntSetForegroundAndFocusWindow(TopWindow
, Wnd
, TRUE
);
332 UserDerefObjectCo(TopWindow
);
338 co_IntSetActiveWindow(PWND Wnd OPTIONAL
)
341 PUSER_MESSAGE_QUEUE ThreadQueue
;
344 CBTACTIVATESTRUCT cbt
;
349 pti
= PsGetCurrentThreadWin32Thread();
350 ThreadQueue
= pti
->MessageQueue
;
351 ASSERT(ThreadQueue
!= 0);
355 if ((Wnd
->style
& (WS_POPUP
| WS_CHILD
)) == WS_CHILD
)
357 /* Windows doesn't seem to return an error here */
358 return ThreadQueue
->ActiveWindow
;
363 hWndPrev
= ThreadQueue
->ActiveWindow
;
364 if (hWndPrev
== hWnd
)
369 /* call CBT hook chain */
371 cbt
.hWndActive
= hWndPrev
;
372 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
374 ERR("SetActiveWindow WH_CBT Call Hook return!\n");
378 co_IntSendDeactivateMessages(hWndPrev
, hWnd
);
380 ThreadQueue
->ActiveWindow
= hWnd
;
382 co_IntSendActivateMessages(hWndPrev
, hWnd
, FALSE
);
385 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
390 co_UserSetFocus(PWND Window
)
395 PUSER_MESSAGE_QUEUE ThreadQueue
;
398 ASSERT_REFS_CO(Window
);
400 pti
= PsGetCurrentThreadWin32Thread();
401 ThreadQueue
= pti
->MessageQueue
;
402 ASSERT(ThreadQueue
!= 0);
404 hWndPrev
= ThreadQueue
->FocusWindow
;
408 if (hWndPrev
== Window
->head
.h
)
410 return hWndPrev
; /* nothing to do */
413 /* Check if we can set the focus to this window */
414 for (pwndTop
= Window
; pwndTop
!= NULL
; pwndTop
= pwndTop
->spwndParent
)
416 if (pwndTop
->style
& (WS_MINIMIZED
|WS_DISABLED
)) return 0;
417 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
420 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)Window
->head
.h
, (LPARAM
)hWndPrev
))
422 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
426 /* activate pwndTop if needed. */
427 if (pwndTop
->head
.h
!= ThreadQueue
->ActiveWindow
)
429 co_IntSetActiveWindow(pwndTop
);
430 /* Abort if window destroyed */
431 if (Window
->state2
& WNDS2_INDESTROY
) return 0;
432 /* Do not change focus if the window is no longer active */
433 if (pwndTop
->head
.h
!= ThreadQueue
->ActiveWindow
)
435 ERR("SetFocus Top window did not go active!\n");
440 ThreadQueue
->FocusWindow
= Window
->head
.h
;
441 TRACE("Focus: %d -> %d\n", hWndPrev
, Window
->head
.h
);
443 co_IntSendKillFocusMessages(hWndPrev
, Window
->head
.h
);
444 co_IntSendSetFocusMessages(hWndPrev
, Window
->head
.h
);
448 ThreadQueue
->FocusWindow
= 0;
449 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)0, (LPARAM
)hWndPrev
))
451 ERR("SetFocusWindow 2 WH_CBT Call Hook return!\n");
455 co_IntSendKillFocusMessages(hWndPrev
, 0);
461 UserGetForegroundWindow(VOID
)
463 PUSER_MESSAGE_QUEUE ForegroundQueue
;
465 ForegroundQueue
= IntGetFocusMessageQueue();
466 return( ForegroundQueue
!= NULL
? ForegroundQueue
->ActiveWindow
: 0);
469 HWND FASTCALL
UserGetActiveWindow(VOID
)
472 PUSER_MESSAGE_QUEUE ThreadQueue
;
474 pti
= PsGetCurrentThreadWin32Thread();
475 ThreadQueue
= pti
->MessageQueue
;
476 return( ThreadQueue
? ThreadQueue
->ActiveWindow
: 0);
483 PUSER_MESSAGE_QUEUE ThreadQueue
;
484 DECLARE_RETURN(HWND
);
486 TRACE("Enter IntGetCapture\n");
488 pti
= PsGetCurrentThreadWin32Thread();
489 ThreadQueue
= pti
->MessageQueue
;
490 RETURN( ThreadQueue
? ThreadQueue
->CaptureWindow
: 0);
493 TRACE("Leave IntGetCapture, ret=%i\n",_ret_
);
498 co_UserSetCapture(HWND hWnd
)
501 PUSER_MESSAGE_QUEUE ThreadQueue
;
505 pti
= PsGetCurrentThreadWin32Thread();
506 ThreadQueue
= pti
->MessageQueue
;
508 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
)
511 if ((Window
= UserGetWindowObject(hWnd
)))
513 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
519 hWndPrev
= MsqSetStateWindow(ThreadQueue
, MSQ_STATE_CAPTURE
, hWnd
);
523 pWnd
= UserGetWindowObject(hWndPrev
);
525 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
529 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART
, Window
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
531 if (hWndPrev
&& hWndPrev
!= hWnd
)
533 if (ThreadQueue
->MenuOwner
&& Window
) ThreadQueue
->QF_flags
|= QF_CAPTURELOCKED
;
535 co_IntPostOrSendMessage(hWndPrev
, WM_CAPTURECHANGED
, 0, (LPARAM
)hWnd
);
537 ThreadQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
540 ThreadQueue
->CaptureWindow
= hWnd
;
542 if (hWnd
== NULL
) // Release mode.
546 /* also remove other windows if not capturing anymore */
547 MsqSetStateWindow(ThreadQueue
, MSQ_STATE_MENUOWNER
, NULL
);
548 MsqSetStateWindow(ThreadQueue
, MSQ_STATE_MOVESIZE
, NULL
);
550 /* Somebody may have missed some mouse movements */
554 mi
.dwFlags
= MOUSEEVENTF_MOVE
;
557 UserSendMouseInput(&mi
, FALSE
);
564 IntReleaseCapture(VOID
)
567 PUSER_MESSAGE_QUEUE ThreadQueue
;
569 pti
= PsGetCurrentThreadWin32Thread();
570 ThreadQueue
= pti
->MessageQueue
;
572 // Can not release inside WM_CAPTURECHANGED!!
573 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
) return FALSE
;
575 co_UserSetCapture(NULL
);
584 NtUserGetForegroundWindow(VOID
)
586 DECLARE_RETURN(HWND
);
588 TRACE("Enter NtUserGetForegroundWindow\n");
589 UserEnterExclusive();
591 RETURN( UserGetForegroundWindow());
594 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_
);
600 NtUserSetActiveWindow(HWND hWnd
)
602 USER_REFERENCE_ENTRY Ref
;
603 DECLARE_RETURN(HWND
);
605 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd
);
606 UserEnterExclusive();
612 PUSER_MESSAGE_QUEUE ThreadQueue
;
615 if (!(Window
= UserGetWindowObject(hWnd
)))
620 pti
= PsGetCurrentThreadWin32Thread();
621 ThreadQueue
= pti
->MessageQueue
;
623 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
625 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
629 UserRefObjectCo(Window
, &Ref
);
630 hWndPrev
= co_IntSetActiveWindow(Window
);
631 UserDerefObjectCo(Window
);
637 RETURN( co_IntSetActiveWindow(0));
641 TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_
);
650 NtUserSetCapture(HWND hWnd
)
652 DECLARE_RETURN(HWND
);
654 TRACE("Enter NtUserSetCapture(%x)\n", hWnd
);
655 UserEnterExclusive();
657 RETURN( co_UserSetCapture(hWnd
));
660 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_
);
669 NtUserSetFocus(HWND hWnd
)
672 USER_REFERENCE_ENTRY Ref
;
673 DECLARE_RETURN(HWND
);
676 TRACE("Enter NtUserSetFocus(%x)\n", hWnd
);
677 UserEnterExclusive();
681 if (!(Window
= UserGetWindowObject(hWnd
)))
686 UserRefObjectCo(Window
, &Ref
);
687 ret
= co_UserSetFocus(Window
);
688 UserDerefObjectCo(Window
);
694 RETURN( co_UserSetFocus(0));
698 TRACE("Leave NtUserSetFocus, ret=%i\n",_ret_
);