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