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