[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 ? (ForegroundQueue->spwndCapture ? UserHMGetHandle(ForegroundQueue->spwndCapture) : 0) : 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 BOOL FASTCALL
49 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
50 {
51 USER_REFERENCE_ENTRY RefPrev;
52 PWND WndPrev;
53 BOOL Ret = TRUE;
54
55 if (hWndPrev && (WndPrev = ValidateHwndNoErr(hWndPrev)))
56 {
57 UserRefObjectCo(WndPrev, &RefPrev);
58
59 if (co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0)) //(LPARAM)hWnd))
60 {
61 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
62 MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
63 (LPARAM)hWnd);
64
65 if (WndPrev)
66 WndPrev->state &= ~WNDS_ACTIVEFRAME;
67 }
68 else
69 {
70 ERR("Application is keeping itself Active to prevent the change!\n");
71 Ret = FALSE;
72 }
73
74 UserDerefObjectCo(WndPrev);
75 }
76 return Ret;
77 }
78
79 BOOL FASTCALL
80 co_IntMakeWindowActive(PWND Window)
81 {
82 PWND spwndOwner;
83 if (VerifyWnd(Window))
84 { // Set last active for window and it's owner.
85 spwndOwner = Window;
86 while (spwndOwner->spwndOwner)
87 {
88 spwndOwner = spwndOwner->spwndOwner;
89 }
90 spwndOwner->spwndLastActive = Window;
91 return TRUE;
92 }
93 ERR("MakeWindowActive Failed!\n");
94 return FALSE;
95 }
96
97 BOOL FASTCALL
98 co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOOL Async)
99 {
100 USER_REFERENCE_ENTRY Ref, RefPrev;
101 HANDLE OldTID, NewTID;
102 PTHREADINFO pti, ptiOld, ptiNew;
103 BOOL InAAPM = FALSE;
104
105 if (Window)
106 {
107 pti = PsGetCurrentThreadWin32Thread();
108
109 UserRefObjectCo(Window, &Ref);
110
111 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
112
113 /* Send palette messages */
114 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
115 co_IntPostOrSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
116 {
117 UserSendNotifyMessage( HWND_BROADCAST,
118 WM_PALETTEISCHANGING,
119 (WPARAM)UserHMGetHandle(Window),
120 0);
121 }
122 //// Fixes bug 7089.
123 if (!(Window->style & WS_CHILD))
124 {
125 PWND pwndTemp = co_GetDesktopWindow(Window)->spwndChild;
126
127 while (pwndTemp && !(pwndTemp->style & WS_VISIBLE)) pwndTemp = pwndTemp->spwndNext;
128
129 if (Window != pwndTemp || (WindowPrev && !IntIsWindowVisible(WindowPrev)))
130 {
131 if (!Async || pti->MessageQueue == gpqForeground)
132 {
133 UINT flags = SWP_NOSIZE | SWP_NOMOVE;
134 if (Window == pwndTemp) flags |= SWP_NOACTIVATE;
135 //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground);
136 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, flags);
137 }
138 }
139 }
140 ////
141 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
142 NewTID = IntGetWndThreadId(Window);
143 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
144 ptiNew = Window->head.pti;
145
146 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
147
148 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
149 (!WindowPrev || OldTID != NewTID) )
150 {
151 PWND cWindow;
152 HWND *List, *phWnd;
153
154 List = IntWinListChildren(UserGetDesktopWindow());
155 if ( List )
156 {
157 if ( OldTID )
158 {
159 ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
160 // Note: Do not set pci flags, this does crash!
161 for (phWnd = List; *phWnd; ++phWnd)
162 {
163 cWindow = ValidateHwndNoErr(*phWnd);
164 if (cWindow && cWindow->head.pti == ptiOld)
165 { // FALSE if the window is being deactivated,
166 // ThreadId that owns the window being activated.
167 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
168 }
169 }
170 ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
171 }
172 if ( NewTID )
173 { //// Prevents a resource crash due to reentrance!
174 InAAPM = TRUE;
175 pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
176 ////
177 for (phWnd = List; *phWnd; ++phWnd)
178 {
179 cWindow = ValidateHwndNoErr(*phWnd);
180 if (cWindow && cWindow->head.pti == ptiNew)
181 { // TRUE if the window is being activated,
182 // ThreadId that owns the window being deactivated.
183 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
184 }
185 }
186 }
187 ExFreePool(List);//ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
188 }
189 }
190 if (WindowPrev)
191 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
192
193 if (Window->state & WNDS_ACTIVEFRAME)
194 { // If already active frame do not allow NCPaint.
195 //ERR("SendActivateMessage Is Active Frame!\n");
196 Window->state |= WNDS_NONCPAINT;
197 }
198
199 if (Window->style & WS_MINIMIZE)
200 {
201 TRACE("Widow was minimized\n");
202 }
203
204 co_IntMakeWindowActive(Window);
205
206 /* FIXME: IntIsWindow */
207
208 co_IntSendMessageNoWait( UserHMGetHandle(Window),
209 WM_NCACTIVATE,
210 (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)),
211 0); //(LPARAM)hWndPrev);
212
213 co_IntSendMessageNoWait( UserHMGetHandle(Window),
214 WM_ACTIVATE,
215 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, Window->style & WS_MINIMIZE),
216 (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0));
217
218 if (!Window->spwndOwner && !IntGetParent(Window))
219 {
220 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
221 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (WPARAM) UserHMGetHandle(Window), FALSE);
222 }
223
224 Window->state &= ~WNDS_NONCPAINT;
225
226 UserDerefObjectCo(Window);
227 }
228 return InAAPM;
229 }
230
231 VOID FASTCALL
232 IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
233 {
234 PWND pWndPrev;
235 PUSER_MESSAGE_QUEUE ThreadQueue = pti->MessageQueue; // Queue can change...
236
237 ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
238 if (!pWnd && ThreadQueue->spwndActive)
239 {
240 ThreadQueue->QF_flags |= QF_FOCUSNULLSINCEACTIVE;
241 }
242
243 pWndPrev = ThreadQueue->spwndFocus;
244
245 /* check if the specified window can be set in the input data of a given queue */
246 if (!pWnd || ThreadQueue == pWnd->head.pti->MessageQueue)
247 /* set the current thread focus window */
248 ThreadQueue->spwndFocus = pWnd;
249
250 if (pWnd)
251 {
252 if (pWndPrev)
253 {
254 co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0);
255 }
256 if (ThreadQueue->spwndFocus == pWnd)
257 {
258 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
259 co_IntPostOrSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ? UserHMGetHandle(pWndPrev) : NULL), 0);
260 }
261 }
262 else
263 {
264 if (pWndPrev)
265 {
266 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
267 co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
268 }
269 }
270 }
271
272 HWND FASTCALL
273 IntFindChildWindowToOwner(PWND Root, PWND Owner)
274 {
275 HWND Ret;
276 PWND Child, OwnerWnd;
277
278 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
279 {
280 OwnerWnd = Child->spwndOwner;
281 if(!OwnerWnd)
282 continue;
283
284 if(OwnerWnd == Owner)
285 {
286 Ret = Child->head.h;
287 return Ret;
288 }
289 }
290
291 return NULL;
292 }
293
294 VOID FASTCALL
295 FindRemoveAsyncMsg(PWND Wnd, WPARAM wParam)
296 {
297 PTHREADINFO pti;
298 PUSER_SENT_MESSAGE Message;
299 PLIST_ENTRY Entry;
300
301 if (!Wnd) return;
302
303 pti = Wnd->head.pti;
304
305 if (!IsListEmpty(&pti->SentMessagesListHead))
306 {
307 // Scan sent queue messages to see if we received async messages.
308 Entry = pti->SentMessagesListHead.Flink;
309 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
310 do
311 {
312 if (IsListEmpty(Entry)) return;
313 if (!Message) return;
314 Entry = Message->ListEntry.Flink;
315
316 if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
317 Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
318 Message->Msg.wParam == wParam )
319 {
320 ERR("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message->Msg.hwnd,!!wParam);
321 RemoveEntryList(&Message->ListEntry); // Purge the entry.
322 ExFreePoolWithTag(Message, TAG_USRMSG);
323 }
324 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
325 }
326 while (Entry != &pti->SentMessagesListHead);
327 }
328 }
329
330 BOOL FASTCALL
331 ToggleFGActivate(PTHREADINFO pti)
332 {
333 BOOL Ret;
334 PPROCESSINFO ppi = pti->ppi;
335
336 Ret = !!(pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE);
337 if (Ret)
338 {
339 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
340 }
341 else
342 Ret = !!(ppi->W32PF_flags & W32PF_ALLOWFOREGROUNDACTIVATE);
343
344 if (Ret)
345 ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
346 //ERR("ToggleFGActivate is %d\n",Ret);
347 return Ret;
348 }
349
350 BOOL FASTCALL
351 IsAllowedFGActive(PTHREADINFO pti, PWND Wnd)
352 {
353 // Not allowed if one or more,,
354 if (!ToggleFGActivate(pti) || // bits not set,
355 pti->rpdesk != gpdeskInputDesktop || // not current Desktop,
356 pti->MessageQueue == gpqForeground || // if already the queue foreground,
357 IsFGLocked() || // foreground is locked,
358 Wnd->ExStyle & WS_EX_NOACTIVATE ) // or,,, does not become the foreground window when the user clicks it.
359 {
360 return FALSE;
361 }
362 //ERR("IsAllowedFGActive is TRUE\n");
363 return TRUE;
364 }
365
366 /*
367 Can the system force foreground from one or more conditions.
368 */
369 BOOL FASTCALL
370 CanForceFG(PPROCESSINFO ppi)
371 {
372 if (!ptiLastInput ||
373 ptiLastInput->ppi == ppi ||
374 !gptiForeground ||
375 gptiForeground->ppi == ppi ||
376 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
377 gppiInputProvider == ppi ||
378 !gpqForeground
379 ) return TRUE;
380 //ERR("CanForceFG is FALSE\n");
381 return FALSE;
382 }
383
384 /*
385 MSDN:
386 The system restricts which processes can set the foreground window. A process
387 can set the foreground window only if one of the following conditions is true:
388
389 * The process is the foreground process.
390 * The process was started by the foreground process.
391 * The process received the last input event.
392 * There is no foreground process.
393 * The foreground process is being debugged.
394 * The foreground is not locked (see LockSetForegroundWindow).
395 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
396 * No menus are active.
397 */
398 static
399 BOOL FASTCALL
400 co_IntSetForegroundAndFocusWindow(
401 _In_ PWND Wnd,
402 _In_ BOOL MouseActivate)
403 {
404 HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
405 HWND hWndPrev = NULL;
406 PWND pWndPrev = NULL;
407 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
408 PTHREADINFO pti;
409 BOOL fgRet = FALSE, Ret = FALSE;
410
411 if (Wnd) ASSERT_REFS_CO(Wnd);
412
413 //ERR("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
414
415 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
416 pti = PsGetCurrentThreadWin32Thread();
417
418 if (PrevForegroundQueue)
419 { // Same Window Q as foreground just do active.
420 if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue)
421 {
422 //ERR("Same Window Q as foreground just do active.\n");
423 if (pti->MessageQueue == PrevForegroundQueue)
424 { // Same WQ and TQ go active.
425 //ERR("Same WQ and TQ go active.\n");
426 Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
427 }
428 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
429 { // Same WQ and it is active.
430 //ERR("Same WQ and it is active.\n");
431 Ret = TRUE;
432 }
433 else
434 { // Same WQ as FG but not the same TQ send active.
435 //ERR("Same WQ as FG but not the same TQ send active.\n");
436 co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
437 Ret = TRUE;
438 }
439 return Ret;
440 }
441
442 hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0;
443 pWndPrev = PrevForegroundQueue->spwndActive;
444 }
445
446 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
447 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
448 pti->ppi == ppiScrnSaver
449 )
450 {
451
452 //ToggleFGActivate(pti); // win.c line 2662 fail
453 if (Wnd)
454 {
455 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
456 gptiForeground = Wnd->head.pti;
457 //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
458 }
459 else
460 {
461 IntSetFocusMessageQueue(NULL);
462 gptiForeground = NULL;
463 //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
464 }
465 /*
466 Henri Verbeet,
467 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
468 other thread after we already changed the foreground window back to our own
469 window.
470 */
471 //ERR("SFAFW: 1\n");
472 FindRemoveAsyncMsg(Wnd, 0); // Do this to fix test_SFW todos!
473
474 fgRet = TRUE;
475 }
476
477 // Fix FG Bounce with regedit.
478 if (hWndPrev != hWnd )
479 {
480 if (PrevForegroundQueue &&
481 fgRet &&
482 PrevForegroundQueue->spwndActive)
483 {
484 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
485 if (pti->MessageQueue == PrevForegroundQueue)
486 {
487 //ERR("SFGW: TI same as Prev TI\n");
488 co_IntSetActiveWindow(NULL, FALSE, TRUE, FALSE);
489 }
490 else if (pWndPrev)
491 {
492 //ERR("SFGW Deactivate: TI not same as Prev TI\n");
493 // No real reason to wait here.
494 co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
495 }
496 }
497 }
498
499 if (!Wnd) return FALSE; // Always return false.
500
501 if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
502 {
503 //ERR("Same PQ and WQ go active.\n");
504 Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
505 }
506 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
507 {
508 //ERR("Same Active and Wnd.\n");
509 Ret = TRUE;
510 }
511 else
512 {
513 //ERR("Activate Not same PQ and WQ and Wnd.\n");
514 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
515 Ret = TRUE;
516 }
517 return Ret && fgRet;
518 }
519
520 BOOL FASTCALL
521 co_IntMouseActivateWindow(PWND Wnd)
522 {
523 HWND Top;
524 PWND TopWindow;
525 USER_REFERENCE_ENTRY Ref;
526
527 ASSERT_REFS_CO(Wnd);
528
529 if (Wnd->style & WS_DISABLED)
530 {
531 BOOL Ret;
532 PWND TopWnd;
533 PWND DesktopWindow = UserGetDesktopWindow();
534 if (DesktopWindow)
535 {
536 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
537 if ((TopWnd = ValidateHwndNoErr(Top)))
538 {
539 UserRefObjectCo(TopWnd, &Ref);
540 Ret = co_IntMouseActivateWindow(TopWnd);
541 UserDerefObjectCo(TopWnd);
542
543 return Ret;
544 }
545 }
546 return FALSE;
547 }
548
549 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
550 //if (TopWindow) {ERR("MAW 2 pWnd %p hWnd %p\n",TopWindow,TopWindow->head.h);}
551 if (!TopWindow) return FALSE;
552
553 /* TMN: Check return value from this function? */
554 UserRefObjectCo(TopWindow, &Ref);
555 co_IntSetForegroundAndFocusWindow(TopWindow, TRUE);
556 UserDerefObjectCo(TopWindow);
557 return TRUE;
558 }
559
560 BOOL FASTCALL
561 co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
562 {
563 PTHREADINFO pti;
564 PUSER_MESSAGE_QUEUE ThreadQueue;
565 PWND pWndChg, WndPrev; // State changes.
566 HWND hWndPrev;
567 HWND hWnd = 0;
568 BOOL InAAPM;
569 CBTACTIVATESTRUCT cbt;
570 //ERR("co_IntSetActiveWindow 1\n");
571 if (Wnd)
572 {
573 ASSERT_REFS_CO(Wnd);
574 hWnd = UserHMGetHandle(Wnd);
575 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
576 if (Wnd == UserGetDesktopWindow()) return FALSE;
577 //ERR("co_IntSetActiveWindow 1a hWnd 0x%p\n",hWnd);
578 }
579
580 //ERR("co_IntSetActiveWindow 2\n");
581 pti = PsGetCurrentThreadWin32Thread();
582 ThreadQueue = pti->MessageQueue;
583 ASSERT(ThreadQueue != 0);
584
585 hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
586
587 pWndChg = ThreadQueue->spwndActive; // Keep to notify of a preemptive switch.
588
589 while (Wnd)
590 {
591 BOOL Ret, DoFG, AllowFG;
592
593 if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
594
595 if (ThreadQueue == Wnd->head.pti->MessageQueue)
596 {
597 if (IsAllowedFGActive(pti, Wnd))
598 {
599 DoFG = TRUE;
600 }
601 else
602 {
603 //ERR("co_IntSetActiveWindow 3 Go Out!\n");
604 break;
605 }
606 AllowFG = !pti->cVisWindows; // Nothing is visable.
607 //ERR("co_IntSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
608 }
609 else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
610 {
611 //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
612 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
613 //if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
614 if (!gpqForeground || gpqForeground == ThreadQueue)
615 {
616 DoFG = TRUE;
617 }
618 else
619 DoFG = FALSE;
620 if (DoFG)
621 {
622 if (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE || pti->cVisWindows)
623 AllowFG = TRUE;
624 else
625 AllowFG = FALSE;
626 }
627 else
628 AllowFG = FALSE;
629 //ERR("co_IntSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
630 }
631 Ret = FALSE;
632 if (DoFG)
633 {
634 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
635 //ERR("co_IntSetActiveWindow 3c FG set\n");
636 Ret = co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
637 if (AllowFG)
638 {
639 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
640 }
641 else
642 {
643 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
644 }
645 }
646 return Ret;
647 }
648
649 /* Call CBT hook chain */
650 cbt.fMouse = bMouse;
651 cbt.hWndActive = hWndPrev;
652 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
653 {
654 ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
655 return FALSE;
656 }
657
658 if ( ThreadQueue->spwndActive && ThreadQueue->spwndActive->state & WNDS_DESTROYED )
659 ThreadQueue->spwndActive = NULL;
660 else
661 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
662
663 WndPrev = ThreadQueue->spwndActive; // Keep to save changing active.
664
665 if (WndPrev)
666 {
667 if (ThreadQueue == gpqForeground) gpqForegroundPrev = ThreadQueue;
668 if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev), hWnd)) return FALSE;
669 }
670
671 WndPrev = ThreadQueue->spwndActive; // Again keep to save changing active.
672
673 // While in calling message proc or hook:
674 // Fail if a preemptive switch was made, current active not made previous,
675 // focus window is dead or no longer the same thread queue.
676 if ( ThreadQueue->spwndActivePrev != ThreadQueue->spwndActive ||
677 pWndChg != WndPrev ||
678 (Wnd && !VerifyWnd(Wnd)) ||
679 ThreadQueue != pti->MessageQueue )
680 {
681 ERR("SetActiveWindow: Summery ERROR, active state changed!\n");
682 return FALSE;
683 }
684
685 if (!WndPrev) ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
686
687 if (Wnd) Wnd->state |= WNDS_BEINGACTIVATED;
688
689 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
690 //// Breaks Atl-Esc/Tab via User32.
691 ////FindRemoveAsyncMsg(Wnd,(WPARAM)Wnd); // Clear out activate ASYNC messages.
692
693 /* check if the specified window can be set in the input data of a given queue */
694 if ( !Wnd || ThreadQueue == Wnd->head.pti->MessageQueue)
695 {
696 /* set the current thread active window */
697 ThreadQueue->spwndActive = Wnd;
698 }
699
700 WndPrev = VerifyWnd(ThreadQueue->spwndActivePrev); // Now should be set but verify it again.
701
702 InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async);
703
704 /* now change focus if necessary */
705 if (bFocus && !(ThreadQueue->QF_flags & QF_FOCUSNULLSINCEACTIVE))
706 {
707 /* Do not change focus if the window is no longer active */
708 if (ThreadQueue->spwndActive == Wnd)
709 {
710 if (!ThreadQueue->spwndFocus ||
711 !Wnd ||
712 UserGetAncestor(ThreadQueue->spwndFocus, GA_ROOT) != Wnd)
713 {
714 co_UserSetFocus(Wnd);
715 }
716 }
717 }
718
719 if (InAAPM)
720 {
721 pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
722 }
723
724 // FIXME: Used in the menu loop!!!
725 //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
726
727 //ERR("co_IntSetActiveWindow Exit\n");
728 if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
729 return (ThreadQueue->spwndActive == Wnd);
730 }
731
732 BOOL FASTCALL
733 UserSetActiveWindow(PWND Wnd)
734 {
735 if (Wnd) // Must have a window!
736 {
737 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
738
739 return co_IntSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
740 }
741 /*
742 Yes your eye are not deceiving you~!
743
744 First part of wines Win.c test_SetActiveWindow:
745
746 flush_events( TRUE );
747 ShowWindow(hwnd, SW_HIDE);
748 SetFocus(0);
749 SetActiveWindow(0);
750 check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
751
752 */
753 return FALSE;
754 }
755
756 HWND FASTCALL
757 co_UserSetFocus(PWND Window)
758 {
759 HWND hWndPrev = 0;
760 PWND pwndTop;
761 PTHREADINFO pti;
762 PUSER_MESSAGE_QUEUE ThreadQueue;
763
764 if (Window)
765 ASSERT_REFS_CO(Window);
766
767 pti = PsGetCurrentThreadWin32Thread();
768 ThreadQueue = pti->MessageQueue;
769 ASSERT(ThreadQueue != 0);
770
771 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window ? UserHMGetHandle(Window) : 0, pti );
772
773 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
774
775 if (Window != 0)
776 {
777 if (hWndPrev == UserHMGetHandle(Window))
778 {
779 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0; /* Nothing to do */
780 }
781
782 if (Window->head.pti->MessageQueue != ThreadQueue)
783 {
784 ERR("SetFocus Must have the same Q!\n");
785 return 0;
786 }
787
788 /* Check if we can set the focus to this window */
789 for (pwndTop = Window; pwndTop != NULL; pwndTop = pwndTop->spwndParent)
790 {
791 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
792 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
793 }
794
795 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
796 {
797 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
798 return 0;
799 }
800
801 /* Activate pwndTop if needed. */
802 if (pwndTop != ThreadQueue->spwndActive)
803 {
804 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
805 if (ThreadQueue != ForegroundQueue && IsAllowedFGActive(pti, pwndTop)) // Rule 2 & 3.
806 {
807 //ERR("SetFocus: Set Foreground!\n");
808 if (!(pwndTop->style & WS_VISIBLE))
809 {
810 pti->ppi->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE;
811 }
812 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE))
813 {
814 ERR("SetFocus: Set Foreground and Focus Failed!\n");
815 return 0;
816 }
817 }
818
819 /* Set Active when it is needed. */
820 if (pwndTop != ThreadQueue->spwndActive)
821 {
822 //ERR("SetFocus: Set Active!\n");
823 if (!co_IntSetActiveWindow(pwndTop, FALSE, FALSE, FALSE))
824 {
825 ERR("SetFocus: Set Active Failed!\n");
826 return 0;
827 }
828 }
829
830 /* Abort if window destroyed */
831 if (Window->state2 & WNDS2_INDESTROY) return 0;
832 /* Do not change focus if the window is no longer active */
833 if (pwndTop != ThreadQueue->spwndActive)
834 {
835 ERR("SetFocus: Top window did not go active!\n");
836 return 0;
837 }
838 }
839
840 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
841 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
842
843 IntSendFocusMessages( pti, Window);
844
845 TRACE("Focus: %p -> %p\n", hWndPrev, Window->head.h);
846 }
847 else /* NULL hwnd passed in */
848 {
849 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
850 {
851 ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
852 return 0;
853 }
854
855 /* set the current thread focus window null */
856 IntSendFocusMessages( pti, NULL);
857 }
858 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
859 }
860
861 HWND FASTCALL
862 UserGetForegroundWindow(VOID)
863 {
864 PUSER_MESSAGE_QUEUE ForegroundQueue;
865
866 ForegroundQueue = IntGetFocusMessageQueue();
867 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
868 }
869
870 HWND FASTCALL UserGetActiveWindow(VOID)
871 {
872 PTHREADINFO pti;
873 PUSER_MESSAGE_QUEUE ThreadQueue;
874
875 pti = PsGetCurrentThreadWin32Thread();
876 ThreadQueue = pti->MessageQueue;
877 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
878 }
879
880 HWND APIENTRY
881 IntGetCapture(VOID)
882 {
883 PTHREADINFO pti;
884 PUSER_MESSAGE_QUEUE ThreadQueue;
885 DECLARE_RETURN(HWND);
886
887 TRACE("Enter IntGetCapture\n");
888
889 pti = PsGetCurrentThreadWin32Thread();
890 ThreadQueue = pti->MessageQueue;
891 RETURN( ThreadQueue ? (ThreadQueue->spwndCapture ? UserHMGetHandle(ThreadQueue->spwndCapture) : 0) : 0);
892
893 CLEANUP:
894 TRACE("Leave IntGetCapture, ret=%p\n", _ret_);
895 END_CLEANUP;
896 }
897
898 HWND FASTCALL
899 co_UserSetCapture(HWND hWnd)
900 {
901 PTHREADINFO pti;
902 PUSER_MESSAGE_QUEUE ThreadQueue;
903 PWND pWnd, Window = NULL;
904 HWND hWndPrev;
905
906 pti = PsGetCurrentThreadWin32Thread();
907 ThreadQueue = pti->MessageQueue;
908
909 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
910 return NULL;
911
912 if (hWnd && (Window = UserGetWindowObject(hWnd)))
913 {
914 if (Window->head.pti->MessageQueue != ThreadQueue)
915 {
916 return NULL;
917 }
918 }
919
920 hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd);
921
922 if (hWndPrev)
923 {
924 pWnd = UserGetWindowObject(hWndPrev);
925 if (pWnd)
926 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
927 }
928
929 if (Window)
930 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
931
932 if (hWndPrev && hWndPrev != hWnd)
933 {
934 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
935
936 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
937
938 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
939 }
940
941 ThreadQueue->spwndCapture = Window;
942
943 if (hWnd == NULL) // Release mode.
944 {
945 MOUSEINPUT mi;
946 /// These are HACKS!
947 /* Also remove other windows if not capturing anymore */
948 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
949 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
950 ///
951 /* Somebody may have missed some mouse movements */
952 mi.dx = 0;
953 mi.dy = 0;
954 mi.mouseData = 0;
955 mi.dwFlags = MOUSEEVENTF_MOVE;
956 mi.time = 0;
957 mi.dwExtraInfo = 0;
958 UserSendMouseInput(&mi, FALSE);
959 }
960 return hWndPrev;
961 }
962
963 /*
964 API Call
965 */
966 BOOL
967 FASTCALL
968 IntReleaseCapture(VOID)
969 {
970 PTHREADINFO pti;
971 PUSER_MESSAGE_QUEUE ThreadQueue;
972
973 pti = PsGetCurrentThreadWin32Thread();
974 ThreadQueue = pti->MessageQueue;
975
976 // Can not release inside WM_CAPTURECHANGED!!
977 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
978
979 co_UserSetCapture(NULL);
980
981 return TRUE;
982 }
983
984 /*
985 API Call
986 */
987 BOOL FASTCALL
988 co_IntSetForegroundWindow(PWND Window)
989 {
990 if (Window) ASSERT_REFS_CO(Window);
991
992 return co_IntSetForegroundAndFocusWindow(Window, FALSE);
993 }
994
995 /*
996 API Call
997 */
998 BOOL FASTCALL
999 co_IntSetForegroundWindowMouse(PWND Window)
1000 {
1001 if (Window) ASSERT_REFS_CO(Window);
1002
1003 return co_IntSetForegroundAndFocusWindow(Window, TRUE);
1004 }
1005
1006 /*
1007 API Call
1008 */
1009 BOOL FASTCALL
1010 IntLockSetForegroundWindow(UINT uLockCode)
1011 {
1012 ULONG Err = ERROR_ACCESS_DENIED;
1013 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1014 switch (uLockCode)
1015 {
1016 case LSFW_LOCK:
1017 if ( CanForceFG(ppi) && !gppiLockSFW )
1018 {
1019 gppiLockSFW = ppi;
1020 return TRUE;
1021 }
1022 break;
1023 case LSFW_UNLOCK:
1024 if ( gppiLockSFW == ppi)
1025 {
1026 gppiLockSFW = NULL;
1027 return TRUE;
1028 }
1029 break;
1030 default:
1031 Err = ERROR_INVALID_PARAMETER;
1032 }
1033 EngSetLastError(Err);
1034 return FALSE;
1035 }
1036
1037 /*
1038 API Call
1039 */
1040 BOOL FASTCALL
1041 IntAllowSetForegroundWindow(DWORD dwProcessId)
1042 {
1043 PPROCESSINFO ppi, ppiCur;
1044 PEPROCESS Process = NULL;
1045
1046 ppi = NULL;
1047 if (dwProcessId != ASFW_ANY)
1048 {
1049 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)dwProcessId, &Process)))
1050 {
1051 EngSetLastError(ERROR_INVALID_PARAMETER);
1052 return FALSE;
1053 }
1054 ppi = PsGetProcessWin32Process(Process);
1055 if (!ppi)
1056 {
1057 ObDereferenceObject(Process);
1058 return FALSE;
1059 }
1060 }
1061 ppiCur = PsGetCurrentProcessWin32Process();
1062 if (!CanForceFG(ppiCur))
1063 {
1064 if (Process) ObDereferenceObject(Process);
1065 EngSetLastError(ERROR_ACCESS_DENIED);
1066 return FALSE;
1067 }
1068 if (dwProcessId == ASFW_ANY)
1069 { // All processes will be enabled to set the foreground window.
1070 //ERR("ptiLastInput is CLEARED!!\n");
1071 ptiLastInput = NULL;
1072 }
1073 else
1074 { // Rule #3, last input event in force.
1075 ERR("ptiLastInput is SET!!\n");
1076 //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030.
1077 ObDereferenceObject(Process);
1078 }
1079 return TRUE;
1080 }
1081
1082 /*
1083 * @implemented
1084 */
1085 HWND APIENTRY
1086 NtUserGetForegroundWindow(VOID)
1087 {
1088 DECLARE_RETURN(HWND);
1089
1090 TRACE("Enter NtUserGetForegroundWindow\n");
1091 UserEnterExclusive();
1092
1093 RETURN( UserGetForegroundWindow());
1094
1095 CLEANUP:
1096 TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_);
1097 UserLeave();
1098 END_CLEANUP;
1099 }
1100
1101 HWND APIENTRY
1102 NtUserSetActiveWindow(HWND hWnd)
1103 {
1104 USER_REFERENCE_ENTRY Ref;
1105 HWND hWndPrev;
1106 PWND Window;
1107 DECLARE_RETURN(HWND);
1108
1109 TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd);
1110 UserEnterExclusive();
1111
1112 Window = NULL;
1113 if (hWnd)
1114 {
1115 if (!(Window = UserGetWindowObject(hWnd)))
1116 {
1117 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd);
1118 RETURN( NULL);
1119 }
1120 }
1121
1122 if (!Window ||
1123 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
1124 {
1125 hWndPrev = gptiCurrent->MessageQueue->spwndActive ? UserHMGetHandle(gptiCurrent->MessageQueue->spwndActive) : NULL;
1126 if (Window) UserRefObjectCo(Window, &Ref);
1127 UserSetActiveWindow(Window);
1128 if (Window) UserDerefObjectCo(Window);
1129 RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
1130 }
1131 RETURN( NULL);
1132
1133 CLEANUP:
1134 TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_);
1135 UserLeave();
1136 END_CLEANUP;
1137 }
1138
1139 /*
1140 * @implemented
1141 */
1142 HWND APIENTRY
1143 NtUserSetCapture(HWND hWnd)
1144 {
1145 DECLARE_RETURN(HWND);
1146
1147 TRACE("Enter NtUserSetCapture(%p)\n", hWnd);
1148 UserEnterExclusive();
1149
1150 RETURN( co_UserSetCapture(hWnd));
1151
1152 CLEANUP:
1153 TRACE("Leave NtUserSetCapture, ret=%p\n", _ret_);
1154 UserLeave();
1155 END_CLEANUP;
1156 }
1157
1158 /*
1159 * @implemented
1160 */
1161 HWND APIENTRY
1162 NtUserSetFocus(HWND hWnd)
1163 {
1164 PWND Window;
1165 USER_REFERENCE_ENTRY Ref;
1166 DECLARE_RETURN(HWND);
1167 HWND ret;
1168
1169 TRACE("Enter NtUserSetFocus(%p)\n", hWnd);
1170 UserEnterExclusive();
1171
1172 if (hWnd)
1173 {
1174 if (!(Window = UserGetWindowObject(hWnd)))
1175 {
1176 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd);
1177 RETURN(NULL);
1178 }
1179
1180 UserRefObjectCo(Window, &Ref);
1181 ret = co_UserSetFocus(Window);
1182 UserDerefObjectCo(Window);
1183
1184 RETURN(ret);
1185 }
1186 else
1187 {
1188 RETURN( co_UserSetFocus(0));
1189 }
1190
1191 CLEANUP:
1192 TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_);
1193 UserLeave();
1194 END_CLEANUP;
1195 }
1196
1197 /* EOF */