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
;
16 IntGetCaptureWindow(VOID
)
18 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
19 return ForegroundQueue
!= NULL
? ForegroundQueue
->CaptureWindow
: 0;
23 UserGetFocusWindow(VOID
)
26 PUSER_MESSAGE_QUEUE ThreadQueue
;
28 pti
= PsGetCurrentThreadWin32Thread();
29 ThreadQueue
= pti
->MessageQueue
;
30 /* Is it a foreground queue? */
31 if (!ThreadQueue
|| ThreadQueue
!= IntGetFocusMessageQueue())
33 return ThreadQueue
->FocusWindow
;
37 IntGetThreadFocusWindow(VOID
)
40 PUSER_MESSAGE_QUEUE ThreadQueue
;
42 pti
= PsGetCurrentThreadWin32Thread();
43 ThreadQueue
= pti
->MessageQueue
;
46 return ThreadQueue
->FocusWindow
;
50 co_IntSendDeactivateMessages(HWND hWndPrev
, HWND hWnd
)
54 if (hWndPrev
&& (WndPrev
= UserGetWindowObject(hWndPrev
)))
56 co_IntSendMessageNoWait(hWndPrev
, WM_NCACTIVATE
, FALSE
, 0);
57 co_IntSendMessageNoWait(hWndPrev
, WM_ACTIVATE
,
58 MAKEWPARAM(WA_INACTIVE
, WndPrev
->style
& WS_MINIMIZE
),
64 co_IntSendActivateMessages(HWND hWndPrev
, HWND hWnd
, BOOL MouseActivate
)
66 USER_REFERENCE_ENTRY Ref
, RefPrev
;
67 PWND Window
, WindowPrev
= NULL
;
69 if ((Window
= UserGetWindowObject(hWnd
)))
71 UserRefObjectCo(Window
, &Ref
);
73 WindowPrev
= UserGetWindowObject(hWndPrev
);
75 if (WindowPrev
) UserRefObjectCo(WindowPrev
, &RefPrev
);
77 /* Send palette messages */
78 if (gpsi
->PUSIFlags
& PUSIF_PALETTEDISPLAY
&&
79 co_IntPostOrSendMessage(hWnd
, WM_QUERYNEWPALETTE
, 0, 0))
81 UserSendNotifyMessage( HWND_BROADCAST
,
87 if (Window
->spwndPrev
!= NULL
)
88 co_WinPosSetWindowPos(Window
, HWND_TOP
, 0, 0, 0, 0,
89 SWP_NOSIZE
| SWP_NOMOVE
);
91 if (!Window
->spwndOwner
&& !IntGetParent(Window
))
93 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED
, (LPARAM
) hWnd
);
97 { // Set last active for window and it's owner.
98 Window
->hWndLastActive
= hWnd
;
99 if (Window
->spwndOwner
)
100 Window
->spwndOwner
->hWndLastActive
= hWnd
;
101 Window
->state
|= WNDS_ACTIVEFRAME
;
105 WindowPrev
->state
&= ~WNDS_ACTIVEFRAME
;
107 if (Window
&& WindowPrev
)
111 HANDLE OldTID
= IntGetWndThreadId(WindowPrev
);
112 HANDLE NewTID
= IntGetWndThreadId(Window
);
114 TRACE("SendActiveMessage Old -> %x, New -> %x\n", OldTID
, NewTID
);
115 if (Window
->style
& WS_MINIMIZE
)
117 TRACE("Widow was minimized\n");
120 if (OldTID
!= NewTID
)
122 List
= IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
125 for (phWnd
= List
; *phWnd
; ++phWnd
)
127 cWindow
= UserGetWindowObject(*phWnd
);
129 if (cWindow
&& (IntGetWndThreadId(cWindow
) == OldTID
))
130 { // FALSE if the window is being deactivated,
131 // ThreadId that owns the window being activated.
132 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, FALSE
, (LPARAM
)NewTID
);
135 for (phWnd
= List
; *phWnd
; ++phWnd
)
137 cWindow
= UserGetWindowObject(*phWnd
);
138 if (cWindow
&& (IntGetWndThreadId(cWindow
) == NewTID
))
139 { // TRUE if the window is being activated,
140 // ThreadId that owns the window being deactivated.
141 co_IntSendMessageNoWait(*phWnd
, WM_ACTIVATEAPP
, TRUE
, (LPARAM
)OldTID
);
147 UserDerefObjectCo(WindowPrev
); // Now allow the previous window to die.
150 UserDerefObjectCo(Window
);
152 /* FIXME: IntIsWindow */
153 co_IntSendMessageNoWait(hWnd
, WM_NCACTIVATE
, (WPARAM
)(hWnd
== UserGetForegroundWindow()), 0);
154 /* FIXME: WA_CLICKACTIVE */
155 co_IntSendMessageNoWait(hWnd
, WM_ACTIVATE
,
156 MAKEWPARAM(MouseActivate
? WA_CLICKACTIVE
: WA_ACTIVE
,
157 Window
->style
& WS_MINIMIZE
),
163 co_IntSendKillFocusMessages(HWND hWndPrev
, HWND hWnd
)
167 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, NULL
, OBJID_CLIENT
, CHILDID_SELF
, 0);
168 co_IntPostOrSendMessage(hWndPrev
, WM_KILLFOCUS
, (WPARAM
)hWnd
, 0);
173 co_IntSendSetFocusMessages(HWND hWndPrev
, HWND hWnd
)
177 PWND pWnd
= UserGetWindowObject(hWnd
);
178 IntNotifyWinEvent(EVENT_OBJECT_FOCUS
, pWnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
179 co_IntPostOrSendMessage(hWnd
, WM_SETFOCUS
, (WPARAM
)hWndPrev
, 0);
184 IntFindChildWindowToOwner(PWND Root
, PWND Owner
)
187 PWND Child
, OwnerWnd
;
189 for(Child
= Root
->spwndChild
; Child
; Child
= Child
->spwndNext
)
191 OwnerWnd
= Child
->spwndOwner
;
195 if(OwnerWnd
== Owner
)
207 The system restricts which processes can set the foreground window. A process
208 can set the foreground window only if one of the following conditions is true:
210 * The process is the foreground process.
211 * The process was started by the foreground process.
212 * The process received the last input event.
213 * There is no foreground process.
214 * The foreground process is being debugged.
215 * The foreground is not locked (see LockSetForegroundWindow).
216 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
217 * No menus are active.
220 co_IntSetForegroundAndFocusWindow(PWND Wnd
, PWND FocusWindow
, BOOL MouseActivate
)
222 CBTACTIVATESTRUCT cbt
;
223 HWND hWnd
= Wnd
->head
.h
;
224 HWND hWndPrev
= NULL
;
225 HWND hWndFocus
= FocusWindow
->head
.h
;
226 HWND hWndFocusPrev
= NULL
;
227 PUSER_MESSAGE_QUEUE PrevForegroundQueue
;
231 TRACE("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd
, hWndFocus
, MouseActivate
? "TRUE" : "FALSE");
233 if ((Wnd
->style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
235 TRACE("Failed - Child\n");
239 if (0 == (Wnd
->style
& WS_VISIBLE
) &&
240 Wnd
->head
.pti
->pEThread
->ThreadsProcess
!= CsrProcess
)
242 ERR("Failed - Invisible\n");
246 PrevForegroundQueue
= IntGetFocusMessageQueue();
247 if (PrevForegroundQueue
!= 0)
249 hWndPrev
= PrevForegroundQueue
->ActiveWindow
;
250 hWndFocusPrev
= PrevForegroundQueue
->FocusWindow
;
253 if (hWndPrev
== hWnd
)
255 TRACE("Failed - Same\n");
259 /* Call CBT hook chain */
260 cbt
.fMouse
= MouseActivate
;
261 cbt
.hWndActive
= hWndPrev
;
262 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
264 ERR("IntSetForegroundAndFocusWindow WH_CBT Call Hook return!\n");
268 co_IntSendDeactivateMessages(hWndPrev
, hWnd
);
269 co_IntSendKillFocusMessages(hWndFocusPrev
, hWndFocus
);
272 IntSetFocusMessageQueue(Wnd
->head
.pti
->MessageQueue
);
274 if (Wnd
->head
.pti
->MessageQueue
)
276 Wnd
->head
.pti
->MessageQueue
->ActiveWindow
= hWnd
;
279 if (FocusWindow
->head
.pti
->MessageQueue
)
281 FocusWindow
->head
.pti
->MessageQueue
->FocusWindow
= hWndFocus
;
284 if (PrevForegroundQueue
!= Wnd
->head
.pti
->MessageQueue
)
286 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
289 co_IntSendSetFocusMessages(hWndFocusPrev
, hWndFocus
);
290 co_IntSendActivateMessages(hWndPrev
, hWnd
, MouseActivate
);
296 co_IntSetForegroundWindow(PWND Window
) // FIXME: Can Window be NULL??
298 /*if (Window)*/ ASSERT_REFS_CO(Window
);
300 return co_IntSetForegroundAndFocusWindow(Window
, Window
, FALSE
);
304 co_IntMouseActivateWindow(PWND Wnd
)
308 USER_REFERENCE_ENTRY Ref
;
312 if(Wnd
->style
& WS_DISABLED
)
316 PWND DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
319 Top
= IntFindChildWindowToOwner(DesktopWindow
, Wnd
);
320 if((TopWnd
= UserGetWindowObject(Top
)))
322 UserRefObjectCo(TopWnd
, &Ref
);
323 Ret
= co_IntMouseActivateWindow(TopWnd
);
324 UserDerefObjectCo(TopWnd
);
333 TopWindow
= UserGetAncestor(Wnd
, GA_ROOT
);
334 if (!TopWindow
) return FALSE
;
336 /* TMN: Check return valud from this function? */
337 UserRefObjectCo(TopWindow
, &Ref
);
339 co_IntSetForegroundAndFocusWindow(TopWindow
, Wnd
, TRUE
);
341 UserDerefObjectCo(TopWindow
);
347 co_IntSetActiveWindow(PWND Wnd OPTIONAL
)
350 PUSER_MESSAGE_QUEUE ThreadQueue
;
353 CBTACTIVATESTRUCT cbt
;
358 pti
= PsGetCurrentThreadWin32Thread();
359 ThreadQueue
= pti
->MessageQueue
;
360 ASSERT(ThreadQueue
!= 0);
364 if ((Wnd
->style
& (WS_POPUP
| WS_CHILD
)) == WS_CHILD
)
366 /* Windows doesn't seem to return an error here */
367 return ThreadQueue
->ActiveWindow
;
372 hWndPrev
= ThreadQueue
->ActiveWindow
;
373 if (hWndPrev
== hWnd
)
378 /* Call CBT hook chain */
380 cbt
.hWndActive
= hWndPrev
;
381 if (co_HOOK_CallHooks( WH_CBT
, HCBT_ACTIVATE
, (WPARAM
)hWnd
, (LPARAM
)&cbt
))
383 ERR("SetActiveWindow WH_CBT Call Hook return!\n");
387 co_IntSendDeactivateMessages(hWndPrev
, hWnd
);
389 ThreadQueue
->ActiveWindow
= hWnd
;
391 co_IntSendActivateMessages(hWndPrev
, hWnd
, FALSE
);
394 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
399 co_UserSetFocus(PWND Window
)
404 PUSER_MESSAGE_QUEUE ThreadQueue
;
407 ASSERT_REFS_CO(Window
);
409 pti
= PsGetCurrentThreadWin32Thread();
410 ThreadQueue
= pti
->MessageQueue
;
411 ASSERT(ThreadQueue
!= 0);
413 hWndPrev
= ThreadQueue
->FocusWindow
;
417 if (hWndPrev
== Window
->head
.h
)
419 return hWndPrev
; /* Nothing to do */
422 /* Check if we can set the focus to this window */
423 for (pwndTop
= Window
; pwndTop
!= NULL
; pwndTop
= pwndTop
->spwndParent
)
425 if (pwndTop
->style
& (WS_MINIMIZED
|WS_DISABLED
)) return 0;
426 if ((pwndTop
->style
& (WS_POPUP
|WS_CHILD
)) != WS_CHILD
) break;
429 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)Window
->head
.h
, (LPARAM
)hWndPrev
))
431 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
435 /* Activate pwndTop if needed. */
436 if (pwndTop
->head
.h
!= ThreadQueue
->ActiveWindow
)
438 co_IntSetActiveWindow(pwndTop
);
439 /* Abort if window destroyed */
440 if (Window
->state2
& WNDS2_INDESTROY
) return 0;
441 /* Do not change focus if the window is no longer active */
442 if (pwndTop
->head
.h
!= ThreadQueue
->ActiveWindow
)
444 ERR("SetFocus Top window did not go active!\n");
449 ThreadQueue
->FocusWindow
= Window
->head
.h
;
450 TRACE("Focus: %d -> %d\n", hWndPrev
, Window
->head
.h
);
452 co_IntSendKillFocusMessages(hWndPrev
, Window
->head
.h
);
453 co_IntSendSetFocusMessages(hWndPrev
, Window
->head
.h
);
457 ThreadQueue
->FocusWindow
= 0;
458 if (co_HOOK_CallHooks( WH_CBT
, HCBT_SETFOCUS
, (WPARAM
)0, (LPARAM
)hWndPrev
))
460 ERR("SetFocusWindow 2 WH_CBT Call Hook return!\n");
464 co_IntSendKillFocusMessages(hWndPrev
, 0);
470 UserGetForegroundWindow(VOID
)
472 PUSER_MESSAGE_QUEUE ForegroundQueue
;
474 ForegroundQueue
= IntGetFocusMessageQueue();
475 return( ForegroundQueue
!= NULL
? ForegroundQueue
->ActiveWindow
: 0);
478 HWND FASTCALL
UserGetActiveWindow(VOID
)
481 PUSER_MESSAGE_QUEUE ThreadQueue
;
483 pti
= PsGetCurrentThreadWin32Thread();
484 ThreadQueue
= pti
->MessageQueue
;
485 return( ThreadQueue
? ThreadQueue
->ActiveWindow
: 0);
492 PUSER_MESSAGE_QUEUE ThreadQueue
;
493 DECLARE_RETURN(HWND
);
495 TRACE("Enter IntGetCapture\n");
497 pti
= PsGetCurrentThreadWin32Thread();
498 ThreadQueue
= pti
->MessageQueue
;
499 RETURN( ThreadQueue
? ThreadQueue
->CaptureWindow
: 0);
502 TRACE("Leave IntGetCapture, ret=%i\n",_ret_
);
507 co_UserSetCapture(HWND hWnd
)
510 PUSER_MESSAGE_QUEUE ThreadQueue
;
514 pti
= PsGetCurrentThreadWin32Thread();
515 ThreadQueue
= pti
->MessageQueue
;
517 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
)
520 if ((Window
= UserGetWindowObject(hWnd
)))
522 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
528 hWndPrev
= MsqSetStateWindow(ThreadQueue
, MSQ_STATE_CAPTURE
, hWnd
);
532 pWnd
= UserGetWindowObject(hWndPrev
);
534 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND
, pWnd
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
538 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART
, Window
, OBJID_WINDOW
, CHILDID_SELF
, WEF_SETBYWNDPTI
);
540 if (hWndPrev
&& hWndPrev
!= hWnd
)
542 if (ThreadQueue
->MenuOwner
&& Window
) ThreadQueue
->QF_flags
|= QF_CAPTURELOCKED
;
544 co_IntPostOrSendMessage(hWndPrev
, WM_CAPTURECHANGED
, 0, (LPARAM
)hWnd
);
546 ThreadQueue
->QF_flags
&= ~QF_CAPTURELOCKED
;
549 ThreadQueue
->CaptureWindow
= hWnd
;
551 if (hWnd
== NULL
) // Release mode.
555 /* Also remove other windows if not capturing anymore */
556 MsqSetStateWindow(ThreadQueue
, MSQ_STATE_MENUOWNER
, NULL
);
557 MsqSetStateWindow(ThreadQueue
, MSQ_STATE_MOVESIZE
, NULL
);
559 /* Somebody may have missed some mouse movements */
563 mi
.dwFlags
= MOUSEEVENTF_MOVE
;
566 UserSendMouseInput(&mi
, FALSE
);
573 IntReleaseCapture(VOID
)
576 PUSER_MESSAGE_QUEUE ThreadQueue
;
578 pti
= PsGetCurrentThreadWin32Thread();
579 ThreadQueue
= pti
->MessageQueue
;
581 // Can not release inside WM_CAPTURECHANGED!!
582 if (ThreadQueue
->QF_flags
& QF_CAPTURELOCKED
) return FALSE
;
584 co_UserSetCapture(NULL
);
593 NtUserGetForegroundWindow(VOID
)
595 DECLARE_RETURN(HWND
);
597 TRACE("Enter NtUserGetForegroundWindow\n");
598 UserEnterExclusive();
600 RETURN( UserGetForegroundWindow());
603 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_
);
609 NtUserSetActiveWindow(HWND hWnd
)
611 USER_REFERENCE_ENTRY Ref
;
612 DECLARE_RETURN(HWND
);
614 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd
);
615 UserEnterExclusive();
621 PUSER_MESSAGE_QUEUE ThreadQueue
;
624 if (!(Window
= UserGetWindowObject(hWnd
)))
629 pti
= PsGetCurrentThreadWin32Thread();
630 ThreadQueue
= pti
->MessageQueue
;
632 if (Window
->head
.pti
->MessageQueue
!= ThreadQueue
)
634 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
638 UserRefObjectCo(Window
, &Ref
);
639 hWndPrev
= co_IntSetActiveWindow(Window
);
640 UserDerefObjectCo(Window
);
646 RETURN( co_IntSetActiveWindow(0));
650 TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_
);
659 NtUserSetCapture(HWND hWnd
)
661 DECLARE_RETURN(HWND
);
663 TRACE("Enter NtUserSetCapture(%x)\n", hWnd
);
664 UserEnterExclusive();
666 RETURN( co_UserSetCapture(hWnd
));
669 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_
);
678 NtUserSetFocus(HWND hWnd
)
681 USER_REFERENCE_ENTRY Ref
;
682 DECLARE_RETURN(HWND
);
685 TRACE("Enter NtUserSetFocus(%x)\n", hWnd
);
686 UserEnterExclusive();
690 if (!(Window
= UserGetWindowObject(hWnd
)))
695 UserRefObjectCo(Window
, &Ref
);
696 ret
= co_UserSetFocus(Window
);
697 UserDerefObjectCo(Window
);
703 RETURN( co_UserSetFocus(0));
707 TRACE("Leave NtUserSetFocus, ret=%i\n",_ret_
);