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