[SAMLIB][SAMSRV]
[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 VOID FASTCALL
233 FindRemoveAsyncMsg(PWND Wnd)
234 {
235 PUSER_MESSAGE_QUEUE MessageQueue;
236 PUSER_SENT_MESSAGE Message;
237 PLIST_ENTRY Entry;
238
239 if (!Wnd) return;
240
241 MessageQueue = Wnd->head.pti->MessageQueue;
242
243 if (!IsListEmpty(&MessageQueue->SentMessagesListHead))
244 {
245 // Scan sent queue messages to see if we received async messages.
246 Entry = MessageQueue->SentMessagesListHead.Flink;
247 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
248 do
249 {
250 if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
251 Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
252 Message->Msg.wParam == 0 )
253 {
254 TRACE("ASYNC SAW: Found one in the Sent Msg Queue! %p\n", Message->Msg.hwnd);
255 RemoveEntryList(Entry); // Purge the entry.
256 }
257 Entry = Message->ListEntry.Flink;
258 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
259 }
260 while (Entry != &MessageQueue->SentMessagesListHead);
261 }
262 }
263
264 /*
265 Can the system force foreground from one or more conditions.
266 */
267 BOOL FASTCALL
268 CanForceFG(PPROCESSINFO ppi)
269 {
270 if (!ptiLastInput ||
271 ptiLastInput->ppi == ppi ||
272 !gptiForeground ||
273 gptiForeground->ppi == ppi ||
274 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
275 gppiInputProvider == ppi ||
276 !gpqForeground
277 ) return TRUE;
278 return FALSE;
279 }
280
281 /*
282 MSDN:
283 The system restricts which processes can set the foreground window. A process
284 can set the foreground window only if one of the following conditions is true:
285
286 * The process is the foreground process.
287 * The process was started by the foreground process.
288 * The process received the last input event.
289 * There is no foreground process.
290 * The foreground process is being debugged.
291 * The foreground is not locked (see LockSetForegroundWindow).
292 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
293 * No menus are active.
294 */
295
296 static BOOL FASTCALL
297 co_IntSetForegroundAndFocusWindow(PWND Wnd, BOOL MouseActivate)
298 {
299 HWND hWnd = UserHMGetHandle(Wnd);
300 HWND hWndPrev = NULL;
301 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
302 PTHREADINFO pti;
303 BOOL fgRet = FALSE, Ret = FALSE;
304
305 ASSERT_REFS_CO(Wnd);
306
307 TRACE("SetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, MouseActivate ? "TRUE" : "FALSE");
308
309 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
310 pti = PsGetCurrentThreadWin32Thread();
311
312 if (PrevForegroundQueue)
313 { // Same Window Q as foreground just do active.
314 if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue)
315 {
316 if (pti->MessageQueue == PrevForegroundQueue)
317 { // Same WQ and TQ go active.
318 Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE);
319 }
320 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
321 { // Same WQ and it is active.
322 Ret = TRUE;
323 }
324 else
325 { // Same WQ as FG but not the same TQ send active.
326 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
327 Ret = TRUE;
328 }
329 return Ret;
330 }
331
332 hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0;
333 }
334
335 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
336 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
337 pti->ppi == ppiScrnSaver
338 )
339 {
340 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
341 gptiForeground = Wnd->head.pti;
342 /*
343 Henri Verbeet,
344 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
345 other thread after we already changed the foreground window back to our own
346 window.
347 */
348 FindRemoveAsyncMsg(Wnd); // Do this to fix test_SFW todos!
349 fgRet = TRUE;
350 }
351
352 // Fix FG Bounce with regedit.
353 if (hWndPrev != hWnd )
354 {
355 if (PrevForegroundQueue &&
356 fgRet &&
357 Wnd->head.pti->MessageQueue != PrevForegroundQueue &&
358 PrevForegroundQueue->spwndActive)
359 {
360 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
361 if (pti->MessageQueue == PrevForegroundQueue)
362 {
363 //ERR("SFGW: TI same as Prev TI\n");
364 co_IntSetActiveWindow(NULL, NULL, FALSE, TRUE);
365 }
366 else
367 co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
368 }
369 }
370
371 if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
372 {
373 Ret = co_IntSetActiveWindow(Wnd, NULL, MouseActivate, TRUE);
374 }
375 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
376 {
377 Ret = TRUE;
378 }
379 else
380 {
381 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
382 Ret = TRUE;
383 }
384
385 return Ret && fgRet;
386 }
387
388 BOOL FASTCALL
389 co_IntMouseActivateWindow(PWND Wnd)
390 {
391 HWND Top;
392 PWND TopWindow;
393 USER_REFERENCE_ENTRY Ref;
394
395 ASSERT_REFS_CO(Wnd);
396
397 if (Wnd->style & WS_DISABLED)
398 {
399 BOOL Ret;
400 PWND TopWnd;
401 PWND DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
402 if (DesktopWindow)
403 {
404 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
405 if ((TopWnd = UserGetWindowObject(Top)))
406 {
407 UserRefObjectCo(TopWnd, &Ref);
408 Ret = co_IntMouseActivateWindow(TopWnd);
409 UserDerefObjectCo(TopWnd);
410
411 return Ret;
412 }
413 }
414 return FALSE;
415 }
416
417 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
418 if (!TopWindow) return FALSE;
419
420 /* TMN: Check return valud from this function? */
421 UserRefObjectCo(TopWindow, &Ref);
422
423 co_IntSetForegroundAndFocusWindow(TopWindow, TRUE);
424
425 UserDerefObjectCo(TopWindow);
426
427 return TRUE;
428 }
429
430 BOOL FASTCALL
431 co_IntSetActiveWindow(PWND Wnd OPTIONAL, HWND * Prev, BOOL bMouse, BOOL bFocus)
432 {
433 PTHREADINFO pti;
434 PUSER_MESSAGE_QUEUE ThreadQueue;
435 HWND hWndPrev;
436 HWND hWnd = 0;
437 CBTACTIVATESTRUCT cbt;
438
439 if (Wnd)
440 {
441 ASSERT_REFS_CO(Wnd);
442 hWnd = UserHMGetHandle(Wnd);
443 }
444
445 pti = PsGetCurrentThreadWin32Thread();
446 ThreadQueue = pti->MessageQueue;
447 ASSERT(ThreadQueue != 0);
448
449 hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
450 if (Prev) *Prev = hWndPrev;
451 if (hWndPrev == hWnd) return TRUE;
452
453 if (Wnd)
454 {
455 if (ThreadQueue != Wnd->head.pti->MessageQueue)
456 {
457 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
458 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
459 if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
460 {
461 return co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
462 }
463 }
464
465 if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
466 }
467
468 /* Call CBT hook chain */
469 cbt.fMouse = bMouse;
470 cbt.hWndActive = hWndPrev;
471 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
472 {
473 ERR("SetActiveWindow WH_CBT Call Hook return!\n");
474 return FALSE;
475 }
476
477 co_IntSendDeactivateMessages(hWndPrev, hWnd);
478
479 if (Wnd) Wnd->state |= WNDS_BEINGACTIVATED;
480
481 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
482
483 /* check if the specified window can be set in the input data of a given queue */
484 if ( !Wnd || ThreadQueue == Wnd->head.pti->MessageQueue)
485 {
486 /* set the current thread active window */
487 if (!Wnd || co_IntMakeWindowActive(Wnd))
488 {
489 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
490 ThreadQueue->spwndActive = Wnd;
491 }
492 }
493
494 co_IntSendActivateMessages(hWndPrev, hWnd, bMouse);
495
496 /* now change focus if necessary */
497 if (bFocus)
498 {
499 /* Do not change focus if the window is no longer active */
500 if (ThreadQueue->spwndActive == Wnd)
501 {
502 if (!ThreadQueue->spwndFocus ||
503 !Wnd ||
504 UserGetAncestor(ThreadQueue->spwndFocus, GA_ROOT) != Wnd)
505 {
506 co_UserSetFocus(Wnd);
507 }
508 }
509 }
510
511 if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
512 return TRUE;
513 }
514
515 HWND FASTCALL
516 co_UserSetFocus(PWND Window)
517 {
518 HWND hWndPrev = 0;
519 PWND pwndTop;
520 PTHREADINFO pti;
521 PUSER_MESSAGE_QUEUE ThreadQueue;
522
523 if (Window)
524 ASSERT_REFS_CO(Window);
525
526 pti = PsGetCurrentThreadWin32Thread();
527 ThreadQueue = pti->MessageQueue;
528 ASSERT(ThreadQueue != 0);
529
530 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
531
532 if (Window != 0)
533 {
534 if (hWndPrev == UserHMGetHandle(Window))
535 {
536 return hWndPrev; /* Nothing to do */
537 }
538
539 if (Window->head.pti->MessageQueue != ThreadQueue)
540 {
541 ERR("SetFocus Must have the same Q!\n");
542 return 0;
543 }
544
545 /* Check if we can set the focus to this window */
546 pwndTop = Window;
547 for (;;)
548 {
549 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
550 if (!pwndTop->spwndParent || pwndTop->spwndParent == UserGetDesktopWindow())
551 {
552 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return 0;
553 break;
554 }
555 if (pwndTop->spwndParent == UserGetMessageWindow()) return 0;
556 pwndTop = pwndTop->spwndParent;
557 }
558
559 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
560 {
561 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
562 return 0;
563 }
564
565 /* Activate pwndTop if needed. */
566 if (pwndTop != ThreadQueue->spwndActive)
567 {
568 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
569 if (ThreadQueue != ForegroundQueue) // HACK see rule 2 & 3.
570 {
571 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE))
572 {
573 ERR("SetFocus Set Foreground and Focus Failed!\n");
574 return 0;
575 }
576 }
577
578 /* Set Active when it is needed. */
579 if (pwndTop != ThreadQueue->spwndActive)
580 {
581 if (!co_IntSetActiveWindow(pwndTop, NULL, FALSE, FALSE))
582 {
583 ERR("SetFocus Set Active Failed!\n");
584 return 0;
585 }
586 }
587
588 /* Abort if window destroyed */
589 if (Window->state2 & WNDS2_INDESTROY) return 0;
590 /* Do not change focus if the window is no longer active */
591 if (pwndTop != ThreadQueue->spwndActive)
592 {
593 ERR("SetFocus Top window did not go active!\n");
594 return 0;
595 }
596 }
597
598 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
599 if (ThreadQueue->spwndFocus && ThreadQueue->spwndFocus == Window)
600 {
601 hWndPrev = UserHMGetHandle(ThreadQueue->spwndFocus);
602 }
603
604 /* check if the specified window can be set in the input data of a given queue */
605 if (ThreadQueue == Window->head.pti->MessageQueue)
606 /* set the current thread focus window */
607 ThreadQueue->spwndFocus = Window;
608
609 TRACE("Focus: %d -> %d\n", hWndPrev, Window->head.h);
610
611 co_IntSendKillFocusMessages(hWndPrev, Window->head.h);
612 co_IntSendSetFocusMessages(hWndPrev, Window->head.h);
613 }
614 else /* NULL hwnd passed in */
615 {
616 if (!hWndPrev) return 0; /* nothing to do */
617 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
618 {
619 ERR("SetFocusWindow 2 WH_CBT Call Hook return!\n");
620 return 0;
621 }
622
623 /* set the current thread focus window null */
624 ThreadQueue->spwndFocus = 0;
625
626 co_IntSendKillFocusMessages(hWndPrev, 0);
627 }
628 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
629 }
630
631 HWND FASTCALL
632 UserGetForegroundWindow(VOID)
633 {
634 PUSER_MESSAGE_QUEUE ForegroundQueue;
635
636 ForegroundQueue = IntGetFocusMessageQueue();
637 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
638 }
639
640 HWND FASTCALL UserGetActiveWindow(VOID)
641 {
642 PTHREADINFO pti;
643 PUSER_MESSAGE_QUEUE ThreadQueue;
644
645 pti = PsGetCurrentThreadWin32Thread();
646 ThreadQueue = pti->MessageQueue;
647 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
648 }
649
650 HWND APIENTRY
651 IntGetCapture(VOID)
652 {
653 PTHREADINFO pti;
654 PUSER_MESSAGE_QUEUE ThreadQueue;
655 DECLARE_RETURN(HWND);
656
657 TRACE("Enter IntGetCapture\n");
658
659 pti = PsGetCurrentThreadWin32Thread();
660 ThreadQueue = pti->MessageQueue;
661 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
662
663 CLEANUP:
664 TRACE("Leave IntGetCapture, ret=%i\n",_ret_);
665 END_CLEANUP;
666 }
667
668 HWND FASTCALL
669 co_UserSetCapture(HWND hWnd)
670 {
671 PTHREADINFO pti;
672 PUSER_MESSAGE_QUEUE ThreadQueue;
673 PWND Window, pWnd;
674 HWND hWndPrev;
675
676 pti = PsGetCurrentThreadWin32Thread();
677 ThreadQueue = pti->MessageQueue;
678
679 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
680 return NULL;
681
682 if ((Window = UserGetWindowObject(hWnd)))
683 {
684 if (Window->head.pti->MessageQueue != ThreadQueue)
685 {
686 return NULL;
687 }
688 }
689
690 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
691
692 if (hWndPrev)
693 {
694 pWnd = UserGetWindowObject(hWndPrev);
695 if (pWnd)
696 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
697 }
698
699 if (Window)
700 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
701
702 if (hWndPrev && hWndPrev != hWnd)
703 {
704 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
705
706 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
707
708 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
709 }
710
711 ThreadQueue->CaptureWindow = hWnd;
712
713 if (hWnd == NULL) // Release mode.
714 {
715 MOUSEINPUT mi;
716 /// These are HACKS!
717 /* Also remove other windows if not capturing anymore */
718 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
719 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
720 ///
721 /* Somebody may have missed some mouse movements */
722 mi.dx = 0;
723 mi.dy = 0;
724 mi.mouseData = 0;
725 mi.dwFlags = MOUSEEVENTF_MOVE;
726 mi.time = 0;
727 mi.dwExtraInfo = 0;
728 UserSendMouseInput(&mi, FALSE);
729 }
730 return hWndPrev;
731 }
732
733 /*
734 API Call
735 */
736 BOOL
737 FASTCALL
738 IntReleaseCapture(VOID)
739 {
740 PTHREADINFO pti;
741 PUSER_MESSAGE_QUEUE ThreadQueue;
742
743 pti = PsGetCurrentThreadWin32Thread();
744 ThreadQueue = pti->MessageQueue;
745
746 // Can not release inside WM_CAPTURECHANGED!!
747 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
748
749 co_UserSetCapture(NULL);
750
751 return TRUE;
752 }
753
754 /*
755 API Call
756 */
757 BOOL FASTCALL
758 co_IntSetForegroundWindow(PWND Window)
759 {
760 ASSERT_REFS_CO(Window);
761
762 return co_IntSetForegroundAndFocusWindow(Window, FALSE);
763 }
764
765 /*
766 API Call
767 */
768 BOOL FASTCALL
769 IntLockSetForegroundWindow(UINT uLockCode)
770 {
771 ULONG Err = ERROR_ACCESS_DENIED;
772 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
773 switch (uLockCode)
774 {
775 case LSFW_LOCK:
776 if ( CanForceFG(ppi) && !gppiLockSFW )
777 {
778 gppiLockSFW = ppi;
779 return TRUE;
780 }
781 break;
782 case LSFW_UNLOCK:
783 if ( gppiLockSFW == ppi)
784 {
785 gppiLockSFW = NULL;
786 return TRUE;
787 }
788 break;
789 default:
790 Err = ERROR_INVALID_PARAMETER;
791 }
792 EngSetLastError(Err);
793 return FALSE;
794 }
795
796 /*
797 API Call
798 */
799 BOOL FASTCALL
800 IntAllowSetForegroundWindow(DWORD dwProcessId)
801 {
802 PPROCESSINFO ppi, ppiCur;
803 PEPROCESS Process = NULL;
804
805 ppi = NULL;
806 if (dwProcessId != ASFW_ANY)
807 {
808 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)dwProcessId, &Process)))
809 {
810 EngSetLastError(ERROR_INVALID_PARAMETER);
811 return FALSE;
812 }
813 ppi = PsGetProcessWin32Process(Process);
814 if (!ppi)
815 {
816 ObDereferenceObject(Process);
817 return FALSE;
818 }
819 }
820 ppiCur = PsGetCurrentProcessWin32Process();
821 if (!CanForceFG(ppiCur))
822 {
823 if (Process) ObDereferenceObject(Process);
824 EngSetLastError(ERROR_ACCESS_DENIED);
825 return FALSE;
826 }
827 if (dwProcessId == ASFW_ANY)
828 { // All processes will be enabled to set the foreground window.
829 ptiLastInput = NULL;
830 }
831 else
832 { // Rule #3, last input event in force.
833 ptiLastInput = ppi->ptiList;
834 ObDereferenceObject(Process);
835 }
836 return TRUE;
837 }
838
839 /*
840 * @implemented
841 */
842 HWND APIENTRY
843 NtUserGetForegroundWindow(VOID)
844 {
845 DECLARE_RETURN(HWND);
846
847 TRACE("Enter NtUserGetForegroundWindow\n");
848 UserEnterExclusive();
849
850 RETURN( UserGetForegroundWindow());
851
852 CLEANUP:
853 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
854 UserLeave();
855 END_CLEANUP;
856 }
857
858 HWND APIENTRY
859 NtUserSetActiveWindow(HWND hWnd)
860 {
861 USER_REFERENCE_ENTRY Ref;
862 HWND hWndPrev;
863 PWND Window;
864 DECLARE_RETURN(HWND);
865
866 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd);
867 UserEnterExclusive();
868
869 Window = NULL;
870 if (hWnd)
871 {
872 if (!(Window = UserGetWindowObject(hWnd)))
873 {
874 RETURN( 0);
875 }
876 }
877
878 if (!Window ||
879 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
880 {
881 if (Window) UserRefObjectCo(Window, &Ref);
882 if (!co_IntSetActiveWindow(Window, &hWndPrev, FALSE, TRUE)) hWndPrev = NULL;
883 if (Window) UserDerefObjectCo(Window);
884 }
885 else
886 hWndPrev = NULL;
887
888 RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
889
890 CLEANUP:
891 TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
892 UserLeave();
893 END_CLEANUP;
894 }
895
896 /*
897 * @implemented
898 */
899 HWND APIENTRY
900 NtUserSetCapture(HWND hWnd)
901 {
902 DECLARE_RETURN(HWND);
903
904 TRACE("Enter NtUserSetCapture(%x)\n", hWnd);
905 UserEnterExclusive();
906
907 RETURN( co_UserSetCapture(hWnd));
908
909 CLEANUP:
910 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_);
911 UserLeave();
912 END_CLEANUP;
913 }
914
915 /*
916 * @implemented
917 */
918 HWND APIENTRY
919 NtUserSetFocus(HWND hWnd)
920 {
921 PWND Window;
922 USER_REFERENCE_ENTRY Ref;
923 DECLARE_RETURN(HWND);
924 HWND ret;
925
926 TRACE("Enter NtUserSetFocus(%x)\n", hWnd);
927 UserEnterExclusive();
928
929 if (hWnd)
930 {
931 if (!(Window = UserGetWindowObject(hWnd)))
932 {
933 RETURN(NULL);
934 }
935
936 UserRefObjectCo(Window, &Ref);
937 ret = co_UserSetFocus(Window);
938 UserDerefObjectCo(Window);
939
940 RETURN(ret);
941 }
942 else
943 {
944 RETURN( co_UserSetFocus(0));
945 }
946
947 CLEANUP:
948 TRACE("Leave NtUserSetFocus, ret=%i\n",_ret_);
949 UserLeave();
950 END_CLEANUP;
951 }
952
953 /* EOF */