[Win32k]
[reactos.git] / reactos / win32ss / user / ntuser / focus.c
1 /*
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
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserFocus);
11
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;
18
19 /*
20 Check locking of a process or one or more menus are active.
21 */
22 BOOL FASTCALL
23 IsFGLocked(VOID)
24 {
25 return (gppiLockSFW || guSFWLockCount);
26 }
27
28 HWND FASTCALL
29 IntGetCaptureWindow(VOID)
30 {
31 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
32 return ForegroundQueue != NULL ? ForegroundQueue->CaptureWindow : 0;
33 }
34
35 HWND FASTCALL
36 IntGetThreadFocusWindow(VOID)
37 {
38 PTHREADINFO pti;
39 PUSER_MESSAGE_QUEUE ThreadQueue;
40
41 pti = PsGetCurrentThreadWin32Thread();
42 ThreadQueue = pti->MessageQueue;
43 if (!ThreadQueue)
44 return NULL;
45 return ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
46 }
47
48 VOID FASTCALL
49 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
50 {
51 PWND WndPrev ;
52
53 if (hWndPrev && (WndPrev = UserGetWindowObject(hWndPrev)))
54 {
55 co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0);
56 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
57 MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
58 (LPARAM)hWnd);
59 }
60 }
61
62 BOOL FASTCALL
63 co_IntMakeWindowActive(PWND Window)
64 {
65 PWND spwndOwner;
66 if (Window)
67 { // Set last active for window and it's owner.
68 Window->spwndLastActive = Window;
69 spwndOwner = Window->spwndOwner;
70 while (spwndOwner)
71 {
72 spwndOwner->spwndLastActive = Window;
73 spwndOwner = spwndOwner->spwndOwner;
74 }
75 return TRUE;
76 }
77 ERR("MakeWindowActive Failed!\n");
78 return FALSE;
79 }
80
81 VOID FASTCALL
82 co_IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
83 {
84 USER_REFERENCE_ENTRY Ref, RefPrev;
85 PWND Window, WindowPrev = NULL;
86 HANDLE OldTID, NewTID;
87 PTHREADINFO ptiOld, ptiNew;
88
89 if ((Window = UserGetWindowObject(hWnd)))
90 {
91 UserRefObjectCo(Window, &Ref);
92
93 WindowPrev = UserGetWindowObject(hWndPrev);
94
95 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
96
97 /* Send palette messages */
98 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
99 co_IntPostOrSendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0))
100 {
101 UserSendNotifyMessage( HWND_BROADCAST,
102 WM_PALETTEISCHANGING,
103 (WPARAM)hWnd,
104 0);
105 }
106
107 if (Window->spwndPrev != NULL)
108 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0,
109 SWP_NOSIZE | SWP_NOMOVE);
110
111 if (!Window->spwndOwner && !IntGetParent(Window))
112 {
113 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd);
114 }
115
116 if (Window)
117 {
118 Window->state |= WNDS_ACTIVEFRAME;
119
120 if (Window->style & WS_MINIMIZE)
121 {
122 TRACE("Widow was minimized\n");
123 }
124 }
125
126 if (WindowPrev)
127 WindowPrev->state &= ~WNDS_ACTIVEFRAME;
128
129 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
130 NewTID = Window ? IntGetWndThreadId(Window) : NULL;
131 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
132 ptiNew = Window ? Window->head.pti : NULL;
133
134 TRACE("SendActiveMessage Old -> %x, New -> %x\n", OldTID, NewTID);
135
136 if (OldTID != NewTID)
137 {
138 PWND cWindow;
139 HWND *List, *phWnd;
140
141 List = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
142 if ( List )
143 {
144 if ( OldTid )
145 {
146 for (phWnd = List; *phWnd; ++phWnd)
147 {
148 cWindow = UserGetWindowObject(*phWnd);
149 if (cWindow && cWindow->head.pti == ptiOld)
150 { // FALSE if the window is being deactivated,
151 // ThreadId that owns the window being activated.
152 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
153 }
154 }
155 }
156 if ( NewTID )
157 {
158 for (phWnd = List; *phWnd; ++phWnd)
159 {
160 cWindow = UserGetWindowObject(*phWnd);
161 if (cWindow && cWindow->head.pti == ptiNew)
162 { // TRUE if the window is being activated,
163 // ThreadId that owns the window being deactivated.
164 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
165 }
166 }
167 }
168 ExFreePool(List);
169 }
170 }
171 if (WindowPrev)
172 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
173
174 UserDerefObjectCo(Window);
175
176 /* FIXME: IntIsWindow */
177 co_IntSendMessageNoWait(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == UserGetForegroundWindow()), 0);
178 /* FIXME: WA_CLICKACTIVE */
179 co_IntSendMessageNoWait(hWnd, WM_ACTIVATE,
180 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE,
181 Window->style & WS_MINIMIZE),
182 (LPARAM)hWndPrev);
183 }
184 }
185
186 VOID FASTCALL
187 co_IntSendKillFocusMessages(HWND hWndPrev, HWND hWnd)
188 {
189 if (hWndPrev)
190 {
191 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
192 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
193 }
194 }
195
196 VOID FASTCALL
197 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
198 {
199 if (hWnd)
200 {
201 PWND pWnd = UserGetWindowObject(hWnd);
202 if (pWnd)
203 {
204 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
205 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
206 }
207 }
208 }
209
210 HWND FASTCALL
211 IntFindChildWindowToOwner(PWND Root, PWND Owner)
212 {
213 HWND Ret;
214 PWND Child, OwnerWnd;
215
216 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
217 {
218 OwnerWnd = Child->spwndOwner;
219 if(!OwnerWnd)
220 continue;
221
222 if(OwnerWnd == Owner)
223 {
224 Ret = Child->head.h;
225 return Ret;
226 }
227 }
228
229 return NULL;
230 }
231
232 /*
233 Can the system force foreground from one or more conditions.
234 */
235 BOOL FASTCALL
236 CanForceFG(PPROCESSINFO ppi)
237 {
238 if (!ptiLastInput ||
239 ptiLastInput->ppi == ppi ||
240 !gptiForeground ||
241 gptiForeground->ppi == ppi ||
242 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
243 gppiInputProvider == ppi ||
244 !gpqForeground
245 ) return TRUE;
246 return FALSE;
247 }
248
249 /*
250 MSDN:
251 The system restricts which processes can set the foreground window. A process
252 can set the foreground window only if one of the following conditions is true:
253
254 * The process is the foreground process.
255 * The process was started by the foreground process.
256 * The process received the last input event.
257 * There is no foreground process.
258 * The foreground process is being debugged.
259 * The foreground is not locked (see LockSetForegroundWindow).
260 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
261 * No menus are active.
262 */
263
264 static BOOL FASTCALL
265 co_IntSetForegroundAndFocusWindow(PWND Wnd, BOOL MouseActivate)
266 {
267 HWND hWnd = UserHMGetHandle(Wnd);
268 HWND hWndPrev = NULL;
269 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
270 PTHREADINFO pti;
271 BOOL fgRet = FALSE, Ret = FALSE;
272
273 ASSERT_REFS_CO(Wnd);
274
275 TRACE("SetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, MouseActivate ? "TRUE" : "FALSE");
276
277 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
278 pti = PsGetCurrentThreadWin32Thread();
279
280 if (PrevForegroundQueue)
281 { // Same Window Q as foreground just do active.
282 if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue)
283 {
284 if (pti->MessageQueue == PrevForegroundQueue)
285 { // Same WQ and TQ go active.
286 Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE);
287 }
288 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
289 { // Same WQ and it is active.
290 Ret = TRUE;
291 }
292 else
293 { // Same WQ as FG but not the same TQ send active.
294 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
295 Ret = TRUE;
296 }
297 return Ret;
298 }
299
300 hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0;
301 }
302
303 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
304 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
305 pti->ppi == ppiScrnSaver
306 )
307 {
308 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
309 gptiForeground = Wnd->head.pti;
310 fgRet = TRUE;
311 }
312 /*
313 Fix FG Bounce with regedit but breaks test_SFW todos:
314 Henri Verbeet,
315 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
316 other thread after we already changed the foreground window back to our own
317 window.
318 */
319 if (hWndPrev != hWnd )
320 {
321 if (PrevForegroundQueue &&
322 fgRet &&
323 Wnd->head.pti->MessageQueue != PrevForegroundQueue &&
324 PrevForegroundQueue->spwndActive)
325 {
326 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
327 if (pti->MessageQueue == PrevForegroundQueue)
328 {
329 //ERR("SFGW: TI same as Prev TI\n");
330 co_IntSetActiveWindow(NULL, NULL, FALSE, TRUE);
331 }
332 else
333 co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
334 }
335 }
336
337 if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
338 {
339 Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE);
340 }
341 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
342 {
343 Ret = TRUE;
344 }
345 else
346 {
347 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
348 Ret = TRUE;
349 }
350
351 return Ret && fgRet;
352 }
353
354 BOOL FASTCALL
355 co_IntMouseActivateWindow(PWND Wnd)
356 {
357 HWND Top;
358 PWND TopWindow;
359 USER_REFERENCE_ENTRY Ref;
360
361 ASSERT_REFS_CO(Wnd);
362
363 if (Wnd->style & WS_DISABLED)
364 {
365 BOOL Ret;
366 PWND TopWnd;
367 PWND DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
368 if (DesktopWindow)
369 {
370 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
371 if ((TopWnd = UserGetWindowObject(Top)))
372 {
373 UserRefObjectCo(TopWnd, &Ref);
374 Ret = co_IntMouseActivateWindow(TopWnd);
375 UserDerefObjectCo(TopWnd);
376
377 return Ret;
378 }
379 }
380 return FALSE;
381 }
382
383 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
384 if (!TopWindow) return FALSE;
385
386 /* TMN: Check return valud from this function? */
387 UserRefObjectCo(TopWindow, &Ref);
388
389 co_IntSetForegroundAndFocusWindow(TopWindow, TRUE);
390
391 UserDerefObjectCo(TopWindow);
392
393 return TRUE;
394 }
395
396 BOOL FASTCALL
397 co_IntSetActiveWindow(PWND Wnd OPTIONAL, HWND * Prev, BOOL bMouse, BOOL bFocus)
398 {
399 PTHREADINFO pti;
400 PUSER_MESSAGE_QUEUE ThreadQueue;
401 HWND hWndPrev;
402 HWND hWnd = 0;
403 CBTACTIVATESTRUCT cbt;
404
405 if (Wnd)
406 {
407 ASSERT_REFS_CO(Wnd);
408 hWnd = UserHMGetHandle(Wnd);
409 }
410
411 pti = PsGetCurrentThreadWin32Thread();
412 ThreadQueue = pti->MessageQueue;
413 ASSERT(ThreadQueue != 0);
414
415 hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
416 if (Prev) *Prev = hWndPrev;
417 if (hWndPrev == hWnd) return TRUE;
418
419 if (Wnd)
420 {
421 if (ThreadQueue != Wnd->head.pti->MessageQueue)
422 {
423 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
424 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
425 if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
426 {
427 return co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
428 }
429 }
430
431 if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
432 }
433
434 /* Call CBT hook chain */
435 cbt.fMouse = bMouse;
436 cbt.hWndActive = hWndPrev;
437 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
438 {
439 ERR("SetActiveWindow WH_CBT Call Hook return!\n");
440 return FALSE;
441 }
442
443 co_IntSendDeactivateMessages(hWndPrev, hWnd);
444
445 if (Wnd) Wnd->state |= WNDS_BEINGACTIVATED;
446
447 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
448
449 /* check if the specified window can be set in the input data of a given queue */
450 if ( !Wnd || ThreadQueue == Wnd->head.pti->MessageQueue)
451 {
452 /* set the current thread active window */
453 if (!Wnd || co_IntMakeWindowActive(Wnd))
454 {
455 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
456 ThreadQueue->spwndActive = Wnd;
457 }
458 }
459
460 co_IntSendActivateMessages(hWndPrev, hWnd, bMouse);
461
462 /* now change focus if necessary */
463 if (bFocus)
464 {
465 /* Do not change focus if the window is no longer active */
466 if (ThreadQueue->spwndActive == Wnd)
467 {
468 if (!ThreadQueue->spwndFocus ||
469 !Wnd ||
470 UserGetAncestor(ThreadQueue->spwndFocus, GA_ROOT) != Wnd)
471 {
472 co_UserSetFocus(Wnd);
473 }
474 }
475 }
476
477 if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
478 return TRUE;
479 }
480
481 HWND FASTCALL
482 co_UserSetFocus(PWND Window)
483 {
484 HWND hWndPrev = 0;
485 PWND pwndTop;
486 PTHREADINFO pti;
487 PUSER_MESSAGE_QUEUE ThreadQueue;
488
489 if (Window)
490 ASSERT_REFS_CO(Window);
491
492 pti = PsGetCurrentThreadWin32Thread();
493 ThreadQueue = pti->MessageQueue;
494 ASSERT(ThreadQueue != 0);
495
496 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
497
498 if (Window != 0)
499 {
500 if (hWndPrev == UserHMGetHandle(Window))
501 {
502 return hWndPrev; /* Nothing to do */
503 }
504
505 if (Window->head.pti->MessageQueue != ThreadQueue)
506 {
507 ERR("SetFocus Must have the same Q!\n");
508 return 0;
509 }
510
511 /* Check if we can set the focus to this window */
512 pwndTop = Window;
513 for (;;)
514 {
515 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
516 if (!pwndTop->spwndParent || pwndTop->spwndParent == UserGetDesktopWindow())
517 {
518 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
519 break;
520 }
521 if (pwndTop->spwndParent == UserGetMessageWindow()) return 0;
522 pwndTop = pwndTop->spwndParent;
523 }
524
525 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
526 {
527 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
528 return 0;
529 }
530
531 /* Activate pwndTop if needed. */
532 if (pwndTop != ThreadQueue->spwndActive)
533 {
534 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
535 if (ThreadQueue != ForegroundQueue) // HACK see rule 2 & 3.
536 {
537 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE))
538 {
539 ERR("SetFocus Set Foreground and Focus Failed!\n");
540 return 0;
541 }
542 }
543
544 /* Set Active when it is needed. */
545 if (pwndTop != ThreadQueue->spwndActive)
546 {
547 if (!co_IntSetActiveWindow(pwndTop, NULL, FALSE, FALSE))
548 {
549 ERR("SetFocus Set Active Failed!\n");
550 return 0;
551 }
552 }
553
554 /* Abort if window destroyed */
555 if (Window->state2 & WNDS2_INDESTROY) return 0;
556 /* Do not change focus if the window is no longer active */
557 if (pwndTop != ThreadQueue->spwndActive)
558 {
559 ERR("SetFocus Top window did not go active!\n");
560 return 0;
561 }
562 }
563
564 /* check if the specified window can be set in the input data of a given queue */
565 if ( !Window || ThreadQueue == Window->head.pti->MessageQueue)
566 /* set the current thread focus window */
567 ThreadQueue->spwndFocus = Window;
568
569 TRACE("Focus: %d -> %d\n", hWndPrev, Window->head.h);
570
571 co_IntSendKillFocusMessages(hWndPrev, Window->head.h);
572 co_IntSendSetFocusMessages(hWndPrev, Window->head.h);
573 }
574 else /* NULL hwnd passed in */
575 {
576 if (!hWndPrev) return 0; /* nothing to do */
577 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
578 {
579 ERR("SetFocusWindow 2 WH_CBT Call Hook return!\n");
580 return 0;
581 }
582
583 /* set the current thread focus window null */
584 ThreadQueue->spwndFocus = 0;
585
586 co_IntSendKillFocusMessages(hWndPrev, 0);
587 }
588 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
589 }
590
591 HWND FASTCALL
592 UserGetForegroundWindow(VOID)
593 {
594 PUSER_MESSAGE_QUEUE ForegroundQueue;
595
596 ForegroundQueue = IntGetFocusMessageQueue();
597 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
598 }
599
600 HWND FASTCALL UserGetActiveWindow(VOID)
601 {
602 PTHREADINFO pti;
603 PUSER_MESSAGE_QUEUE ThreadQueue;
604
605 pti = PsGetCurrentThreadWin32Thread();
606 ThreadQueue = pti->MessageQueue;
607 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
608 }
609
610 HWND APIENTRY
611 IntGetCapture(VOID)
612 {
613 PTHREADINFO pti;
614 PUSER_MESSAGE_QUEUE ThreadQueue;
615 DECLARE_RETURN(HWND);
616
617 TRACE("Enter IntGetCapture\n");
618
619 pti = PsGetCurrentThreadWin32Thread();
620 ThreadQueue = pti->MessageQueue;
621 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
622
623 CLEANUP:
624 TRACE("Leave IntGetCapture, ret=%i\n",_ret_);
625 END_CLEANUP;
626 }
627
628 HWND FASTCALL
629 co_UserSetCapture(HWND hWnd)
630 {
631 PTHREADINFO pti;
632 PUSER_MESSAGE_QUEUE ThreadQueue;
633 PWND Window, pWnd;
634 HWND hWndPrev;
635
636 pti = PsGetCurrentThreadWin32Thread();
637 ThreadQueue = pti->MessageQueue;
638
639 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
640 return NULL;
641
642 if ((Window = UserGetWindowObject(hWnd)))
643 {
644 if (Window->head.pti->MessageQueue != ThreadQueue)
645 {
646 return NULL;
647 }
648 }
649
650 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
651
652 if (hWndPrev)
653 {
654 pWnd = UserGetWindowObject(hWndPrev);
655 if (pWnd)
656 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
657 }
658
659 if (Window)
660 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
661
662 if (hWndPrev && hWndPrev != hWnd)
663 {
664 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
665
666 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
667
668 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
669 }
670
671 ThreadQueue->CaptureWindow = hWnd;
672
673 if (hWnd == NULL) // Release mode.
674 {
675 MOUSEINPUT mi;
676 /// These are HACKS!
677 /* Also remove other windows if not capturing anymore */
678 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
679 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
680 ///
681 /* Somebody may have missed some mouse movements */
682 mi.dx = 0;
683 mi.dy = 0;
684 mi.mouseData = 0;
685 mi.dwFlags = MOUSEEVENTF_MOVE;
686 mi.time = 0;
687 mi.dwExtraInfo = 0;
688 UserSendMouseInput(&mi, FALSE);
689 }
690 return hWndPrev;
691 }
692
693 /*
694 API Call
695 */
696 BOOL
697 FASTCALL
698 IntReleaseCapture(VOID)
699 {
700 PTHREADINFO pti;
701 PUSER_MESSAGE_QUEUE ThreadQueue;
702
703 pti = PsGetCurrentThreadWin32Thread();
704 ThreadQueue = pti->MessageQueue;
705
706 // Can not release inside WM_CAPTURECHANGED!!
707 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
708
709 co_UserSetCapture(NULL);
710
711 return TRUE;
712 }
713
714 /*
715 API Call
716 */
717 BOOL FASTCALL
718 co_IntSetForegroundWindow(PWND Window)
719 {
720 ASSERT_REFS_CO(Window);
721
722 return co_IntSetForegroundAndFocusWindow(Window, FALSE);
723 }
724
725 /*
726 API Call
727 */
728 BOOL FASTCALL
729 IntLockSetForegroundWindow(UINT uLockCode)
730 {
731 ULONG Err = ERROR_ACCESS_DENIED;
732 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
733 switch (uLockCode)
734 {
735 case LSFW_LOCK:
736 if ( CanForceFG(ppi) && !gppiLockSFW )
737 {
738 gppiLockSFW = ppi;
739 return TRUE;
740 }
741 break;
742 case LSFW_UNLOCK:
743 if ( gppiLockSFW == ppi)
744 {
745 gppiLockSFW = NULL;
746 return TRUE;
747 }
748 break;
749 default:
750 Err = ERROR_INVALID_PARAMETER;
751 }
752 EngSetLastError(Err);
753 return FALSE;
754 }
755
756 /*
757 API Call
758 */
759 BOOL FASTCALL
760 IntAllowSetForegroundWindow(DWORD dwProcessId)
761 {
762 PPROCESSINFO ppi, ppiCur;
763 PEPROCESS Process = NULL;
764
765 ppi = NULL;
766 if (dwProcessId != ASFW_ANY)
767 {
768 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)dwProcessId, &Process)))
769 {
770 EngSetLastError(ERROR_INVALID_PARAMETER);
771 return FALSE;
772 }
773 ppi = PsGetProcessWin32Process(Process);
774 if (!ppi)
775 {
776 ObDereferenceObject(Process);
777 return FALSE;
778 }
779 }
780 ppiCur = PsGetCurrentProcessWin32Process();
781 if (!CanForceFG(ppiCur))
782 {
783 if (Process) ObDereferenceObject(Process);
784 EngSetLastError(ERROR_ACCESS_DENIED);
785 return FALSE;
786 }
787 if (dwProcessId == ASFW_ANY)
788 { // All processes will be enabled to set the foreground window.
789 ptiLastInput = NULL;
790 }
791 else
792 { // Rule #3, last input event in force.
793 ptiLastInput = ppi->ptiList;
794 ObDereferenceObject(Process);
795 }
796 return TRUE;
797 }
798
799 /*
800 * @implemented
801 */
802 HWND APIENTRY
803 NtUserGetForegroundWindow(VOID)
804 {
805 DECLARE_RETURN(HWND);
806
807 TRACE("Enter NtUserGetForegroundWindow\n");
808 UserEnterExclusive();
809
810 RETURN( UserGetForegroundWindow());
811
812 CLEANUP:
813 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
814 UserLeave();
815 END_CLEANUP;
816 }
817
818 HWND APIENTRY
819 NtUserSetActiveWindow(HWND hWnd)
820 {
821 USER_REFERENCE_ENTRY Ref;
822 HWND hWndPrev;
823 PWND Window;
824 DECLARE_RETURN(HWND);
825
826 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd);
827 UserEnterExclusive();
828
829 Window = NULL;
830 if (hWnd)
831 {
832 if (!(Window = UserGetWindowObject(hWnd)))
833 {
834 RETURN( 0);
835 }
836 }
837
838 if (!Window ||
839 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
840 {
841 if (Window) UserRefObjectCo(Window, &Ref);
842 if (!co_IntSetActiveWindow(Window, &hWndPrev, FALSE, TRUE)) hWndPrev = NULL;
843 if (Window) UserDerefObjectCo(Window);
844 }
845 else
846 hWndPrev = NULL;
847
848 RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
849
850 CLEANUP:
851 TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
852 UserLeave();
853 END_CLEANUP;
854 }
855
856 /*
857 * @implemented
858 */
859 HWND APIENTRY
860 NtUserSetCapture(HWND hWnd)
861 {
862 DECLARE_RETURN(HWND);
863
864 TRACE("Enter NtUserSetCapture(%x)\n", hWnd);
865 UserEnterExclusive();
866
867 RETURN( co_UserSetCapture(hWnd));
868
869 CLEANUP:
870 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_);
871 UserLeave();
872 END_CLEANUP;
873 }
874
875 /*
876 * @implemented
877 */
878 HWND APIENTRY
879 NtUserSetFocus(HWND hWnd)
880 {
881 PWND Window;
882 USER_REFERENCE_ENTRY Ref;
883 DECLARE_RETURN(HWND);
884 HWND ret;
885
886 TRACE("Enter NtUserSetFocus(%x)\n", hWnd);
887 UserEnterExclusive();
888
889 if (hWnd)
890 {
891 if (!(Window = UserGetWindowObject(hWnd)))
892 {
893 RETURN(NULL);
894 }
895
896 UserRefObjectCo(Window, &Ref);
897 ret = co_UserSetFocus(Window);
898 UserDerefObjectCo(Window);
899
900 RETURN(ret);
901 }
902 else
903 {
904 RETURN( co_UserSetFocus(0));
905 }
906
907 CLEANUP:
908 TRACE("Leave NtUserSetFocus, ret=%i\n",_ret_);
909 UserLeave();
910 END_CLEANUP;
911 }
912
913 /* EOF */