[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: 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
15 HWND FASTCALL
16 IntGetCaptureWindow(VOID)
17 {
18 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
19 return ForegroundQueue != NULL ? ForegroundQueue->CaptureWindow : 0;
20 }
21
22 HWND FASTCALL
23 UserGetFocusWindow(VOID)
24 {
25 PTHREADINFO pti;
26 PUSER_MESSAGE_QUEUE ThreadQueue;
27
28 pti = PsGetCurrentThreadWin32Thread();
29 ThreadQueue = pti->MessageQueue;
30 /* Is it a foreground queue? */
31 if (!ThreadQueue || ThreadQueue != IntGetFocusMessageQueue())
32 return NULL;
33 return ThreadQueue->FocusWindow;
34 }
35
36 HWND FASTCALL
37 IntGetThreadFocusWindow(VOID)
38 {
39 PTHREADINFO pti;
40 PUSER_MESSAGE_QUEUE ThreadQueue;
41
42 pti = PsGetCurrentThreadWin32Thread();
43 ThreadQueue = pti->MessageQueue;
44 if (!ThreadQueue)
45 return NULL;
46 return ThreadQueue->FocusWindow;
47 }
48
49 VOID FASTCALL
50 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
51 {
52 PWND WndPrev ;
53
54 if (hWndPrev && (WndPrev = UserGetWindowObject(hWndPrev)))
55 {
56 co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0);
57 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
58 MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
59 (LPARAM)hWnd);
60 }
61 }
62
63 VOID FASTCALL
64 co_IntSendActivateMessages(HWND hWndPrev, HWND hWnd, BOOL MouseActivate)
65 {
66 USER_REFERENCE_ENTRY Ref, RefPrev;
67 PWND Window, WindowPrev = NULL;
68
69 if ((Window = UserGetWindowObject(hWnd)))
70 {
71 UserRefObjectCo(Window, &Ref);
72
73 WindowPrev = UserGetWindowObject(hWndPrev);
74
75 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
76
77 /* Send palette messages */
78 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
79 co_IntPostOrSendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0))
80 {
81 UserSendNotifyMessage( HWND_BROADCAST,
82 WM_PALETTEISCHANGING,
83 (WPARAM)hWnd,
84 0);
85 }
86
87 if (Window->spwndPrev != NULL)
88 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0,
89 SWP_NOSIZE | SWP_NOMOVE);
90
91 if (!Window->spwndOwner && !IntGetParent(Window))
92 {
93 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd);
94 }
95
96 if (Window)
97 { // Set last active for window and it's owner.
98 Window->hWndLastActive = hWnd;
99 if (Window->spwndOwner)
100 Window->spwndOwner->hWndLastActive = hWnd;
101 Window->state |= WNDS_ACTIVEFRAME;
102 }
103
104 if (WindowPrev)
105 WindowPrev->state &= ~WNDS_ACTIVEFRAME;
106
107 if (Window && WindowPrev)
108 {
109 PWND cWindow;
110 HWND *List, *phWnd;
111 HANDLE OldTID = IntGetWndThreadId(WindowPrev);
112 HANDLE NewTID = IntGetWndThreadId(Window);
113
114 TRACE("SendActiveMessage Old -> %x, New -> %x\n", OldTID, NewTID);
115 if (Window->style & WS_MINIMIZE)
116 {
117 TRACE("Widow was minimized\n");
118 }
119
120 if (OldTID != NewTID)
121 {
122 List = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
123 if (List)
124 {
125 for (phWnd = List; *phWnd; ++phWnd)
126 {
127 cWindow = UserGetWindowObject(*phWnd);
128
129 if (cWindow && (IntGetWndThreadId(cWindow) == OldTID))
130 { // FALSE if the window is being deactivated,
131 // ThreadId that owns the window being activated.
132 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
133 }
134 }
135 for (phWnd = List; *phWnd; ++phWnd)
136 {
137 cWindow = UserGetWindowObject(*phWnd);
138 if (cWindow && (IntGetWndThreadId(cWindow) == NewTID))
139 { // TRUE if the window is being activated,
140 // ThreadId that owns the window being deactivated.
141 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
142 }
143 }
144 ExFreePool(List);
145 }
146 }
147 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
148 }
149
150 UserDerefObjectCo(Window);
151
152 /* FIXME: IntIsWindow */
153 co_IntSendMessageNoWait(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == UserGetForegroundWindow()), 0);
154 /* FIXME: WA_CLICKACTIVE */
155 co_IntSendMessageNoWait(hWnd, WM_ACTIVATE,
156 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE,
157 Window->style & WS_MINIMIZE),
158 (LPARAM)hWndPrev);
159 }
160 }
161
162 VOID FASTCALL
163 co_IntSendKillFocusMessages(HWND hWndPrev, HWND hWnd)
164 {
165 if (hWndPrev)
166 {
167 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
168 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
169 }
170 }
171
172 VOID FASTCALL
173 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
174 {
175 if (hWnd)
176 {
177 PWND pWnd = UserGetWindowObject(hWnd);
178 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
179 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
180 }
181 }
182
183 HWND FASTCALL
184 IntFindChildWindowToOwner(PWND Root, PWND Owner)
185 {
186 HWND Ret;
187 PWND Child, OwnerWnd;
188
189 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
190 {
191 OwnerWnd = Child->spwndOwner;
192 if(!OwnerWnd)
193 continue;
194
195 if(OwnerWnd == Owner)
196 {
197 Ret = Child->head.h;
198 return Ret;
199 }
200 }
201
202 return NULL;
203 }
204
205 /*
206 MSDN:
207 The system restricts which processes can set the foreground window. A process
208 can set the foreground window only if one of the following conditions is true:
209
210 * The process is the foreground process.
211 * The process was started by the foreground process.
212 * The process received the last input event.
213 * There is no foreground process.
214 * The foreground process is being debugged.
215 * The foreground is not locked (see LockSetForegroundWindow).
216 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
217 * No menus are active.
218 */
219 static BOOL FASTCALL
220 co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate)
221 {
222 CBTACTIVATESTRUCT cbt;
223 HWND hWnd = Wnd->head.h;
224 HWND hWndPrev = NULL;
225 HWND hWndFocus = FocusWindow->head.h;
226 HWND hWndFocusPrev = NULL;
227 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
228
229 ASSERT_REFS_CO(Wnd);
230
231 TRACE("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, hWndFocus, MouseActivate ? "TRUE" : "FALSE");
232
233 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
234 {
235 TRACE("Failed - Child\n");
236 return FALSE;
237 }
238
239 if (0 == (Wnd->style & WS_VISIBLE) &&
240 Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess)
241 {
242 ERR("Failed - Invisible\n");
243 return FALSE;
244 }
245
246 PrevForegroundQueue = IntGetFocusMessageQueue();
247 if (PrevForegroundQueue != 0)
248 {
249 hWndPrev = PrevForegroundQueue->ActiveWindow;
250 hWndFocusPrev = PrevForegroundQueue->FocusWindow;
251 }
252
253 if (hWndPrev == hWnd)
254 {
255 TRACE("Failed - Same\n");
256 return TRUE;
257 }
258
259 /* Call CBT hook chain */
260 cbt.fMouse = MouseActivate;
261 cbt.hWndActive = hWndPrev;
262 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
263 {
264 ERR("IntSetForegroundAndFocusWindow WH_CBT Call Hook return!\n");
265 return 0;
266 }
267
268 co_IntSendDeactivateMessages(hWndPrev, hWnd);
269 co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
270
271
272 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
273
274 if (Wnd->head.pti->MessageQueue)
275 {
276 Wnd->head.pti->MessageQueue->ActiveWindow = hWnd;
277 }
278
279 if (FocusWindow->head.pti->MessageQueue)
280 {
281 FocusWindow->head.pti->MessageQueue->FocusWindow = hWndFocus;
282 }
283
284 if (PrevForegroundQueue != Wnd->head.pti->MessageQueue)
285 {
286 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
287 }
288
289 co_IntSendSetFocusMessages(hWndFocusPrev, hWndFocus);
290 co_IntSendActivateMessages(hWndPrev, hWnd, MouseActivate);
291
292 return TRUE;
293 }
294
295 BOOL FASTCALL
296 co_IntSetForegroundWindow(PWND Window) // FIXME: Can Window be NULL??
297 {
298 /*if (Window)*/ ASSERT_REFS_CO(Window);
299
300 return co_IntSetForegroundAndFocusWindow(Window, Window, FALSE);
301 }
302
303 BOOL FASTCALL
304 co_IntMouseActivateWindow(PWND Wnd)
305 {
306 HWND Top;
307 PWND TopWindow;
308 USER_REFERENCE_ENTRY Ref;
309
310 ASSERT_REFS_CO(Wnd);
311
312 if(Wnd->style & WS_DISABLED)
313 {
314 BOOL Ret;
315 PWND TopWnd;
316 PWND DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
317 if(DesktopWindow)
318 {
319 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
320 if((TopWnd = UserGetWindowObject(Top)))
321 {
322 UserRefObjectCo(TopWnd, &Ref);
323 Ret = co_IntMouseActivateWindow(TopWnd);
324 UserDerefObjectCo(TopWnd);
325
326 return Ret;
327 }
328 }
329 return FALSE;
330 }
331
332
333 TopWindow = UserGetAncestor(Wnd, GA_ROOT);
334 if (!TopWindow) return FALSE;
335
336 /* TMN: Check return valud from this function? */
337 UserRefObjectCo(TopWindow, &Ref);
338
339 co_IntSetForegroundAndFocusWindow(TopWindow, Wnd, TRUE);
340
341 UserDerefObjectCo(TopWindow);
342
343 return TRUE;
344 }
345
346 HWND FASTCALL
347 co_IntSetActiveWindow(PWND Wnd OPTIONAL)
348 {
349 PTHREADINFO pti;
350 PUSER_MESSAGE_QUEUE ThreadQueue;
351 HWND hWndPrev;
352 HWND hWnd = 0;
353 CBTACTIVATESTRUCT cbt;
354
355 if (Wnd)
356 ASSERT_REFS_CO(Wnd);
357
358 pti = PsGetCurrentThreadWin32Thread();
359 ThreadQueue = pti->MessageQueue;
360 ASSERT(ThreadQueue != 0);
361
362 if (Wnd != 0)
363 {
364 if ((Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
365 {
366 /* Windows doesn't seem to return an error here */
367 return ThreadQueue->ActiveWindow;
368 }
369 hWnd = Wnd->head.h;
370 }
371
372 hWndPrev = ThreadQueue->ActiveWindow;
373 if (hWndPrev == hWnd)
374 {
375 return hWndPrev;
376 }
377
378 /* Call CBT hook chain */
379 cbt.fMouse = FALSE;
380 cbt.hWndActive = hWndPrev;
381 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
382 {
383 ERR("SetActiveWindow WH_CBT Call Hook return!\n");
384 return 0;
385 }
386
387 co_IntSendDeactivateMessages(hWndPrev, hWnd);
388
389 ThreadQueue->ActiveWindow = hWnd;
390
391 co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
392
393 /* FIXME */
394 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
395 return hWndPrev;
396 }
397
398 HWND FASTCALL
399 co_UserSetFocus(PWND Window)
400 {
401 HWND hWndPrev = 0;
402 PWND pwndTop;
403 PTHREADINFO pti;
404 PUSER_MESSAGE_QUEUE ThreadQueue;
405
406 if (Window)
407 ASSERT_REFS_CO(Window);
408
409 pti = PsGetCurrentThreadWin32Thread();
410 ThreadQueue = pti->MessageQueue;
411 ASSERT(ThreadQueue != 0);
412
413 hWndPrev = ThreadQueue->FocusWindow;
414
415 if (Window != 0)
416 {
417 if (hWndPrev == Window->head.h)
418 {
419 return hWndPrev; /* Nothing to do */
420 }
421
422 /* Check if we can set the focus to this window */
423 for (pwndTop = Window; pwndTop != NULL; pwndTop = pwndTop->spwndParent )
424 {
425 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
426 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
427 }
428
429 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
430 {
431 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
432 return 0;
433 }
434
435 /* Activate pwndTop if needed. */
436 if (pwndTop->head.h != ThreadQueue->ActiveWindow)
437 {
438 co_IntSetActiveWindow(pwndTop);
439 /* Abort if window destroyed */
440 if (Window->state2 & WNDS2_INDESTROY) return 0;
441 /* Do not change focus if the window is no longer active */
442 if (pwndTop->head.h != ThreadQueue->ActiveWindow)
443 {
444 ERR("SetFocus Top window did not go active!\n");
445 return 0;
446 }
447 }
448
449 ThreadQueue->FocusWindow = Window->head.h;
450 TRACE("Focus: %d -> %d\n", hWndPrev, Window->head.h);
451
452 co_IntSendKillFocusMessages(hWndPrev, Window->head.h);
453 co_IntSendSetFocusMessages(hWndPrev, Window->head.h);
454 }
455 else
456 {
457 ThreadQueue->FocusWindow = 0;
458 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
459 {
460 ERR("SetFocusWindow 2 WH_CBT Call Hook return!\n");
461 return 0;
462 }
463
464 co_IntSendKillFocusMessages(hWndPrev, 0);
465 }
466 return hWndPrev;
467 }
468
469 HWND FASTCALL
470 UserGetForegroundWindow(VOID)
471 {
472 PUSER_MESSAGE_QUEUE ForegroundQueue;
473
474 ForegroundQueue = IntGetFocusMessageQueue();
475 return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
476 }
477
478 HWND FASTCALL UserGetActiveWindow(VOID)
479 {
480 PTHREADINFO pti;
481 PUSER_MESSAGE_QUEUE ThreadQueue;
482
483 pti = PsGetCurrentThreadWin32Thread();
484 ThreadQueue = pti->MessageQueue;
485 return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
486 }
487
488 HWND APIENTRY
489 IntGetCapture(VOID)
490 {
491 PTHREADINFO pti;
492 PUSER_MESSAGE_QUEUE ThreadQueue;
493 DECLARE_RETURN(HWND);
494
495 TRACE("Enter IntGetCapture\n");
496
497 pti = PsGetCurrentThreadWin32Thread();
498 ThreadQueue = pti->MessageQueue;
499 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
500
501 CLEANUP:
502 TRACE("Leave IntGetCapture, ret=%i\n",_ret_);
503 END_CLEANUP;
504 }
505
506 HWND FASTCALL
507 co_UserSetCapture(HWND hWnd)
508 {
509 PTHREADINFO pti;
510 PUSER_MESSAGE_QUEUE ThreadQueue;
511 PWND Window, pWnd;
512 HWND hWndPrev;
513
514 pti = PsGetCurrentThreadWin32Thread();
515 ThreadQueue = pti->MessageQueue;
516
517 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
518 return NULL;
519
520 if ((Window = UserGetWindowObject(hWnd)))
521 {
522 if (Window->head.pti->MessageQueue != ThreadQueue)
523 {
524 return NULL;
525 }
526 }
527
528 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
529
530 if (hWndPrev)
531 {
532 pWnd = UserGetWindowObject(hWndPrev);
533 if (pWnd)
534 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
535 }
536
537 if (Window)
538 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
539
540 if (hWndPrev && hWndPrev != hWnd)
541 {
542 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
543
544 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
545
546 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
547 }
548
549 ThreadQueue->CaptureWindow = hWnd;
550
551 if (hWnd == NULL) // Release mode.
552 {
553 MOUSEINPUT mi;
554 /// These are HACKS!
555 /* Also remove other windows if not capturing anymore */
556 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
557 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
558 ///
559 /* Somebody may have missed some mouse movements */
560 mi.dx = 0;
561 mi.dy = 0;
562 mi.mouseData = 0;
563 mi.dwFlags = MOUSEEVENTF_MOVE;
564 mi.time = 0;
565 mi.dwExtraInfo = 0;
566 UserSendMouseInput(&mi, FALSE);
567 }
568 return hWndPrev;
569 }
570
571 BOOL
572 FASTCALL
573 IntReleaseCapture(VOID)
574 {
575 PTHREADINFO pti;
576 PUSER_MESSAGE_QUEUE ThreadQueue;
577
578 pti = PsGetCurrentThreadWin32Thread();
579 ThreadQueue = pti->MessageQueue;
580
581 // Can not release inside WM_CAPTURECHANGED!!
582 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
583
584 co_UserSetCapture(NULL);
585
586 return TRUE;
587 }
588
589 /*
590 * @implemented
591 */
592 HWND APIENTRY
593 NtUserGetForegroundWindow(VOID)
594 {
595 DECLARE_RETURN(HWND);
596
597 TRACE("Enter NtUserGetForegroundWindow\n");
598 UserEnterExclusive();
599
600 RETURN( UserGetForegroundWindow());
601
602 CLEANUP:
603 TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
604 UserLeave();
605 END_CLEANUP;
606 }
607
608 HWND APIENTRY
609 NtUserSetActiveWindow(HWND hWnd)
610 {
611 USER_REFERENCE_ENTRY Ref;
612 DECLARE_RETURN(HWND);
613
614 TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd);
615 UserEnterExclusive();
616
617 if (hWnd)
618 {
619 PWND Window;
620 PTHREADINFO pti;
621 PUSER_MESSAGE_QUEUE ThreadQueue;
622 HWND hWndPrev;
623
624 if (!(Window = UserGetWindowObject(hWnd)))
625 {
626 RETURN( 0);
627 }
628
629 pti = PsGetCurrentThreadWin32Thread();
630 ThreadQueue = pti->MessageQueue;
631
632 if (Window->head.pti->MessageQueue != ThreadQueue)
633 {
634 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
635 RETURN( 0);
636 }
637
638 UserRefObjectCo(Window, &Ref);
639 hWndPrev = co_IntSetActiveWindow(Window);
640 UserDerefObjectCo(Window);
641
642 RETURN( hWndPrev);
643 }
644 else
645 {
646 RETURN( co_IntSetActiveWindow(0));
647 }
648
649 CLEANUP:
650 TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
651 UserLeave();
652 END_CLEANUP;
653 }
654
655 /*
656 * @implemented
657 */
658 HWND APIENTRY
659 NtUserSetCapture(HWND hWnd)
660 {
661 DECLARE_RETURN(HWND);
662
663 TRACE("Enter NtUserSetCapture(%x)\n", hWnd);
664 UserEnterExclusive();
665
666 RETURN( co_UserSetCapture(hWnd));
667
668 CLEANUP:
669 TRACE("Leave NtUserSetCapture, ret=%i\n",_ret_);
670 UserLeave();
671 END_CLEANUP;
672 }
673
674 /*
675 * @implemented
676 */
677 HWND APIENTRY
678 NtUserSetFocus(HWND hWnd)
679 {
680 PWND Window;
681 USER_REFERENCE_ENTRY Ref;
682 DECLARE_RETURN(HWND);
683 HWND ret;
684
685 TRACE("Enter NtUserSetFocus(%x)\n", hWnd);
686 UserEnterExclusive();
687
688 if (hWnd)
689 {
690 if (!(Window = UserGetWindowObject(hWnd)))
691 {
692 RETURN(NULL);
693 }
694
695 UserRefObjectCo(Window, &Ref);
696 ret = co_UserSetFocus(Window);
697 UserDerefObjectCo(Window);
698
699 RETURN(ret);
700 }
701 else
702 {
703 RETURN( co_UserSetFocus(0));
704 }
705
706 CLEANUP:
707 TRACE("Leave NtUserSetFocus, ret=%i\n",_ret_);
708 UserLeave();
709 END_CLEANUP;
710 }
711
712 /* EOF */