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