[NTUSER] Fix ShellHook notifications when creating/activating windows (#2396)
[reactos.git] / 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: win32ss/user/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 /*
29 Get capture window via foreground Queue.
30 */
31 HWND FASTCALL
32 IntGetCaptureWindow(VOID)
33 {
34 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
35 return ( ForegroundQueue ? (ForegroundQueue->spwndCapture ? UserHMGetHandle(ForegroundQueue->spwndCapture) : 0) : 0);
36 }
37
38 HWND FASTCALL
39 IntGetThreadFocusWindow(VOID)
40 {
41 PTHREADINFO pti;
42 PUSER_MESSAGE_QUEUE ThreadQueue;
43
44 pti = PsGetCurrentThreadWin32Thread();
45 ThreadQueue = pti->MessageQueue;
46 if (!ThreadQueue)
47 return NULL;
48 return ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
49 }
50
51 VOID FASTCALL
52 UpdateShellHook(PWND Window)
53 {
54 if ( Window->spwndParent == UserGetDesktopWindow() &&
55 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
56 (Window->ExStyle & WS_EX_APPWINDOW)))
57 {
58 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
59 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (WPARAM) UserHMGetHandle(Window), FALSE);
60 }
61 else
62 {
63 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, 0, FALSE);
64 }
65 }
66
67 BOOL FASTCALL
68 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd, BOOL Clear)
69 {
70 USER_REFERENCE_ENTRY RefPrev;
71 PWND WndPrev;
72 BOOL Ret = TRUE;
73 LPARAM lParam = hWnd ? (LPARAM)hWnd : 0;
74
75 if (hWndPrev && (WndPrev = ValidateHwndNoErr(hWndPrev)))
76 {
77 UserRefObjectCo(WndPrev, &RefPrev);
78
79 if (co_IntSendMessage(hWndPrev, WM_NCACTIVATE, FALSE, lParam))
80 {
81 co_IntSendMessage(hWndPrev, WM_ACTIVATE,
82 MAKEWPARAM(WA_INACTIVE, (WndPrev->style & WS_MINIMIZE) != 0),
83 (LPARAM)hWnd);
84
85 if (WndPrev && Clear)
86 WndPrev->state &= ~(WNDS_ACTIVEFRAME|WNDS_HASCAPTION);
87 }
88 else
89 {
90 ERR("Application is keeping itself Active to prevent the change!\n");
91 Ret = FALSE;
92 }
93
94 UserDerefObjectCo(WndPrev);
95 }
96 return Ret;
97 }
98
99 //
100 // Deactivating the foreground message queue.
101 //
102 // Release Active, Capture and Focus Windows associated with this message queue.
103 //
104 BOOL FASTCALL
105 IntDeactivateWindow(PTHREADINFO pti, HANDLE tid)
106 {
107 USER_REFERENCE_ENTRY Ref;
108 PTHREADINFO ptiPrev;
109 PWND pwndPrev;
110 BOOL InAAPM = FALSE;
111 PTHREADINFO ptiCurrent = PsGetCurrentThreadWin32Thread();
112
113 if ( !pti->MessageQueue->spwndActive )
114 {
115 TRACE("IDAW E : Nothing to do, Active is NULL! pti 0x%p tid 0x%p\n",pti,tid);
116 return TRUE;
117 }
118
119 TRACE("IDAW : pti 0x%p tid 0x%p\n",pti,tid);
120
121 if (ptiCurrent != pti)
122 {
123 IntReferenceThreadInfo(pti);
124 IntReferenceThreadInfo(ptiCurrent);
125 }
126
127 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) )
128 {
129 pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
130 InAAPM = TRUE;
131 }
132
133 //
134 // Check for Capture and release it.
135 //
136 if ( pti->MessageQueue->spwndCapture )
137 {
138 MSG msg;
139 PWND pwndCapture = pti->MessageQueue->spwndCapture;
140
141 UserRefObjectCo(pwndCapture, &Ref);
142 co_IntSendMessage(UserHMGetHandle(pwndCapture), WM_CANCELMODE, 0, 0);
143 UserDerefObjectCo(pwndCapture);
144
145 /* Generate mouse move message */
146 msg.message = WM_MOUSEMOVE;
147 msg.wParam = UserGetMouseButtonsState();
148 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
149 msg.pt = gpsi->ptCursor;
150 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
151 }
152
153 //
154 // Check for Active and release it.
155 //
156 if ( pti->MessageQueue->spwndActive )
157 {
158 pwndPrev = pti->MessageQueue->spwndActive;
159 ptiPrev = pwndPrev->head.pti;
160
161 if (!co_IntSendDeactivateMessages(UserHMGetHandle(pwndPrev), 0, TRUE))
162 {
163 if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
164 if (ptiCurrent != pti)
165 {
166 IntDereferenceThreadInfo(pti);
167 IntDereferenceThreadInfo(ptiCurrent);
168 }
169 return FALSE;
170 }
171
172 if ( pti->MessageQueue->spwndActive == pwndPrev )
173 {
174 pti->MessageQueue->spwndActivePrev = pwndPrev;
175 pti->MessageQueue->spwndActive = NULL;
176 }
177
178 if (ptiPrev->TIF_flags & TIF_INCLEANUP) ptiPrev = NULL;
179 }
180 else
181 {
182 ptiPrev = pti;
183 pwndPrev = (PWND)-1; // Avoid zero Active window.
184 }
185
186 if ( ptiPrev )
187 {
188 HANDLE OldTID = PsGetThreadId(ptiPrev->pEThread);
189 PWND cWindow;
190 HWND *List, *phWnd;
191
192 List = IntWinListChildren(UserGetDesktopWindow());
193 if ( List )
194 {
195 if ( OldTID )
196 {
197 for (phWnd = List; *phWnd; ++phWnd)
198 {
199 cWindow = ValidateHwndNoErr(*phWnd);
200 if ( cWindow && cWindow->head.pti == ptiPrev )
201 { // FALSE if the window is being deactivated,
202 // ThreadId that owns the window being activated.
203 //ERR("IDW : WM_ACTIVATEAPP(0) hwnd %p tid Old %p New %p\n",UserHMGetHandle(cWindow),OldTID,tid);
204 UserRefObjectCo(cWindow, &Ref);
205 co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)tid);
206 UserDerefObjectCo(cWindow);
207 }
208 }
209 }
210 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
211 }
212 }
213
214 //
215 // Now check for a change (Bounce), if Active same as previous window, release it too.
216 //
217 if ( pti->MessageQueue->spwndActive == pwndPrev )
218 {
219 if (!co_IntSendDeactivateMessages(UserHMGetHandle(pwndPrev), 0, FALSE))
220 {
221 if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
222 if (ptiCurrent != pti)
223 {
224 IntDereferenceThreadInfo(pti);
225 IntDereferenceThreadInfo(ptiCurrent);
226 }
227 return FALSE;
228 }
229
230 if ( pti->MessageQueue->spwndActive == pwndPrev )
231 {
232 pti->MessageQueue->spwndActivePrev = pwndPrev;
233 pti->MessageQueue->spwndActive = NULL;
234 }
235 }
236
237 //
238 // Check for Focus and release it.
239 //
240 if ( pti->MessageQueue->spwndFocus )
241 {
242 PWND pwndFocus = pti->MessageQueue->spwndFocus;
243
244 //
245 // Fix win.c:test_SetForegroundWindow:SetActiveWindow(0)!
246 //
247 pti->MessageQueue->spwndFocus = NULL; // Null out Focus.
248
249 UserRefObjectCo(pwndFocus, &Ref);
250 co_IntSendMessage(UserHMGetHandle(pwndFocus), WM_KILLFOCUS, 0, 0);
251 UserDerefObjectCo(pwndFocus);
252 }
253
254 if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
255 if (ptiCurrent != pti)
256 {
257 IntDereferenceThreadInfo(pti);
258 IntDereferenceThreadInfo(ptiCurrent);
259 }
260 return TRUE;
261 }
262
263 //
264 // Activating another threads foreground window after a switch.
265 //
266 VOID FASTCALL
267 IntActivateWindow(PWND Wnd, PTHREADINFO pti, HANDLE tid, DWORD Type)
268 {
269 USER_REFERENCE_ENTRY Ref;
270 PUSER_MESSAGE_QUEUE pmq = pti->MessageQueue;
271
272 if (Wnd)
273 {
274 Wnd = VerifyWnd(Wnd);
275
276 if (!Wnd) return;
277
278 UserRefObjectCo(Wnd, &Ref);
279
280 if (!gpqForeground)
281 {
282 // No foreground queue set.
283 co_IntSetForegroundMessageQueue( Wnd, pti, (BOOL)Type, 0);
284 }
285 else
286 {
287 // Same Active and Wnd.
288 if ( pmq->spwndActive == Wnd )
289 {
290 WPARAM wParam = (Wnd->head.pti->MessageQueue == gpqForeground);
291
292 co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, wParam, 0);
293
294 if (wParam)
295 {
296 UpdateShellHook(Wnd);
297
298 co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
299 }
300 }
301 else // Not the same, set the active Wnd.
302 {
303 co_IntSetActiveWindow(Wnd,(BOOL)Type,TRUE,TRUE);
304 }
305 }
306 UserDerefObjectCo(Wnd);
307 }
308 else // Handle no Wnd!
309 {
310 if ( tid && // TID,
311 pmq->spwndActive && // Active WND not zero,
312 gpqForeground == pmq ) // Same message queues.
313 {
314 Wnd = pmq->spwndActive; // Use active window from current queue.
315
316 UserRefObjectCo(Wnd, &Ref);
317
318 co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, TRUE, 0);
319
320 UpdateShellHook(Wnd);
321
322 co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
323
324 UserDerefObjectCo(Wnd);
325 }
326 else if (gpqForeground != pmq)
327 {
328 // Not the same message queue so clear flags for foreground switching.
329 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
330 pti->ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
331 }
332 }
333 }
334
335 BOOL FASTCALL
336 co_IntMakeWindowActive(PWND Window)
337 {
338 PWND spwndOwner;
339 if (VerifyWnd(Window))
340 { // Set last active for window and it's owner.
341 spwndOwner = Window;
342 while (spwndOwner->spwndOwner)
343 {
344 spwndOwner = spwndOwner->spwndOwner;
345 }
346 spwndOwner->spwndLastActive = Window;
347 return TRUE;
348 }
349 ERR("MakeWindowActive Failed!\n");
350 return FALSE;
351 }
352
353 BOOL FASTCALL
354 co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOOL Async)
355 {
356 USER_REFERENCE_ENTRY Ref, RefPrev, RefCall;
357 HANDLE OldTID, NewTID;
358 PTHREADINFO pti, ptiOld, ptiNew;
359 BOOL InAAPM = FALSE;
360
361 //ERR("SendActivateMessages\n");
362
363 pti = PsGetCurrentThreadWin32Thread();
364
365 if (Window)
366 {
367 UserRefObjectCo(Window, &Ref);
368
369 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
370
371 pti->MessageQueue->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED;
372
373 /* Send palette messages */
374 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
375 //co_IntPostOrSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
376 co_IntSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
377 {
378 UserSendNotifyMessage( HWND_BROADCAST,
379 WM_PALETTEISCHANGING,
380 (WPARAM)UserHMGetHandle(Window),
381 0);
382 }
383 //// Fixes CORE-6434.
384 if (!(Window->style & WS_CHILD))
385 {
386 PWND pwndTemp = co_GetDesktopWindow(Window)->spwndChild;
387
388 while (pwndTemp && !(pwndTemp->style & WS_VISIBLE)) pwndTemp = pwndTemp->spwndNext;
389
390 if (Window != pwndTemp || (WindowPrev && !IntIsWindowVisible(WindowPrev)))
391 {
392 if (!Async || pti->MessageQueue == gpqForeground)
393 {
394 UINT flags = SWP_NOSIZE | SWP_NOMOVE;
395 if (Window == pwndTemp) flags |= SWP_NOACTIVATE;
396 //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground);
397 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, flags);
398 }
399 }
400 }
401 ////
402 //// CORE-1161 and CORE-6651
403 if (Window->spwndPrev)
404 {
405 HWND *phwndTopLevel, *phwndCurrent;
406 PWND pwndCurrent, pwndDesktop;
407
408 pwndDesktop = co_GetDesktopWindow(Window);//UserGetDesktopWindow();
409 if (Window->spwndParent == pwndDesktop )
410 {
411 phwndTopLevel = IntWinListChildren(pwndDesktop);
412 phwndCurrent = phwndTopLevel;
413 while(*phwndCurrent)
414 {
415 pwndCurrent = UserGetWindowObject(*phwndCurrent);
416
417 if (pwndCurrent && pwndCurrent->spwndOwner == Window )
418 {
419 co_WinPosSetWindowPos(pwndCurrent, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
420 }
421 phwndCurrent++;
422 }
423 ExFreePoolWithTag(phwndTopLevel, USERTAG_WINDOWLIST);
424 }
425 }
426 ////
427 }
428
429 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
430 NewTID = Window ? IntGetWndThreadId(Window) : NULL;
431 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
432 ptiNew = Window ? Window->head.pti : NULL;
433
434 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
435
436 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
437 (OldTID != NewTID) )
438 {
439 PWND cWindow;
440 HWND *List, *phWnd;
441
442 List = IntWinListChildren(UserGetDesktopWindow());
443 if ( List )
444 {
445 if ( OldTID )
446 {
447 ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
448 // Note: Do not set pci flags, this does crash!
449 for (phWnd = List; *phWnd; ++phWnd)
450 {
451 cWindow = ValidateHwndNoErr(*phWnd);
452 if (cWindow && cWindow->head.pti == ptiOld)
453 { // FALSE if the window is being deactivated,
454 // ThreadId that owns the window being activated.
455 //ERR("SAM : WM_ACTIVATEAPP(0) tid Old %p New %p\n",OldTID,NewTID);
456 UserRefObjectCo(cWindow, &RefCall);
457 co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
458 UserDerefObjectCo(cWindow);
459 }
460 }
461 ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
462 }
463 if ( NewTID )
464 { //// Prevents a resource crash due to reentrance!
465 InAAPM = TRUE;
466 pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
467 ////
468 for (phWnd = List; *phWnd; ++phWnd)
469 {
470 cWindow = ValidateHwndNoErr(*phWnd);
471 if (cWindow && cWindow->head.pti == ptiNew)
472 { // TRUE if the window is being activated,
473 // ThreadId that owns the window being deactivated.
474 //ERR("SAM : WM_ACTIVATEAPP(1) hwnd %p tid New %p Old %p\n",UserHMGetHandle(cWindow),NewTID,OldTID);
475 UserRefObjectCo(cWindow, &RefCall);
476 co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
477 UserDerefObjectCo(cWindow);
478 }
479 }
480 }
481 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
482 }
483 }
484
485 if (Window)
486 {
487 if (WindowPrev)
488 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
489
490 if (Window->state & WNDS_ACTIVEFRAME)
491 { // If already active frame do not allow NCPaint.
492 //ERR("SendActivateMessage Is Active Frame!\n");
493 Window->state |= WNDS_NONCPAINT;
494 }
495
496 if (Window->style & WS_MINIMIZE)
497 {
498 TRACE("Widow was minimized\n");
499 }
500
501 co_IntMakeWindowActive(Window);
502
503 co_IntSendMessage( UserHMGetHandle(Window),
504 WM_NCACTIVATE,
505 (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)),
506 0);
507
508 co_IntSendMessage( UserHMGetHandle(Window),
509 WM_ACTIVATE,
510 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, (Window->style & WS_MINIMIZE) != 0),
511 (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0));
512
513 if (Window->style & WS_VISIBLE)
514 UpdateShellHook(Window);
515
516 Window->state &= ~WNDS_NONCPAINT;
517
518 UserDerefObjectCo(Window);
519 }
520 return InAAPM;
521 }
522
523 VOID FASTCALL
524 IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
525 {
526 PWND pWndPrev;
527 PUSER_MESSAGE_QUEUE ThreadQueue = pti->MessageQueue; // Queue can change...
528
529 ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
530 if (!pWnd && ThreadQueue->spwndActive)
531 {
532 ThreadQueue->QF_flags |= QF_FOCUSNULLSINCEACTIVE;
533 }
534
535 pWndPrev = ThreadQueue->spwndFocus;
536
537 /* check if the specified window can be set in the input data of a given queue */
538 if (!pWnd || ThreadQueue == pWnd->head.pti->MessageQueue)
539 /* set the current thread focus window */
540 ThreadQueue->spwndFocus = pWnd;
541
542 if (pWnd)
543 {
544 if (pWndPrev)
545 {
546 co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0);
547 }
548 if (ThreadQueue->spwndFocus == pWnd)
549 {
550 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
551
552 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ? UserHMGetHandle(pWndPrev) : NULL), 0);
553 }
554 }
555 else
556 {
557 if (pWndPrev)
558 {
559 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
560
561 co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
562 }
563 }
564 }
565
566 BOOL FASTCALL
567 FindRemoveEventMsg(PTHREADINFO pti, DWORD Event, DWORD EventLast)
568 {
569 PUSER_MESSAGE Message;
570 PLIST_ENTRY Entry;
571 BOOL Ret = FALSE;
572
573 Entry = pti->PostedMessagesListHead.Flink;
574 while (Entry != &pti->PostedMessagesListHead)
575 {
576 // Scan posted queue messages to see if we received async messages.
577 Message = CONTAINING_RECORD(Entry, USER_MESSAGE, ListEntry);
578 Entry = Entry->Flink;
579
580 if (Message->dwQEvent == EventLast)
581 {
582 //ERR("Event D/SAW: Last Activate/Deactivate %d\n", EventLast);
583 return Ret;
584 }
585
586 if (Message->dwQEvent == Event)
587 {
588 //ERR("Event D/SAW: Found one in the Post Msg Queue! Activate/Deactivate %d\n", Event);
589 ClearMsgBitsMask(pti, Message->QS_Flags);
590 MsqDestroyMessage(Message);
591 Ret = TRUE;
592 }
593 }
594 return Ret;
595 }
596
597 BOOL FASTCALL
598 ToggleFGActivate(PTHREADINFO pti)
599 {
600 BOOL Ret;
601 PPROCESSINFO ppi = pti->ppi;
602
603 Ret = !!(pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE);
604 if (Ret)
605 {
606 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
607 }
608 else
609 Ret = !!(ppi->W32PF_flags & W32PF_ALLOWFOREGROUNDACTIVATE);
610
611 if (Ret)
612 ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
613 //ERR("ToggleFGActivate is %d\n",Ret);
614 return Ret;
615 }
616
617 BOOL FASTCALL
618 IsAllowedFGActive(PTHREADINFO pti, PWND Wnd)
619 {
620 // Not allowed if one or more,,
621 if (!ToggleFGActivate(pti) || // bits not set,
622 pti->rpdesk != gpdeskInputDesktop || // not current Desktop,
623 pti->MessageQueue == gpqForeground || // if already the queue foreground,
624 IsFGLocked() || // foreground is locked,
625 Wnd->ExStyle & WS_EX_NOACTIVATE ) // or,,, does not become the foreground window when the user clicks it.
626 {
627 return FALSE;
628 }
629 //ERR("IsAllowedFGActive is TRUE\n");
630 return TRUE;
631 }
632
633 /*
634 Can the system force foreground from one or more conditions.
635 */
636 BOOL FASTCALL
637 CanForceFG(PPROCESSINFO ppi)
638 {
639 if (!ptiLastInput ||
640 ptiLastInput->ppi == ppi ||
641 !gptiForeground ||
642 gptiForeground->ppi == ppi ||
643 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
644 gppiInputProvider == ppi ||
645 !gpqForeground
646 ) return TRUE;
647 //ERR("CanForceFG is FALSE\n");
648 return FALSE;
649 }
650
651 //
652 // Switching out foreground message queues.
653 //
654 BOOL FASTCALL
655 co_IntSetForegroundMessageQueue(
656 _In_opt_ PWND Wnd,
657 _In_ PTHREADINFO pti,
658 _In_ BOOL MouseActivate,
659 _In_ DWORD Type )
660 {
661 PTHREADINFO ptiChg, ptiPrev;
662 PUSER_MESSAGE_QUEUE pumq, pumqChg, pumqPrev;
663 BOOL Removed, Ret = TRUE;
664
665 if (Wnd && !VerifyWnd(Wnd))
666 {
667 return FALSE;
668 }
669
670 if ( !gptiForeground || gptiForeground->TIF_flags & TIF_INCLEANUP )
671 ptiPrev = NULL;
672 else
673 ptiPrev = gptiForeground;
674
675 if (Wnd)
676 {
677 ptiChg = Wnd->head.pti;
678 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
679 gptiForeground = Wnd->head.pti;
680 //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
681 }
682 else
683 {
684 ptiChg = NULL;
685 IntSetFocusMessageQueue(NULL);
686 gptiForeground = NULL;
687 //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
688 }
689
690 //
691 // Process the changing out of the message queues.
692 //
693 if (gpqForegroundPrev != gpqForeground)
694 {
695 pumqPrev = NULL;
696 if ( ptiPrev && !(ptiPrev->TIF_flags & TIF_INCLEANUP) )
697 {
698 pumqPrev = ptiPrev->MessageQueue;
699 }
700
701 pumq = pti ? pti->MessageQueue : NULL;
702
703 // Deactivate the previous message queue.
704 if (pumqPrev)
705 {
706 if ( pumq != pumqPrev )
707 {
708 MSG Msg;
709 HWND hWndPrev = pumqPrev->spwndActive ? UserHMGetHandle(pumqPrev->spwndActive) : NULL;
710 HANDLE tid = gptiForeground ? PsGetThreadId(gptiForeground->pEThread) : NULL; // TID from changing Window PTI.
711
712 Msg.message = WM_ASYNC_SETACTIVEWINDOW;
713 Msg.hwnd = hWndPrev;
714 Msg.wParam = (WPARAM)pumqPrev->spwndActive;
715 Msg.lParam = 0;
716 Msg.time = 0;
717 //ERR("SFWAMQ : DAW P pti 0x%p tid 0x%p hWndPrev 0x%p\n",ptiPrev,tid,hWndPrev);
718 MsqPostMessage(ptiPrev, &Msg, FALSE, QS_EVENT, POSTEVENT_DAW, (LONG_PTR)tid);
719 }
720 }
721
722 pumqChg = NULL;
723 if ( ptiChg && !(ptiChg->TIF_flags & TIF_INCLEANUP) )
724 {
725 pumqChg = ptiChg->MessageQueue;
726 }
727
728 pumq = pti ? pti->MessageQueue : NULL;
729
730 // Activate changing message queue.
731 if (pumqChg)
732 {
733 /*
734 Henri Verbeet,
735 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
736 other thread after we already changed the foreground window back to our own
737 window.
738 */
739 //ERR("SFWAMQ : 1\n");
740 Removed = FindRemoveEventMsg(ptiChg, POSTEVENT_DAW, POSTEVENT_NONE);
741
742 if (pumqChg != pumq)
743 {
744 MSG Msg;
745 HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
746 HANDLE tid = ptiPrev ? PsGetThreadId(ptiPrev->pEThread) : NULL;
747
748 if (Removed) pumqChg->QF_flags |= QF_EVENTDEACTIVATEREMOVED;
749
750 Msg.message = WM_ASYNC_SETACTIVEWINDOW;
751 Msg.hwnd = hWnd;
752 Msg.wParam = (WPARAM)Wnd;
753 Msg.lParam = (LPARAM)tid; //// Fixme! Type flags?
754 Msg.time = 0;
755 //ERR("SFWAMQ : SAW P pti 0x%p tid 0x%p hWnd 0x%p\n",ptiChg,tid,hWnd);
756 MsqPostMessage(ptiChg, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)Type|MouseActivate);
757 }
758 else // Current message queue same as changed message queue.
759 {
760 if (pumq->spwndActive == Wnd)
761 {
762 co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, TRUE, (LPARAM)UserHMGetHandle(Wnd));
763
764 UpdateShellHook(Wnd);
765
766 co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
767 }
768 else
769 {
770 //ERR("SFWAMQ : SAW I pti 0x%p hWnd 0x%p\n",ptiChg,Wnd->head.h);
771 Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE/*Type*/, FALSE);
772 //if (!Ret) ERR("SFWAMQ : ISAW : return error\n");
773 return Ret;
774 }
775 }
776 }
777
778 // Handle same message queue after switch out.
779 pumqPrev = NULL;
780 if ( ptiPrev && !(ptiPrev->TIF_flags & TIF_INCLEANUP) )
781 {
782 pumqPrev = ptiPrev->MessageQueue;
783 }
784 pumq = pti ? pti->MessageQueue : NULL;
785
786 if ( pumqPrev && pumq == pumqPrev )
787 {
788 HANDLE tid = Wnd ? PsGetThreadId(Wnd->head.pti->pEThread) : NULL;
789 //ERR("SFWAMQ : DAW I pti 0x%p tid 0x%p hWnd 0x%p\n",ptiPrev,tid,Wnd ? Wnd->head.h : 0);
790 IntDeactivateWindow(pti, tid);
791 }
792 }
793 return Ret;
794 }
795
796 /*
797 MSDN:
798 The system restricts which processes can set the foreground window. A process
799 can set the foreground window only if one of the following conditions is true:
800
801 * The process is the foreground process.
802 * The process was started by the foreground process.
803 * The process received the last input event.
804 * There is no foreground process.
805 * The foreground process is being debugged.
806 * The foreground is not locked (see LockSetForegroundWindow).
807 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
808 * No menus are active.
809 */
810 static
811 BOOL FASTCALL
812 co_IntSetForegroundAndFocusWindow(
813 _In_opt_ PWND Wnd,
814 _In_ BOOL MouseActivate,
815 _In_ BOOL bFlash )
816 {
817 HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
818 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
819 PTHREADINFO pti;
820 BOOL Ret = FALSE;
821
822 if (Wnd) ASSERT_REFS_CO(Wnd);
823
824 TRACE("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
825
826 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
827 pti = PsGetCurrentThreadWin32Thread();
828
829 if (Wnd && PrevForegroundQueue)
830 { // Same Window Q as foreground just do active.
831 if (Wnd->head.pti->MessageQueue == PrevForegroundQueue)
832 {
833 //ERR("Same Window Q as foreground just do active.\n");
834 if (pti->MessageQueue == PrevForegroundQueue)
835 { // Same WQ and TQ go active.
836 //ERR("Same WQ and TQ go active.\n");
837 Ret = IntUserSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
838 }
839 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
840 { // Same WQ and it is active.
841 //ERR("Same WQ and it is active.\n");
842 Ret = TRUE;
843 }
844 else
845 { // Same WQ as FG but not the same TQ send active.
846 //ERR("Same WQ as FG but not the same TQ send active.\n");
847 MSG Msg;
848 PTHREADINFO ptiNew = Wnd->head.pti;
849
850 Msg.message = WM_ASYNC_SETACTIVEWINDOW;
851 Msg.hwnd = hWnd;
852 Msg.wParam = (WPARAM)Wnd;
853 Msg.lParam = 0;
854 Msg.time = 0;
855 //ERR("SFAFW 1 : SAW P pti 0x%p hWnd 0x%p\n",ptiNew,hWnd);
856 MsqPostMessage(ptiNew, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)MouseActivate);
857
858 Ret = TRUE;
859 }
860 return Ret;
861 }
862 }
863
864 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
865 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
866 pti->ppi == ppiScrnSaver
867 )
868 {
869
870 ToggleFGActivate(pti);
871
872 return co_IntSetForegroundMessageQueue( Wnd, pti, MouseActivate, 0 );
873 }
874
875 if (!Wnd) return FALSE; // No window, always return FALSE.
876
877 //// if (bFlash) FIXME : handle flash!!!
878
879 if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
880 {
881 //ERR("Same PQ and WQ go active.\n");
882 Ret = IntUserSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
883 //if (!Ret) ERR("ISFAFW : IUSAW : return error\n");
884 }
885 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
886 {
887 TRACE("Same Active and Wnd.\n"); // Leave this for now.
888 }
889 else
890 {
891 //ERR("Activate Not same PQ and WQ and Wnd.\n");
892 //// CORE-10785 fix hang, ROSTESTS-208 allows test to run.
893 MSG Msg;
894 PTHREADINFO ptiNew = Wnd->head.pti;
895
896 Msg.message = WM_ASYNC_SETACTIVEWINDOW;
897 Msg.hwnd = hWnd;
898 Msg.wParam = (WPARAM)Wnd;
899 Msg.lParam = 0;
900 Msg.time = 0;
901 //ERR("SFAFW 2 : SAW P pti 0x%p hWnd 0x%p\n",ptiNew,hWnd);
902 MsqPostMessage(ptiNew, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)MouseActivate);
903 }
904 // Always return FALSE.
905 return FALSE;
906 }
907
908 //
909 // Set the Active Window.
910 //
911 BOOL FASTCALL
912 co_IntSetActiveWindow(
913 _In_ PWND Wnd,
914 _In_ BOOL bMouse,
915 _In_ BOOL bFocus,
916 _In_ BOOL Async )
917 {
918 PTHREADINFO pti;
919 PUSER_MESSAGE_QUEUE ThreadQueue;
920 PWND pWndChg, WndPrev; // State changes.
921 HWND hWndPrev;
922 HWND hWnd = 0;
923 BOOL InAAPM;
924 CBTACTIVATESTRUCT cbt;
925
926 //ERR("co_IntSetActiveWindow 1\n");
927
928 pti = PsGetCurrentThreadWin32Thread();
929 ThreadQueue = pti->MessageQueue;
930 ASSERT(ThreadQueue != 0);
931
932 hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
933
934 pWndChg = ThreadQueue->spwndActive; // Keep to notify of a preemptive switch.
935
936 if ( !Wnd || Wnd == UserGetDesktopWindow() )
937 {
938 //ERR("ISAW : NULL %p\n",Wnd);
939 return FALSE;
940 }
941
942 ASSERT_REFS_CO(Wnd);
943 hWnd = UserHMGetHandle(Wnd);
944 //ERR("co_IntSetActiveWindow 2 hWnd 0x%p\n",hWnd);
945
946 /* check if the specified window can be set in the input data of a given queue */
947 if ( ThreadQueue != Wnd->head.pti->MessageQueue )
948 {
949 //ERR("ISAW : Must have the same Message Queue\n");
950 return FALSE;
951 }
952
953 if (!VerifyWnd(Wnd))
954 {
955 //ERR("ISAW : Window is in Destroy!\n");
956 return FALSE;
957 }
958
959 if ( Wnd == pWndChg )
960 {
961 //ERR("ISAW : Nothing to do\n");
962 return TRUE; // Fix CORE-8780 and CORE-11979. See CORE-11324 for breakage.
963 }
964
965 if ( Wnd->state & WNDS_BEINGACTIVATED ) return TRUE;
966
967 /* Call CBT hook chain */
968 cbt.fMouse = bMouse;
969 cbt.hWndActive = hWndPrev;
970 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
971 {
972 ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
973 return FALSE;
974 }
975
976 ThreadQueue->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED;
977
978 if ( ThreadQueue->spwndActive && ThreadQueue->spwndActive->state & WNDS_DESTROYED )
979 ThreadQueue->spwndActive = NULL;
980 else
981 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
982
983 WndPrev = ThreadQueue->spwndActive; // Keep to save changing active.
984
985 if (WndPrev)
986 {
987 if (ThreadQueue == gpqForeground) gpqForegroundPrev = ThreadQueue;
988 if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev), hWnd, TRUE)) return FALSE;
989 }
990
991 WndPrev = ThreadQueue->spwndActive; // Again keep to save changing active.
992
993 // While in calling message proc or hook:
994 // Fail if a preemptive switch was made, current active not made previous,
995 // focus window is dead or no longer the same thread queue.
996 if ( ThreadQueue->spwndActivePrev != ThreadQueue->spwndActive ||
997 pWndChg != WndPrev ||
998 (Wnd && !VerifyWnd(Wnd)) ||
999 ThreadQueue != pti->MessageQueue )
1000 {
1001 ERR("SetActiveWindow: Summary ERROR, active state changed!\n");
1002 return FALSE;
1003 }
1004
1005 if (!WndPrev) ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
1006
1007 /* set the current thread active window */
1008 ThreadQueue->spwndActive = Wnd;
1009
1010 // Set state flag to prevent recursions.
1011 Wnd->state |= WNDS_BEINGACTIVATED;
1012
1013 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1014
1015 // Clear out activate EVENT messages.
1016 FindRemoveEventMsg(pti, POSTEVENT_SAW, POSTEVENT_DAW);
1017
1018 WndPrev = VerifyWnd(ThreadQueue->spwndActivePrev); // Now should be set but verify it again.
1019
1020 InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async);
1021
1022 /* now change focus if necessary */
1023 //// Fixes CORE-6452 allows setting focus on window.
1024 if (bFocus && !(ThreadQueue->QF_flags & QF_FOCUSNULLSINCEACTIVE))
1025 {
1026 /* Do not change focus if the window is no longer active */
1027 if (pti->MessageQueue->spwndActive != IntGetNonChildAncestor(pti->MessageQueue->spwndFocus))
1028 {
1029 PWND pWndSend = pti->MessageQueue->spwndActive;
1030 // Clear focus if the active window is minimized.
1031 if (pWndSend && pti->MessageQueue->spwndActive->style & WS_MINIMIZE) pWndSend = NULL;
1032 // Send focus messages and if so, set the focus.
1033 IntSendFocusMessages( pti, pWndSend);
1034 }
1035 }
1036 ////
1037 if (InAAPM)
1038 {
1039 pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
1040 }
1041
1042 // Checked in MENU_TrackMenu
1043 ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
1044
1045 //ERR("co_IntSetActiveWindow Exit\n");
1046 Wnd->state &= ~WNDS_BEINGACTIVATED;
1047 return (ThreadQueue->spwndActive == Wnd);
1048 }
1049
1050 //
1051 // Set the Active Window.
1052 //
1053 // Window is not optional!
1054 //
1055 BOOL FASTCALL
1056 IntUserSetActiveWindow(
1057 _In_ PWND Wnd,
1058 _In_ BOOL bMouse,
1059 _In_ BOOL bFocus,
1060 _In_ BOOL Async)
1061 {
1062 PTHREADINFO pti;
1063 PUSER_MESSAGE_QUEUE ThreadQueue;
1064
1065 //ERR("IntUserSetActiveWindow 1\n");
1066 ASSERT_REFS_CO(Wnd);
1067 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1068 //ERR("IntUserSetActiveWindow 1a hWnd 0x%p\n",UserHMGetHandle(Wnd));
1069
1070 //ERR("IntUserSetActiveWindow 2\n");
1071 pti = PsGetCurrentThreadWin32Thread();
1072 ThreadQueue = pti->MessageQueue;
1073 ASSERT(ThreadQueue != 0);
1074
1075 while (Wnd)
1076 {
1077 BOOL Ret, DoFG, AllowFG;
1078
1079 if (ThreadQueue == Wnd->head.pti->MessageQueue)
1080 {
1081 if (IsAllowedFGActive(pti, Wnd))
1082 {
1083 DoFG = TRUE;
1084 }
1085 else
1086 {
1087 //ERR("IntUserSetActiveWindow 3 Go Out!\n");
1088 break;
1089 }
1090 AllowFG = !pti->cVisWindows; // Nothing is visable.
1091 //ERR("IntUserSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
1092 }
1093 else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
1094 {
1095 //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
1096 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
1097 if (!gpqForeground || gpqForeground == ThreadQueue)
1098 {
1099 DoFG = TRUE;
1100 }
1101 else
1102 DoFG = FALSE;
1103 if (DoFG)
1104 {
1105 if (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE || pti->cVisWindows)
1106 AllowFG = TRUE;
1107 else
1108 AllowFG = FALSE;
1109 }
1110 else
1111 AllowFG = FALSE;
1112 //ERR("IntUserSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
1113 }
1114 Ret = FALSE;
1115 if (DoFG)
1116 {
1117 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
1118 //ERR("IntUserSetActiveWindow 3c FG set\n");
1119 Ret = co_IntSetForegroundAndFocusWindow(Wnd, bMouse, TRUE);
1120 if (AllowFG)
1121 {
1122 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
1123 }
1124 else
1125 {
1126 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
1127 }
1128 }
1129 return Ret;
1130 }
1131
1132 return co_IntSetActiveWindow(Wnd, bMouse, bFocus, Async);
1133 }
1134
1135 BOOL FASTCALL
1136 co_IntMouseActivateWindow(PWND Wnd)
1137 {
1138 TRACE("Mouse Active\n");
1139 return co_IntSetForegroundAndFocusWindow(Wnd, TRUE, TRUE);
1140 }
1141
1142 BOOL FASTCALL
1143 UserSetActiveWindow( _In_opt_ PWND Wnd )
1144 {
1145 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1146
1147 if (Wnd)
1148 {
1149 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
1150
1151 return IntUserSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
1152 }
1153 /*
1154 Yes your eye are not deceiving you~!
1155
1156 First part of wines Win.c test_SetActiveWindow:
1157
1158 flush_events( TRUE );
1159 ShowWindow(hwnd, SW_HIDE);
1160 SetFocus(0);
1161 SetActiveWindow(0);
1162 check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
1163
1164 Now Handle wines Msg.c test_SetActiveWindow( 0 )...
1165 */
1166 TRACE("USAW: Previous active window\n");
1167 if ( gpqForegroundPrev &&
1168 gpqForegroundPrev->spwndActivePrev &&
1169 (gpqForegroundPrev->spwndActivePrev->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE &&
1170 !(gpqForegroundPrev->spwndActivePrev->state2 & WNDS2_BOTTOMMOST) &&
1171 (Wnd = VerifyWnd(gpqForegroundPrev->spwndActivePrev)) != NULL )
1172 {
1173 TRACE("USAW:PAW hwnd %p\n",Wnd?Wnd->head.h:NULL);
1174 return IntUserSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
1175 }
1176
1177 // Activate anyone but the active window.
1178 if ( pti->MessageQueue->spwndActive &&
1179 (Wnd = VerifyWnd(pti->MessageQueue->spwndActive)) != NULL )
1180 {
1181 //ERR("USAW:AOWM hwnd %p\n",Wnd?Wnd->head.h:NULL);
1182 if (!ActivateOtherWindowMin(Wnd))
1183 {
1184 // Okay, now go find someone else to play with!
1185 //ERR("USAW: Going to WPAOW\n");
1186 co_WinPosActivateOtherWindow(Wnd);
1187 }
1188 return TRUE;
1189 }
1190
1191 TRACE("USAW: Nothing\n");
1192 return FALSE;
1193 }
1194
1195 HWND FASTCALL
1196 co_UserSetFocus(PWND Window)
1197 {
1198 HWND hWndPrev = 0;
1199 PWND pwndTop;
1200 PTHREADINFO pti;
1201 PUSER_MESSAGE_QUEUE ThreadQueue;
1202
1203 if (Window)
1204 ASSERT_REFS_CO(Window);
1205
1206 pti = PsGetCurrentThreadWin32Thread();
1207 ThreadQueue = pti->MessageQueue;
1208 ASSERT(ThreadQueue != 0);
1209
1210 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window ? UserHMGetHandle(Window) : 0, pti );
1211
1212 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
1213
1214 if (Window != 0)
1215 {
1216 if (hWndPrev == UserHMGetHandle(Window))
1217 {
1218 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0; /* Nothing to do */
1219 }
1220
1221 if (Window->head.pti->MessageQueue != ThreadQueue)
1222 {
1223 ERR("SetFocus Must have the same Q!\n");
1224 return 0;
1225 }
1226
1227 /* Check if we can set the focus to this window */
1228 //// Fixes wine win test_SetParent both "todo" line 3710 and 3720...
1229 for (pwndTop = Window; pwndTop; pwndTop = pwndTop->spwndParent)
1230 {
1231 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
1232 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
1233 if (pwndTop->spwndParent == NULL) break;
1234 }
1235 ////
1236 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
1237 {
1238 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
1239 return 0;
1240 }
1241
1242 /* Activate pwndTop if needed. */
1243 if (pwndTop != ThreadQueue->spwndActive)
1244 {
1245 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
1246 if (ThreadQueue != ForegroundQueue && IsAllowedFGActive(pti, pwndTop)) // Rule 2 & 3.
1247 {
1248 //ERR("SetFocus: Set Foreground!\n");
1249 if (!(pwndTop->style & WS_VISIBLE))
1250 {
1251 pti->ppi->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE;
1252 }
1253 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE, TRUE))
1254 {
1255 ERR("SetFocus: Set Foreground and Focus Failed!\n");
1256 return 0;
1257 }
1258 }
1259
1260 /* Set Active when it is needed. */
1261 if (pwndTop != ThreadQueue->spwndActive)
1262 {
1263 //ERR("SetFocus: Set Active! %p\n",pwndTop?UserHMGetHandle(pwndTop):0);
1264 if (!co_IntSetActiveWindow(pwndTop, FALSE, FALSE, FALSE))
1265 {
1266 ERR("SetFocus: Set Active Failed!\n");
1267 return 0;
1268 }
1269 }
1270
1271 /* Abort if window destroyed */
1272 if (Window->state2 & WNDS2_INDESTROY) return 0;
1273 /* Do not change focus if the window is no longer active */
1274 if (pwndTop != ThreadQueue->spwndActive)
1275 {
1276 ERR("SetFocus: Top window did not go active!\n");
1277 return 0;
1278 }
1279 }
1280
1281 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
1282 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
1283
1284 IntSendFocusMessages( pti, Window);
1285
1286 TRACE("Focus: %p -> %p\n", hWndPrev, Window->head.h);
1287 }
1288 else /* NULL hwnd passed in */
1289 {
1290 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
1291 {
1292 ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
1293 return 0;
1294 }
1295 //ERR("SetFocus: Set Focus NULL\n");
1296 /* set the current thread focus window null */
1297 IntSendFocusMessages( pti, NULL);
1298 }
1299 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
1300 }
1301
1302 HWND FASTCALL
1303 UserGetForegroundWindow(VOID)
1304 {
1305 PUSER_MESSAGE_QUEUE ForegroundQueue;
1306
1307 ForegroundQueue = IntGetFocusMessageQueue();
1308 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
1309 }
1310
1311 HWND FASTCALL UserGetActiveWindow(VOID)
1312 {
1313 PTHREADINFO pti;
1314 PUSER_MESSAGE_QUEUE ThreadQueue;
1315
1316 pti = PsGetCurrentThreadWin32Thread();
1317 ThreadQueue = pti->MessageQueue;
1318 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
1319 }
1320
1321 HWND APIENTRY
1322 IntGetCapture(VOID)
1323 {
1324 PTHREADINFO pti;
1325 PUSER_MESSAGE_QUEUE ThreadQueue;
1326 DECLARE_RETURN(HWND);
1327
1328 TRACE("Enter IntGetCapture\n");
1329
1330 pti = PsGetCurrentThreadWin32Thread();
1331 ThreadQueue = pti->MessageQueue;
1332 RETURN( ThreadQueue ? (ThreadQueue->spwndCapture ? UserHMGetHandle(ThreadQueue->spwndCapture) : 0) : 0);
1333
1334 CLEANUP:
1335 TRACE("Leave IntGetCapture, ret=%p\n", _ret_);
1336 END_CLEANUP;
1337 }
1338
1339 HWND FASTCALL
1340 co_UserSetCapture(HWND hWnd)
1341 {
1342 PTHREADINFO pti;
1343 PUSER_MESSAGE_QUEUE ThreadQueue;
1344 PWND pWnd, Window = NULL;
1345 HWND hWndPrev;
1346
1347 pti = PsGetCurrentThreadWin32Thread();
1348 ThreadQueue = pti->MessageQueue;
1349
1350 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
1351 return NULL;
1352
1353 if (hWnd && (Window = UserGetWindowObject(hWnd)))
1354 {
1355 if (Window->head.pti->MessageQueue != ThreadQueue)
1356 {
1357 ERR("Window Thread does not match Current!\n");
1358 return NULL;
1359 }
1360 }
1361
1362 hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd);
1363
1364 if (hWndPrev)
1365 {
1366 pWnd = UserGetWindowObject(hWndPrev);
1367 if (pWnd)
1368 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1369 }
1370
1371 if (Window)
1372 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1373
1374 //
1375 // Only send the message if we have a previous Window!
1376 // Fix msg_menu tracking popup menu and win test_capture_4!!!!
1377 //
1378 if (hWndPrev)
1379 {
1380 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
1381
1382 co_IntSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
1383
1384 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
1385 }
1386
1387 if (hWnd == NULL) // Release mode.
1388 {
1389 MOUSEINPUT mi;
1390 /// These are HACKS!
1391 /* Also remove other windows if not capturing anymore */
1392 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
1393 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
1394 ///
1395 /* Somebody may have missed some mouse movements */
1396 mi.dx = 0;
1397 mi.dy = 0;
1398 mi.mouseData = 0;
1399 mi.dwFlags = MOUSEEVENTF_MOVE;
1400 mi.time = 0;
1401 mi.dwExtraInfo = 0;
1402 UserSendMouseInput(&mi, FALSE);
1403 }
1404 return hWndPrev;
1405 }
1406
1407 /*
1408 API Call
1409 */
1410 BOOL
1411 FASTCALL
1412 IntReleaseCapture(VOID)
1413 {
1414 PTHREADINFO pti;
1415 PUSER_MESSAGE_QUEUE ThreadQueue;
1416
1417 pti = PsGetCurrentThreadWin32Thread();
1418 ThreadQueue = pti->MessageQueue;
1419
1420 // Can not release inside WM_CAPTURECHANGED!!
1421 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
1422
1423 co_UserSetCapture(NULL);
1424
1425 return TRUE;
1426 }
1427
1428 /*
1429 API Call
1430 */
1431 BOOL FASTCALL
1432 co_IntSetForegroundWindow(PWND Window)
1433 {
1434 if (Window) ASSERT_REFS_CO(Window);
1435
1436 return co_IntSetForegroundAndFocusWindow(Window, FALSE, TRUE);
1437 }
1438
1439 /*
1440 API Call
1441 */
1442 BOOL FASTCALL
1443 co_IntSetForegroundWindowMouse(PWND Window)
1444 {
1445 if (Window) ASSERT_REFS_CO(Window);
1446
1447 return co_IntSetForegroundAndFocusWindow(Window, TRUE, FALSE);
1448 }
1449
1450 /*
1451 API Call
1452 */
1453 BOOL FASTCALL
1454 IntLockSetForegroundWindow(UINT uLockCode)
1455 {
1456 ULONG Err = ERROR_ACCESS_DENIED;
1457 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1458 switch (uLockCode)
1459 {
1460 case LSFW_LOCK:
1461 if ( CanForceFG(ppi) && !gppiLockSFW )
1462 {
1463 gppiLockSFW = ppi;
1464 return TRUE;
1465 }
1466 break;
1467 case LSFW_UNLOCK:
1468 if ( gppiLockSFW == ppi)
1469 {
1470 gppiLockSFW = NULL;
1471 return TRUE;
1472 }
1473 break;
1474 default:
1475 Err = ERROR_INVALID_PARAMETER;
1476 }
1477 EngSetLastError(Err);
1478 return FALSE;
1479 }
1480
1481 /*
1482 API Call
1483 */
1484 BOOL FASTCALL
1485 IntAllowSetForegroundWindow(DWORD dwProcessId)
1486 {
1487 PPROCESSINFO ppi, ppiCur;
1488 PEPROCESS Process = NULL;
1489
1490 ppi = NULL;
1491 if (dwProcessId != ASFW_ANY)
1492 {
1493 if (!NT_SUCCESS(PsLookupProcessByProcessId(UlongToHandle(dwProcessId), &Process)))
1494 {
1495 EngSetLastError(ERROR_INVALID_PARAMETER);
1496 return FALSE;
1497 }
1498 ppi = PsGetProcessWin32Process(Process);
1499 if (!ppi)
1500 {
1501 ObDereferenceObject(Process);
1502 return FALSE;
1503 }
1504 }
1505 ppiCur = PsGetCurrentProcessWin32Process();
1506 if (!CanForceFG(ppiCur))
1507 {
1508 if (Process) ObDereferenceObject(Process);
1509 EngSetLastError(ERROR_ACCESS_DENIED);
1510 return FALSE;
1511 }
1512 if (dwProcessId == ASFW_ANY)
1513 { // All processes will be enabled to set the foreground window.
1514 //ERR("ptiLastInput is CLEARED!!\n");
1515 ptiLastInput = NULL;
1516 }
1517 else
1518 { // Rule #3, last input event in force.
1519 ERR("ptiLastInput is SET!!\n");
1520 //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030.
1521 ObDereferenceObject(Process);
1522 }
1523 return TRUE;
1524 }
1525
1526 /*
1527 * @implemented
1528 */
1529 HWND APIENTRY
1530 NtUserGetForegroundWindow(VOID)
1531 {
1532 DECLARE_RETURN(HWND);
1533
1534 TRACE("Enter NtUserGetForegroundWindow\n");
1535 UserEnterExclusive();
1536
1537 RETURN( UserGetForegroundWindow());
1538
1539 CLEANUP:
1540 TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_);
1541 UserLeave();
1542 END_CLEANUP;
1543 }
1544
1545 HWND APIENTRY
1546 NtUserSetActiveWindow(HWND hWnd)
1547 {
1548 USER_REFERENCE_ENTRY Ref;
1549 HWND hWndPrev;
1550 PWND Window;
1551 DECLARE_RETURN(HWND);
1552
1553 TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd);
1554 UserEnterExclusive();
1555
1556 Window = NULL;
1557 if (hWnd)
1558 {
1559 if (!(Window = UserGetWindowObject(hWnd)))
1560 {
1561 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd);
1562 RETURN( NULL);
1563 }
1564 }
1565
1566 if (!Window ||
1567 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
1568 {
1569 hWndPrev = gptiCurrent->MessageQueue->spwndActive ? UserHMGetHandle(gptiCurrent->MessageQueue->spwndActive) : NULL;
1570 if (Window) UserRefObjectCo(Window, &Ref);
1571 UserSetActiveWindow(Window);
1572 if (Window) UserDerefObjectCo(Window);
1573 RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
1574 }
1575 RETURN( NULL);
1576
1577 CLEANUP:
1578 TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_);
1579 UserLeave();
1580 END_CLEANUP;
1581 }
1582
1583 /*
1584 * @implemented
1585 */
1586 HWND APIENTRY
1587 NtUserSetCapture(HWND hWnd)
1588 {
1589 DECLARE_RETURN(HWND);
1590
1591 TRACE("Enter NtUserSetCapture(%p)\n", hWnd);
1592 UserEnterExclusive();
1593
1594 RETURN( co_UserSetCapture(hWnd));
1595
1596 CLEANUP:
1597 TRACE("Leave NtUserSetCapture, ret=%p\n", _ret_);
1598 UserLeave();
1599 END_CLEANUP;
1600 }
1601
1602 /*
1603 * @implemented
1604 */
1605 HWND APIENTRY
1606 NtUserSetFocus(HWND hWnd)
1607 {
1608 PWND Window;
1609 USER_REFERENCE_ENTRY Ref;
1610 DECLARE_RETURN(HWND);
1611 HWND ret;
1612
1613 TRACE("Enter NtUserSetFocus(%p)\n", hWnd);
1614 UserEnterExclusive();
1615
1616 if (hWnd)
1617 {
1618 if (!(Window = UserGetWindowObject(hWnd)))
1619 {
1620 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd);
1621 RETURN(NULL);
1622 }
1623
1624 UserRefObjectCo(Window, &Ref);
1625 ret = co_UserSetFocus(Window);
1626 UserDerefObjectCo(Window);
1627
1628 RETURN(ret);
1629 }
1630 else
1631 {
1632 RETURN( co_UserSetFocus(0));
1633 }
1634
1635 CLEANUP:
1636 TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_);
1637 UserLeave();
1638 END_CLEANUP;
1639 }
1640
1641 /* EOF */