Sync with trunk r47129
[reactos.git] / subsystems / win32 / win32k / ntuser / focus.c
1 /*
2 * ReactOS Win32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21 #include <win32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 HWND FASTCALL
27 IntGetCaptureWindow(VOID)
28 {
29 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
30 return ForegroundQueue != NULL ? ForegroundQueue->CaptureWindow : 0;
31 }
32
33 HWND FASTCALL
34 IntGetFocusWindow(VOID)
35 {
36 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
37 return ForegroundQueue != NULL ? ForegroundQueue->FocusWindow : 0;
38 }
39
40 HWND FASTCALL
41 IntGetThreadFocusWindow(VOID)
42 {
43 PTHREADINFO pti;
44 PUSER_MESSAGE_QUEUE ThreadQueue;
45
46 pti = PsGetCurrentThreadWin32Thread();
47 ThreadQueue = pti->MessageQueue;
48 return ThreadQueue != NULL ? ThreadQueue->FocusWindow : 0;
49 }
50
51 VOID FASTCALL
52 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
53 {
54 if (hWndPrev)
55 {
56 co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0);
57 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
58 MAKEWPARAM(WA_INACTIVE, UserGetWindowLong(hWndPrev, GWL_STYLE, FALSE) & 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 PWINDOW_OBJECT 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 (co_IntPostOrSendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0))
79 {
80 UserPostMessage( HWND_BROADCAST,
81 WM_PALETTEISCHANGING,
82 (WPARAM)hWnd,
83 0);
84 }
85
86 if (UserGetWindow(hWnd, GW_HWNDPREV) != NULL)
87 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0,
88 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
89
90 if (!IntGetOwner(Window) && !IntGetParent(Window))
91 {
92 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (LPARAM) hWnd);
93 }
94
95 if (Window->Wnd)
96 { // Set last active for window and it's owner.
97 Window->Wnd->hWndLastActive = hWnd;
98 if (Window->Wnd->spwndOwner)
99 Window->Wnd->spwndOwner->hWndLastActive = hWnd;
100 Window->Wnd->state |= WNDS_ACTIVEFRAME;
101 }
102
103 if (WindowPrev && WindowPrev->Wnd)
104 WindowPrev->Wnd->state &= ~WNDS_ACTIVEFRAME;
105
106 if (Window && WindowPrev)
107 {
108 HANDLE OldTID = IntGetWndThreadId(WindowPrev);
109 HANDLE NewTID = IntGetWndThreadId(Window);
110
111 DPRINT1("SendActiveMessage Old -> %x, New -> %x\n", OldTID, NewTID);
112 if (Window->Wnd->style & WS_MINIMIZE)
113 {
114 DPRINT1("Widow was nminimized\n");
115 }
116
117 if (OldTID != NewTID)
118 {
119 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
120 co_IntSendMessageNoWait(hWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
121 }
122 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
123 }
124
125 UserDerefObjectCo(Window);
126
127 /* FIXME: IntIsWindow */
128 co_IntSendMessageNoWait(hWnd, WM_NCACTIVATE, (WPARAM)(hWnd == UserGetForegroundWindow()), 0);
129 /* FIXME: WA_CLICKACTIVE */
130 co_IntSendMessageNoWait(hWnd, WM_ACTIVATE,
131 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE,
132 UserGetWindowLong(hWnd, GWL_STYLE, FALSE) & WS_MINIMIZE),
133 (LPARAM)hWndPrev);
134 }
135 }
136
137 VOID FASTCALL
138 co_IntSendKillFocusMessages(HWND hWndPrev, HWND hWnd)
139 {
140 if (hWndPrev)
141 {
142 co_IntPostOrSendMessage(hWndPrev, WM_KILLFOCUS, (WPARAM)hWnd, 0);
143 }
144 }
145
146 VOID FASTCALL
147 co_IntSendSetFocusMessages(HWND hWndPrev, HWND hWnd)
148 {
149 if (hWnd)
150 {
151 co_IntPostOrSendMessage(hWnd, WM_SETFOCUS, (WPARAM)hWndPrev, 0);
152 }
153 }
154
155 HWND FASTCALL
156 IntFindChildWindowToOwner(PWINDOW_OBJECT Root, PWINDOW_OBJECT Owner)
157 {
158 HWND Ret;
159 PWINDOW_OBJECT Child, OwnerWnd;
160
161 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
162 {
163 OwnerWnd = UserGetWindowObject(Child->hOwner);
164 if(!OwnerWnd)
165 continue;
166
167 if(OwnerWnd == Owner)
168 {
169 Ret = Child->hSelf;
170 return Ret;
171 }
172 }
173
174 return NULL;
175 }
176
177 static BOOL FASTCALL
178 co_IntSetForegroundAndFocusWindow(PWINDOW_OBJECT Window, PWINDOW_OBJECT FocusWindow, BOOL MouseActivate)
179 {
180 HWND hWnd = Window->hSelf;
181 HWND hWndPrev = NULL;
182 HWND hWndFocus = FocusWindow->hSelf;
183 HWND hWndFocusPrev = NULL;
184 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
185 PWND Wnd;
186
187 ASSERT_REFS_CO(Window);
188
189 DPRINT("IntSetForegroundAndFocusWindow(%x, %x, %s)\n", hWnd, hWndFocus, MouseActivate ? "TRUE" : "FALSE");
190
191 Wnd = Window->Wnd;
192
193 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
194 {
195 DPRINT("Failed - Child\n");
196 return FALSE;
197 }
198
199 if (0 == (Wnd->style & WS_VISIBLE) &&
200 Window->pti->pEThread->ThreadsProcess != CsrProcess)
201 {
202 DPRINT("Failed - Invisible\n");
203 return FALSE;
204 }
205
206 PrevForegroundQueue = IntGetFocusMessageQueue();
207 if (PrevForegroundQueue != 0)
208 {
209 hWndPrev = PrevForegroundQueue->ActiveWindow;
210 hWndFocusPrev = PrevForegroundQueue->FocusWindow;
211 }
212
213 if (hWndPrev == hWnd)
214 {
215 DPRINT("Failed - Same\n");
216 return TRUE;
217 }
218
219 /* FIXME: Call hooks. */
220
221 co_IntSendDeactivateMessages(hWndPrev, hWnd);
222 co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
223
224
225 IntSetFocusMessageQueue(Window->pti->MessageQueue);
226
227 if (Window->pti->MessageQueue)
228 {
229 Window->pti->MessageQueue->ActiveWindow = hWnd;
230 }
231
232 if (FocusWindow->pti->MessageQueue)
233 {
234 FocusWindow->pti->MessageQueue->FocusWindow = hWndFocus;
235 }
236
237 if (PrevForegroundQueue != Window->pti->MessageQueue)
238 {
239 /* FIXME: Send WM_ACTIVATEAPP to all thread windows. */
240 }
241
242 co_IntSendSetFocusMessages(hWndFocusPrev, hWndFocus);
243 co_IntSendActivateMessages(hWndPrev, hWnd, MouseActivate);
244
245 return TRUE;
246 }
247
248 BOOL FASTCALL
249 co_IntSetForegroundWindow(PWINDOW_OBJECT Window)//FIXME: can Window be NULL??
250 {
251 /*if (Window)*/ ASSERT_REFS_CO(Window);
252
253 return co_IntSetForegroundAndFocusWindow(Window, Window, FALSE);
254 }
255
256 BOOL FASTCALL
257 co_IntMouseActivateWindow(PWINDOW_OBJECT Window)
258 {
259 HWND Top;
260 PWINDOW_OBJECT TopWindow;
261 USER_REFERENCE_ENTRY Ref;
262 PWND Wnd;
263
264 ASSERT_REFS_CO(Window);
265
266 Wnd = Window->Wnd;
267 if(Wnd->style & WS_DISABLED)
268 {
269 BOOL Ret;
270 PWINDOW_OBJECT TopWnd;
271 PWINDOW_OBJECT DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
272 if(DesktopWindow)
273 {
274 Top = IntFindChildWindowToOwner(DesktopWindow, Window);
275 if((TopWnd = UserGetWindowObject(Top)))
276 {
277 UserRefObjectCo(TopWnd, &Ref);
278 Ret = co_IntMouseActivateWindow(TopWnd);
279 UserDerefObjectCo(TopWnd);
280
281 return Ret;
282 }
283 }
284 return FALSE;
285 }
286
287
288 TopWindow = UserGetAncestor(Window, GA_ROOT);
289 if (!TopWindow) return FALSE;
290
291 /* TMN: Check return valud from this function? */
292 UserRefObjectCo(TopWindow, &Ref);
293
294 co_IntSetForegroundAndFocusWindow(TopWindow, Window, TRUE);
295
296 UserDerefObjectCo(TopWindow);
297
298 return TRUE;
299 }
300
301 HWND FASTCALL
302 co_IntSetActiveWindow(PWINDOW_OBJECT Window OPTIONAL)
303 {
304 PTHREADINFO pti;
305 PUSER_MESSAGE_QUEUE ThreadQueue;
306 HWND hWndPrev;
307 HWND hWnd = 0;
308 PWND Wnd;
309 CBTACTIVATESTRUCT cbt;
310
311 if (Window)
312 ASSERT_REFS_CO(Window);
313
314 pti = PsGetCurrentThreadWin32Thread();
315 ThreadQueue = pti->MessageQueue;
316 ASSERT(ThreadQueue != 0);
317
318 if (Window != 0)
319 {
320 Wnd = Window->Wnd;
321 if ((!(Wnd->style & WS_VISIBLE) &&
322 Window->pti->pEThread->ThreadsProcess != CsrProcess) ||
323 (Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
324 {
325 return ThreadQueue ? 0 : ThreadQueue->ActiveWindow;
326 }
327 hWnd = Window->hSelf;
328 }
329
330 hWndPrev = ThreadQueue->ActiveWindow;
331 if (hWndPrev == hWnd)
332 {
333 return hWndPrev;
334 }
335
336 /* call CBT hook chain */
337 cbt.fMouse = FALSE;
338 cbt.hWndActive = hWndPrev;
339 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
340 return 0;
341
342 ThreadQueue->ActiveWindow = hWnd;
343
344 co_IntSendDeactivateMessages(hWndPrev, hWnd);
345 co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
346
347 /* FIXME */
348 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
349 return hWndPrev;
350 }
351
352 static
353 HWND FASTCALL
354 co_IntSetFocusWindow(PWINDOW_OBJECT Window OPTIONAL)
355 {
356 HWND hWndPrev = 0;
357 PTHREADINFO pti;
358 PUSER_MESSAGE_QUEUE ThreadQueue;
359
360 if (Window)
361 ASSERT_REFS_CO(Window);
362
363 pti = PsGetCurrentThreadWin32Thread();
364 ThreadQueue = pti->MessageQueue;
365 ASSERT(ThreadQueue != 0);
366
367 hWndPrev = ThreadQueue->FocusWindow;
368
369 if (Window != 0)
370 {
371 if (hWndPrev == Window->hSelf)
372 {
373 return hWndPrev;
374 }
375
376 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->hSelf, (LPARAM)hWndPrev))
377 return 0;
378
379 ThreadQueue->FocusWindow = Window->hSelf;
380
381 co_IntSendKillFocusMessages(hWndPrev, Window->hSelf);
382 co_IntSendSetFocusMessages(hWndPrev, Window->hSelf);
383 }
384 else
385 {
386 ThreadQueue->FocusWindow = 0;
387
388 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
389 return 0;
390
391 co_IntSendKillFocusMessages(hWndPrev, 0);
392 }
393 return hWndPrev;
394 }
395
396
397 /*
398 * @implemented
399 */
400 HWND FASTCALL
401 UserGetForegroundWindow(VOID)
402 {
403 PUSER_MESSAGE_QUEUE ForegroundQueue;
404
405 ForegroundQueue = IntGetFocusMessageQueue();
406 return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
407 }
408
409
410 /*
411 * @implemented
412 */
413 HWND APIENTRY
414 NtUserGetForegroundWindow(VOID)
415 {
416 DECLARE_RETURN(HWND);
417
418 DPRINT("Enter NtUserGetForegroundWindow\n");
419 UserEnterExclusive();
420
421 RETURN( UserGetForegroundWindow());
422
423 CLEANUP:
424 DPRINT("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
425 UserLeave();
426 END_CLEANUP;
427 }
428
429
430 HWND FASTCALL UserGetActiveWindow(VOID)
431 {
432 PTHREADINFO pti;
433 PUSER_MESSAGE_QUEUE ThreadQueue;
434
435 pti = PsGetCurrentThreadWin32Thread();
436 ThreadQueue = pti->MessageQueue;
437 return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
438 }
439
440
441 HWND APIENTRY
442 NtUserSetActiveWindow(HWND hWnd)
443 {
444 USER_REFERENCE_ENTRY Ref;
445 DECLARE_RETURN(HWND);
446
447 DPRINT("Enter NtUserSetActiveWindow(%x)\n", hWnd);
448 UserEnterExclusive();
449
450 if (hWnd)
451 {
452 PWINDOW_OBJECT Window;
453 PTHREADINFO pti;
454 PUSER_MESSAGE_QUEUE ThreadQueue;
455 HWND hWndPrev;
456
457 if (!(Window = UserGetWindowObject(hWnd)))
458 {
459 RETURN( 0);
460 }
461
462 pti = PsGetCurrentThreadWin32Thread();
463 ThreadQueue = pti->MessageQueue;
464
465 if (Window->pti->MessageQueue != ThreadQueue)
466 {
467 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
468 RETURN( 0);
469 }
470
471 UserRefObjectCo(Window, &Ref);
472 hWndPrev = co_IntSetActiveWindow(Window);
473 UserDerefObjectCo(Window);
474
475 RETURN( hWndPrev);
476 }
477 else
478 {
479 RETURN( co_IntSetActiveWindow(0));
480 }
481
482 CLEANUP:
483 DPRINT("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
484 UserLeave();
485 END_CLEANUP;
486 }
487
488 /*
489 * @implemented
490 */
491 HWND APIENTRY
492 IntGetCapture(VOID)
493 {
494 PTHREADINFO pti;
495 PUSER_MESSAGE_QUEUE ThreadQueue;
496 DECLARE_RETURN(HWND);
497
498 DPRINT("Enter IntGetCapture\n");
499
500 pti = PsGetCurrentThreadWin32Thread();
501 ThreadQueue = pti->MessageQueue;
502 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
503
504 CLEANUP:
505 DPRINT("Leave IntGetCapture, ret=%i\n",_ret_);
506 END_CLEANUP;
507 }
508
509 /*
510 * @implemented
511 */
512 HWND APIENTRY
513 NtUserSetCapture(HWND hWnd)
514 {
515 PTHREADINFO pti;
516 PUSER_MESSAGE_QUEUE ThreadQueue;
517 PWINDOW_OBJECT Window;
518 HWND hWndPrev;
519 DECLARE_RETURN(HWND);
520
521 DPRINT("Enter NtUserSetCapture(%x)\n", hWnd);
522 UserEnterExclusive();
523
524 pti = PsGetCurrentThreadWin32Thread();
525 ThreadQueue = pti->MessageQueue;
526
527 if((Window = UserGetWindowObject(hWnd)))
528 {
529 if(Window->pti->MessageQueue != ThreadQueue)
530 {
531 RETURN(NULL);
532 }
533 }
534
535 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
536
537 /* also remove other windows if not capturing anymore */
538 if(hWnd == NULL)
539 {
540 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
541 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
542 }
543
544 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
545 ThreadQueue->CaptureWindow = hWnd;
546
547 RETURN( hWndPrev);
548
549 CLEANUP:
550 DPRINT("Leave NtUserSetCapture, ret=%i\n",_ret_);
551 UserLeave();
552 END_CLEANUP;
553 }
554
555
556
557 HWND FASTCALL co_UserSetFocus(PWINDOW_OBJECT Window OPTIONAL)
558 {
559 if (Window)
560 {
561 PTHREADINFO pti;
562 PUSER_MESSAGE_QUEUE ThreadQueue;
563 HWND hWndPrev;
564 PWINDOW_OBJECT TopWnd;
565 USER_REFERENCE_ENTRY Ref;
566 PWND Wnd;
567
568 ASSERT_REFS_CO(Window);
569
570 pti = PsGetCurrentThreadWin32Thread();
571 ThreadQueue = pti->MessageQueue;
572
573 Wnd = Window->Wnd;
574 if (Wnd->style & (WS_MINIMIZE | WS_DISABLED))
575 {
576 return( (ThreadQueue ? ThreadQueue->FocusWindow : 0));
577 }
578
579 if (Window->pti->MessageQueue != ThreadQueue)
580 {
581 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
582 return( 0);
583 }
584
585 TopWnd = UserGetAncestor(Window, GA_ROOT);
586 if (TopWnd && TopWnd->hSelf != UserGetActiveWindow())
587 {
588 // PWINDOW_OBJECT WndTops = UserGetWindowObject(hWndTop);
589 UserRefObjectCo(TopWnd, &Ref);
590 co_IntSetActiveWindow(TopWnd);
591 UserDerefObjectCo(TopWnd);
592 }
593
594 hWndPrev = co_IntSetFocusWindow(Window);
595
596 return( hWndPrev);
597 }
598 else
599 {
600 return( co_IntSetFocusWindow(NULL));
601 }
602
603 }
604
605
606 /*
607 * @implemented
608 */
609 HWND APIENTRY
610 NtUserSetFocus(HWND hWnd)
611 {
612 PWINDOW_OBJECT Window;
613 USER_REFERENCE_ENTRY Ref;
614 DECLARE_RETURN(HWND);
615 HWND ret;
616
617 DPRINT("Enter NtUserSetFocus(%x)\n", hWnd);
618 UserEnterExclusive();
619
620 if (hWnd)
621 {
622 if (!(Window = UserGetWindowObject(hWnd)))
623 {
624 RETURN(NULL);
625 }
626
627 UserRefObjectCo(Window, &Ref);
628 ret = co_UserSetFocus(Window);
629 UserDerefObjectCo(Window);
630
631 RETURN(ret);
632 }
633 else
634 {
635 RETURN( co_UserSetFocus(0));
636 }
637
638 CLEANUP:
639 DPRINT("Leave NtUserSetFocus, ret=%i\n",_ret_);
640 UserLeave();
641 END_CLEANUP;
642 }
643
644 /* EOF */