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