- [Win32k] Rename class and window structures.
[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->spwndOwner)
97 Window->Wnd->spwndOwner->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 PWND 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 PWND 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 PWND Wnd;
323 CBTACTIVATESTRUCT cbt;
324
325 if (Window)
326 ASSERT_REFS_CO(Window);
327
328 pti = PsGetCurrentThreadWin32Thread();
329 ThreadQueue = pti->MessageQueue;
330 ASSERT(ThreadQueue != 0);
331
332 if (Window != 0)
333 {
334 Wnd = Window->Wnd;
335 if ((!(Wnd->style & WS_VISIBLE) &&
336 Window->OwnerThread->ThreadsProcess != CsrProcess) ||
337 (Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
338 {
339 return ThreadQueue ? 0 : ThreadQueue->ActiveWindow;
340 }
341 hWnd = Window->hSelf;
342 }
343
344 hWndPrev = ThreadQueue->ActiveWindow;
345 if (hWndPrev == hWnd)
346 {
347 return hWndPrev;
348 }
349
350 /* call CBT hook chain */
351 cbt.fMouse = FALSE;
352 cbt.hWndActive = hWndPrev;
353 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
354 return 0;
355
356 ThreadQueue->ActiveWindow = hWnd;
357
358 co_IntSendDeactivateMessages(hWndPrev, hWnd);
359 co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
360
361 /* FIXME */
362 /* return IntIsWindow(hWndPrev) ? hWndPrev : 0;*/
363 return hWndPrev;
364 }
365
366 static
367 HWND FASTCALL
368 co_IntSetFocusWindow(PWINDOW_OBJECT Window OPTIONAL)
369 {
370 HWND hWndPrev = 0;
371 PTHREADINFO pti;
372 PUSER_MESSAGE_QUEUE ThreadQueue;
373
374 if (Window)
375 ASSERT_REFS_CO(Window);
376
377 pti = PsGetCurrentThreadWin32Thread();
378 ThreadQueue = pti->MessageQueue;
379 ASSERT(ThreadQueue != 0);
380
381 hWndPrev = ThreadQueue->FocusWindow;
382
383 if (Window != 0)
384 {
385 if (hWndPrev == Window->hSelf)
386 {
387 return hWndPrev;
388 }
389
390 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->hSelf, (LPARAM)hWndPrev))
391 return 0;
392
393 ThreadQueue->FocusWindow = Window->hSelf;
394
395 co_IntSendKillFocusMessages(hWndPrev, Window->hSelf);
396 co_IntSendSetFocusMessages(hWndPrev, Window->hSelf);
397 }
398 else
399 {
400 ThreadQueue->FocusWindow = 0;
401
402 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
403 return 0;
404
405 co_IntSendKillFocusMessages(hWndPrev, 0);
406 }
407 return hWndPrev;
408 }
409
410
411 /*
412 * @implemented
413 */
414 HWND FASTCALL
415 UserGetForegroundWindow(VOID)
416 {
417 PUSER_MESSAGE_QUEUE ForegroundQueue;
418
419 ForegroundQueue = IntGetFocusMessageQueue();
420 return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
421 }
422
423
424 /*
425 * @implemented
426 */
427 HWND APIENTRY
428 NtUserGetForegroundWindow(VOID)
429 {
430 DECLARE_RETURN(HWND);
431
432 DPRINT("Enter NtUserGetForegroundWindow\n");
433 UserEnterExclusive();
434
435 RETURN( UserGetForegroundWindow());
436
437 CLEANUP:
438 DPRINT("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
439 UserLeave();
440 END_CLEANUP;
441 }
442
443
444 HWND FASTCALL UserGetActiveWindow()
445 {
446 PTHREADINFO pti;
447 PUSER_MESSAGE_QUEUE ThreadQueue;
448
449 pti = PsGetCurrentThreadWin32Thread();
450 ThreadQueue = pti->MessageQueue;
451 return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
452 }
453
454
455 HWND APIENTRY
456 NtUserSetActiveWindow(HWND hWnd)
457 {
458 USER_REFERENCE_ENTRY Ref;
459 DECLARE_RETURN(HWND);
460
461 DPRINT("Enter NtUserSetActiveWindow(%x)\n", hWnd);
462 UserEnterExclusive();
463
464 if (hWnd)
465 {
466 PWINDOW_OBJECT Window;
467 PTHREADINFO pti;
468 PUSER_MESSAGE_QUEUE ThreadQueue;
469 HWND hWndPrev;
470
471 if (!(Window = UserGetWindowObject(hWnd)))
472 {
473 RETURN( 0);
474 }
475
476 pti = PsGetCurrentThreadWin32Thread();
477 ThreadQueue = pti->MessageQueue;
478
479 if (Window->MessageQueue != ThreadQueue)
480 {
481 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
482 RETURN( 0);
483 }
484
485 UserRefObjectCo(Window, &Ref);
486 hWndPrev = co_IntSetActiveWindow(Window);
487 UserDerefObjectCo(Window);
488
489 RETURN( hWndPrev);
490 }
491 else
492 {
493 RETURN( co_IntSetActiveWindow(0));
494 }
495
496 CLEANUP:
497 DPRINT("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
498 UserLeave();
499 END_CLEANUP;
500 }
501
502 /*
503 * @implemented
504 */
505 HWND APIENTRY
506 IntGetCapture(VOID)
507 {
508 PTHREADINFO pti;
509 PUSER_MESSAGE_QUEUE ThreadQueue;
510 DECLARE_RETURN(HWND);
511
512 DPRINT("Enter IntGetCapture\n");
513
514 pti = PsGetCurrentThreadWin32Thread();
515 ThreadQueue = pti->MessageQueue;
516 RETURN( ThreadQueue ? ThreadQueue->CaptureWindow : 0);
517
518 CLEANUP:
519 DPRINT("Leave IntGetCapture, ret=%i\n",_ret_);
520 END_CLEANUP;
521 }
522
523 /*
524 * @implemented
525 */
526 HWND APIENTRY
527 NtUserSetCapture(HWND hWnd)
528 {
529 PTHREADINFO pti;
530 PUSER_MESSAGE_QUEUE ThreadQueue;
531 PWINDOW_OBJECT Window;
532 HWND hWndPrev;
533 DECLARE_RETURN(HWND);
534
535 DPRINT("Enter NtUserSetCapture(%x)\n", hWnd);
536 UserEnterExclusive();
537
538 pti = PsGetCurrentThreadWin32Thread();
539 ThreadQueue = pti->MessageQueue;
540
541 if((Window = UserGetWindowObject(hWnd)))
542 {
543 if(Window->MessageQueue != ThreadQueue)
544 {
545 RETURN(NULL);
546 }
547 }
548
549 hWndPrev = MsqSetStateWindow(ThreadQueue, MSQ_STATE_CAPTURE, hWnd);
550
551 /* also remove other windows if not capturing anymore */
552 if(hWnd == NULL)
553 {
554 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MENUOWNER, NULL);
555 MsqSetStateWindow(ThreadQueue, MSQ_STATE_MOVESIZE, NULL);
556 }
557
558 co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
559 ThreadQueue->CaptureWindow = hWnd;
560
561 RETURN( hWndPrev);
562
563 CLEANUP:
564 DPRINT("Leave NtUserSetCapture, ret=%i\n",_ret_);
565 UserLeave();
566 END_CLEANUP;
567 }
568
569
570
571 HWND FASTCALL co_UserSetFocus(PWINDOW_OBJECT Window OPTIONAL)
572 {
573 if (Window)
574 {
575 PTHREADINFO pti;
576 PUSER_MESSAGE_QUEUE ThreadQueue;
577 HWND hWndPrev;
578 PWINDOW_OBJECT TopWnd;
579 USER_REFERENCE_ENTRY Ref;
580 PWND Wnd;
581
582 ASSERT_REFS_CO(Window);
583
584 pti = PsGetCurrentThreadWin32Thread();
585 ThreadQueue = pti->MessageQueue;
586
587 Wnd = Window->Wnd;
588 if (Wnd->style & (WS_MINIMIZE | WS_DISABLED))
589 {
590 return( (ThreadQueue ? ThreadQueue->FocusWindow : 0));
591 }
592
593 if (Window->MessageQueue != ThreadQueue)
594 {
595 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
596 return( 0);
597 }
598
599 TopWnd = UserGetAncestor(Window, GA_ROOT);
600 if (TopWnd && TopWnd->hSelf != UserGetActiveWindow())
601 {
602 // PWINDOW_OBJECT WndTops = UserGetWindowObject(hWndTop);
603 UserRefObjectCo(TopWnd, &Ref);
604 co_IntSetActiveWindow(TopWnd);
605 UserDerefObjectCo(TopWnd);
606 }
607
608 hWndPrev = co_IntSetFocusWindow(Window);
609
610 return( hWndPrev);
611 }
612 else
613 {
614 return( co_IntSetFocusWindow(NULL));
615 }
616
617 }
618
619
620 /*
621 * @implemented
622 */
623 HWND APIENTRY
624 NtUserSetFocus(HWND hWnd)
625 {
626 PWINDOW_OBJECT Window;
627 USER_REFERENCE_ENTRY Ref;
628 DECLARE_RETURN(HWND);
629 HWND ret;
630
631 DPRINT("Enter NtUserSetFocus(%x)\n", hWnd);
632 UserEnterExclusive();
633
634 if (hWnd)
635 {
636 if (!(Window = UserGetWindowObject(hWnd)))
637 {
638 RETURN(NULL);
639 }
640
641 UserRefObjectCo(Window, &Ref);
642 ret = co_UserSetFocus(Window);
643 UserDerefObjectCo(Window);
644
645 RETURN(ret);
646 }
647 else
648 {
649 RETURN( co_UserSetFocus(0));
650 }
651
652 CLEANUP:
653 DPRINT("Leave NtUserSetFocus, ret=%i\n",_ret_);
654 UserLeave();
655 END_CLEANUP;
656 }
657
658 /* EOF */