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