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