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