- Small SetWindowPos fixes.
[reactos.git] / reactos / subsys / win32k / ntuser / winpos.c
1 /*
2 * ReactOS W32 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 /* $Id: winpos.c,v 1.47 2003/11/24 21:01:20 navaraf Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Windows
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH NtGdid
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/guicheck.h>
35 #include <include/window.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/winsta.h>
39 #include <include/winpos.h>
40 #include <include/rect.h>
41 #include <include/callback.h>
42 #include <include/painting.h>
43 #include <include/dce.h>
44 #include <include/vis.h>
45
46 #define NDEBUG
47 #include <debug.h>
48
49 /* GLOBALS *******************************************************************/
50
51 #define MINMAX_NOSWP (0x00010000)
52
53 #define SWP_EX_NOCOPY 0x0001
54 #define SWP_EX_PAINTSELF 0x0002
55
56 #define SWP_AGG_NOGEOMETRYCHANGE \
57 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
58 #define SWP_AGG_NOPOSCHANGE \
59 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
60 #define SWP_AGG_STATUSFLAGS \
61 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
62
63 ATOM AtomInternalPos = (ATOM) NULL;
64
65 /* FUNCTIONS *****************************************************************/
66
67 #define HAS_DLGFRAME(Style, ExStyle) \
68 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
69 (((Style) & WS_DLGFRAME) && !((Style) & WS_BORDER)))
70
71 #define HAS_THICKFRAME(Style, ExStyle) \
72 (((Style) & WS_THICKFRAME) && \
73 !((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)
74
75 VOID FASTCALL
76 WinPosSetupInternalPos(VOID)
77 {
78 AtomInternalPos = NtAddAtom(L"SysIP", (ATOM*)(PULONG)&AtomInternalPos);
79 }
80
81 BOOL STDCALL
82 NtUserGetClientOrigin(HWND hWnd, LPPOINT Point)
83 {
84 PWINDOW_OBJECT WindowObject;
85
86 WindowObject = IntGetWindowObject(hWnd);
87 if (WindowObject == NULL)
88 {
89 Point->x = Point->y = 0;
90 return(TRUE);
91 }
92 Point->x = WindowObject->ClientRect.left;
93 Point->y = WindowObject->ClientRect.top;
94 return(TRUE);
95 }
96
97 /*******************************************************************
98 * can_activate_window
99 *
100 * Check if we can activate the specified window.
101 */
102 static BOOL FASTCALL
103 can_activate_window(HWND hwnd)
104 {
105 LONG style;
106
107 if (! hwnd)
108 {
109 return FALSE;
110 }
111 style = NtUserGetWindowLong(hwnd, GWL_STYLE, FALSE);
112 if (! (style & WS_VISIBLE))
113 {
114 return FALSE;
115 }
116 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
117 {
118 return FALSE;
119 }
120 return ! (style & WS_DISABLED);
121 }
122
123 /*******************************************************************
124 * WinPosActivateOtherWindow
125 *
126 * Activates window other than pWnd.
127 */
128 void FASTCALL
129 WinPosActivateOtherWindow(PWINDOW_OBJECT Window)
130 {
131 HWND hwndTo;
132 #if 0
133 HWND fg;
134 #endif
135
136 if ((NtUserGetWindowLong(Window->Self, GWL_STYLE, FALSE) & WS_POPUP)
137 && (hwndTo = NtUserGetWindow(Window->Self, GW_OWNER)))
138 {
139 hwndTo = NtUserGetAncestor(hwndTo, GA_ROOT);
140 if (can_activate_window(hwndTo)) goto done;
141 }
142
143 hwndTo = Window->Self;
144 for (;;)
145 {
146 if (!(hwndTo = NtUserGetWindow(hwndTo, GW_HWNDNEXT)))
147 {
148 break;
149 }
150 if (can_activate_window(hwndTo))
151 {
152 break;
153 }
154 }
155
156 done:
157 #ifdef TODO
158 fg = NtUserGetForegroundWindow();
159 /* TRACE("win = %p fg = %p\n", hwndTo, fg); */
160 if (! fg || (hwnd == fg))
161 {
162 if (NtUserSetForegroundWindow(hwndTo))
163 {
164 return;
165 }
166 }
167 #endif
168
169 if (! NtUserSetActiveWindow(hwndTo))
170 {
171 NtUserSetActiveWindow(NULL);
172 }
173 }
174
175 POINT STATIC FASTCALL
176 WinPosFindIconPos(HWND hWnd, POINT Pos)
177 {
178 POINT point;
179 //FIXME
180 return point;
181 }
182
183 HWND STATIC FASTCALL
184 WinPosNtGdiIconTitle(PWINDOW_OBJECT WindowObject)
185 {
186 return(NULL);
187 }
188
189 BOOL STATIC FASTCALL
190 WinPosShowIconTitle(PWINDOW_OBJECT WindowObject, BOOL Show)
191 {
192 PINTERNALPOS InternalPos = (PINTERNALPOS)IntGetProp(WindowObject, AtomInternalPos);
193 PWINDOW_OBJECT IconWindow;
194 NTSTATUS Status;
195
196 if (InternalPos)
197 {
198 HWND hWnd = InternalPos->IconTitle;
199
200 if (hWnd == NULL)
201 {
202 hWnd = WinPosNtGdiIconTitle(WindowObject);
203 }
204 if (Show)
205 {
206 Status =
207 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->
208 HandleTable,
209 hWnd,
210 otWindow,
211 (PVOID*)&IconWindow);
212 if (NT_SUCCESS(Status))
213 {
214 if (!(IconWindow->Style & WS_VISIBLE))
215 {
216 NtUserSendMessage(hWnd, WM_SHOWWINDOW, TRUE, 0);
217 WinPosSetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE |
218 SWP_NOMOVE | SWP_NOACTIVATE |
219 SWP_NOZORDER | SWP_SHOWWINDOW);
220 }
221 ObmDereferenceObject(IconWindow);
222 }
223 }
224 else
225 {
226 WinPosShowWindow(hWnd, SW_HIDE);
227 }
228 }
229 return(FALSE);
230 }
231
232 PINTERNALPOS STATIC STDCALL
233 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject, POINT pt, PRECT RestoreRect)
234 {
235 PINTERNALPOS InternalPos = (PINTERNALPOS)IntGetProp(WindowObject, AtomInternalPos);
236 if (InternalPos == NULL)
237 {
238 InternalPos =
239 ExAllocatePool(NonPagedPool, sizeof(INTERNALPOS));
240 IntSetProp(WindowObject, AtomInternalPos, InternalPos);
241 InternalPos->IconTitle = 0;
242 InternalPos->NormalRect = WindowObject->WindowRect;
243 InternalPos->IconPos.x = InternalPos->MaxPos.x = 0xFFFFFFFF;
244 InternalPos->IconPos.y = InternalPos->MaxPos.y = 0xFFFFFFFF;
245 }
246 if (WindowObject->Style & WS_MINIMIZE)
247 {
248 InternalPos->IconPos = pt;
249 }
250 else if (WindowObject->Style & WS_MAXIMIZE)
251 {
252 InternalPos->MaxPos = pt;
253 }
254 else if (RestoreRect != NULL)
255 {
256 InternalPos->NormalRect = *RestoreRect;
257 }
258 return(InternalPos);
259 }
260
261 UINT STDCALL
262 WinPosMinMaximize(PWINDOW_OBJECT WindowObject, UINT ShowFlag, RECT* NewPos)
263 {
264 POINT Size;
265 PINTERNALPOS InternalPos;
266 UINT SwpFlags = 0;
267
268 Size.x = WindowObject->WindowRect.left;
269 Size.y = WindowObject->WindowRect.top;
270 InternalPos = WinPosInitInternalPos(WindowObject, Size,
271 &WindowObject->WindowRect);
272
273 if (InternalPos)
274 {
275 if (WindowObject->Style & WS_MINIMIZE)
276 {
277 if (!NtUserSendMessage(WindowObject->Self, WM_QUERYOPEN, 0, 0))
278 {
279 return(SWP_NOSIZE | SWP_NOMOVE);
280 }
281 SwpFlags |= SWP_NOCOPYBITS;
282 }
283 switch (ShowFlag)
284 {
285 case SW_MINIMIZE:
286 {
287 if (WindowObject->Style & WS_MAXIMIZE)
288 {
289 WindowObject->Flags |= WINDOWOBJECT_RESTOREMAX;
290 WindowObject->Style &= ~WS_MAXIMIZE;
291 }
292 else
293 {
294 WindowObject->Style &= ~WINDOWOBJECT_RESTOREMAX;
295 }
296 WindowObject->Style |= WS_MINIMIZE;
297 InternalPos->IconPos = WinPosFindIconPos(WindowObject,
298 InternalPos->IconPos);
299 NtGdiSetRect(NewPos, InternalPos->IconPos.x, InternalPos->IconPos.y,
300 NtUserGetSystemMetrics(SM_CXICON),
301 NtUserGetSystemMetrics(SM_CYICON));
302 SwpFlags |= SWP_NOCOPYBITS;
303 break;
304 }
305
306 case SW_MAXIMIZE:
307 {
308 WinPosGetMinMaxInfo(WindowObject, &Size, &InternalPos->MaxPos,
309 NULL, NULL);
310 if (WindowObject->Style & WS_MINIMIZE)
311 {
312 WinPosShowIconTitle(WindowObject, FALSE);
313 WindowObject->Style &= ~WS_MINIMIZE;
314 }
315 WindowObject->Style |= WS_MINIMIZE;
316 NtGdiSetRect(NewPos, InternalPos->MaxPos.x, InternalPos->MaxPos.y,
317 Size.x, Size.y);
318 break;
319 }
320
321 case SW_RESTORE:
322 {
323 if (WindowObject->Style & WS_MINIMIZE)
324 {
325 WindowObject->Style &= ~WS_MINIMIZE;
326 WinPosShowIconTitle(WindowObject, FALSE);
327 if (WindowObject->Flags & WINDOWOBJECT_RESTOREMAX)
328 {
329 WinPosGetMinMaxInfo(WindowObject, &Size,
330 &InternalPos->MaxPos, NULL, NULL);
331 WindowObject->Style |= WS_MAXIMIZE;
332 NtGdiSetRect(NewPos, InternalPos->MaxPos.x,
333 InternalPos->MaxPos.y, Size.x, Size.y);
334 break;
335 }
336 }
337 else
338 {
339 if (!(WindowObject->Style & WS_MAXIMIZE))
340 {
341 return(-1);
342 }
343 else
344 {
345 WindowObject->Style &= ~WS_MAXIMIZE;
346 }
347 *NewPos = InternalPos->NormalRect;
348 NewPos->right -= NewPos->left;
349 NewPos->bottom -= NewPos->top;
350 break;
351 }
352 }
353 }
354 }
355 else
356 {
357 SwpFlags |= SWP_NOSIZE | SWP_NOMOVE;
358 }
359 return(SwpFlags);
360 }
361
362 UINT STDCALL
363 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window, POINT* MaxSize, POINT* MaxPos,
364 POINT* MinTrack, POINT* MaxTrack)
365 {
366 MINMAXINFO MinMax;
367 INT XInc, YInc;
368 INTERNALPOS* Pos;
369
370 /* Get default values. */
371 MinMax.ptMaxSize.x = NtUserGetSystemMetrics(SM_CXSCREEN);
372 MinMax.ptMaxSize.y = NtUserGetSystemMetrics(SM_CYSCREEN);
373 MinMax.ptMinTrackSize.x = NtUserGetSystemMetrics(SM_CXMINTRACK);
374 MinMax.ptMinTrackSize.y = NtUserGetSystemMetrics(SM_CYMINTRACK);
375 MinMax.ptMaxTrackSize.x = NtUserGetSystemMetrics(SM_CXSCREEN);
376 MinMax.ptMaxTrackSize.y = NtUserGetSystemMetrics(SM_CYSCREEN);
377
378 if (HAS_DLGFRAME(Window->Style, Window->ExStyle))
379 {
380 XInc = NtUserGetSystemMetrics(SM_CXDLGFRAME);
381 YInc = NtUserGetSystemMetrics(SM_CYDLGFRAME);
382 }
383 else
384 {
385 XInc = YInc = 0;
386 if (HAS_THICKFRAME(Window->Style, Window->ExStyle))
387 {
388 XInc += NtUserGetSystemMetrics(SM_CXFRAME);
389 YInc += NtUserGetSystemMetrics(SM_CYFRAME);
390 }
391 if (Window->Style & WS_BORDER)
392 {
393 XInc += NtUserGetSystemMetrics(SM_CXBORDER);
394 YInc += NtUserGetSystemMetrics(SM_CYBORDER);
395 }
396 }
397 MinMax.ptMaxSize.x += 2 * XInc;
398 MinMax.ptMaxSize.y += 2 * YInc;
399
400 Pos = (PINTERNALPOS)IntGetProp(Window, AtomInternalPos);
401 if (Pos != NULL)
402 {
403 MinMax.ptMaxPosition = Pos->MaxPos;
404 }
405 else
406 {
407 MinMax.ptMaxPosition.x -= XInc;
408 MinMax.ptMaxPosition.y -= YInc;
409 }
410
411 IntSendMessage(Window->Self, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax, TRUE);
412
413 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
414 MinMax.ptMinTrackSize.x);
415 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
416 MinMax.ptMinTrackSize.y);
417
418 if (MaxSize) *MaxSize = MinMax.ptMaxSize;
419 if (MaxPos) *MaxPos = MinMax.ptMaxPosition;
420 if (MinTrack) *MinTrack = MinMax.ptMinTrackSize;
421 if (MaxTrack) *MaxTrack = MinMax.ptMaxTrackSize;
422
423 return 0; //FIXME: what does it return?
424 }
425
426 BOOL STATIC FASTCALL
427 WinPosChangeActiveWindow(HWND hWnd, BOOL MouseMsg)
428 {
429 PWINDOW_OBJECT WindowObject;
430
431 WindowObject = IntGetWindowObject(hWnd);
432 if (WindowObject == NULL)
433 {
434 return FALSE;
435 }
436
437 NtUserSendMessage(hWnd,
438 WM_ACTIVATE,
439 MAKELONG(MouseMsg ? WA_CLICKACTIVE : WA_CLICKACTIVE,
440 (WindowObject->Style & WS_MINIMIZE) ? 1 : 0),
441 (LPARAM)IntGetDesktopWindow()); /* FIXME: Previous active window */
442
443 IntReleaseWindowObject(WindowObject);
444
445 return TRUE;
446 }
447
448 LONG STATIC STDCALL
449 WinPosDoNCCALCSize(PWINDOW_OBJECT Window, PWINDOWPOS WinPos,
450 RECT* WindowRect, RECT* ClientRect)
451 {
452 UINT wvrFlags = 0;
453
454 /* Send WM_NCCALCSIZE message to get new client area */
455 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
456 {
457 NCCALCSIZE_PARAMS params;
458 WINDOWPOS winposCopy;
459
460 params.rgrc[0] = *WindowRect;
461 params.rgrc[1] = Window->WindowRect;
462 params.rgrc[2] = Window->ClientRect;
463 if (0 != (Window->Style & WS_CHILD))
464 {
465 NtGdiOffsetRect(&(params.rgrc[0]), - Window->Parent->ClientRect.left,
466 - Window->Parent->ClientRect.top);
467 NtGdiOffsetRect(&(params.rgrc[1]), - Window->Parent->ClientRect.left,
468 - Window->Parent->ClientRect.top);
469 NtGdiOffsetRect(&(params.rgrc[2]), - Window->Parent->ClientRect.left,
470 - Window->Parent->ClientRect.top);
471 }
472 params.lppos = &winposCopy;
473 winposCopy = *WinPos;
474
475 wvrFlags = IntSendNCCALCSIZEMessage(Window->Self, TRUE, NULL, &params);
476
477 /* If the application send back garbage, ignore it */
478 if (params.rgrc[0].left <= params.rgrc[0].right &&
479 params.rgrc[0].top <= params.rgrc[0].bottom)
480 {
481 *ClientRect = params.rgrc[0];
482 if (Window->Style & WS_CHILD)
483 {
484 NtGdiOffsetRect(ClientRect, Window->Parent->ClientRect.left,
485 Window->Parent->ClientRect.top);
486 }
487 }
488
489 /* FIXME: WVR_ALIGNxxx */
490
491 if (ClientRect->left != Window->ClientRect.left ||
492 ClientRect->top != Window->ClientRect.top)
493 {
494 WinPos->flags &= ~SWP_NOCLIENTMOVE;
495 }
496
497 if ((ClientRect->right - ClientRect->left !=
498 Window->ClientRect.right - Window->ClientRect.left) ||
499 (ClientRect->bottom - ClientRect->top !=
500 Window->ClientRect.bottom - Window->ClientRect.top))
501 {
502 WinPos->flags &= ~SWP_NOCLIENTSIZE;
503 }
504 }
505 else
506 {
507 if (! (WinPos->flags & SWP_NOMOVE)
508 && (ClientRect->left != Window->ClientRect.left ||
509 ClientRect->top != Window->ClientRect.top))
510 {
511 WinPos->flags &= ~SWP_NOCLIENTMOVE;
512 }
513 }
514
515 return wvrFlags;
516 }
517
518 BOOL STDCALL
519 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject,
520 PWINDOWPOS WinPos,
521 PRECT WindowRect,
522 PRECT ClientRect)
523 {
524 INT X, Y;
525
526 if (!(WinPos->flags & SWP_NOSENDCHANGING))
527 {
528 IntSendWINDOWPOSCHANGINGMessage(WindowObject->Self, WinPos);
529 }
530
531 *WindowRect = WindowObject->WindowRect;
532 *ClientRect =
533 (WindowObject->Style & WS_MINIMIZE) ? WindowObject->WindowRect :
534 WindowObject->ClientRect;
535
536 if (!(WinPos->flags & SWP_NOSIZE))
537 {
538 WindowRect->right = WindowRect->left + WinPos->cx;
539 WindowRect->bottom = WindowRect->top + WinPos->cy;
540 }
541
542 if (!(WinPos->flags & SWP_NOMOVE))
543 {
544 X = WinPos->x;
545 Y = WinPos->y;
546 if (0 != (WindowObject->Style & WS_CHILD))
547 {
548 X += WindowObject->Parent->ClientRect.left;
549 Y += WindowObject->Parent->ClientRect.top;
550 }
551 WindowRect->left = X;
552 WindowRect->top = Y;
553 WindowRect->right += X - WindowObject->WindowRect.left;
554 WindowRect->bottom += Y - WindowObject->WindowRect.top;
555 NtGdiOffsetRect(ClientRect,
556 X - WindowObject->WindowRect.left,
557 Y - WindowObject->WindowRect.top);
558 }
559
560 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
561
562 return TRUE;
563 }
564
565 /*
566 * Fix Z order taking into account owned popups -
567 * basically we need to maintain them above the window that owns them
568 */
569 HWND FASTCALL
570 WinPosDoOwnedPopups(HWND hWnd, HWND hWndInsertAfter)
571 {
572 /* FIXME */
573 return hWndInsertAfter;
574 }
575
576 /***********************************************************************
577 * WinPosInternalMoveWindow
578 *
579 * Update WindowRect and ClientRect of Window and all of its children
580 * We keep both WindowRect and ClientRect in screen coordinates internally
581 */
582 static VOID
583 WinPosInternalMoveWindow(PWINDOW_OBJECT Window, INT MoveX, INT MoveY)
584 {
585 PWINDOW_OBJECT Child;
586
587 Window->WindowRect.left += MoveX;
588 Window->WindowRect.right += MoveX;
589 Window->WindowRect.top += MoveY;
590 Window->WindowRect.bottom += MoveY;
591
592 Window->ClientRect.left += MoveX;
593 Window->ClientRect.right += MoveX;
594 Window->ClientRect.top += MoveY;
595 Window->ClientRect.bottom += MoveY;
596
597 ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
598 Child = Window->FirstChild;
599 while (Child)
600 {
601 WinPosInternalMoveWindow(Child, MoveX, MoveY);
602 Child = Child->NextSibling;
603 }
604 ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
605 }
606
607 /*
608 * WinPosFixupSWPFlags
609 *
610 * Fix redundant flags and values in the WINDOWPOS structure.
611 */
612
613 BOOL FASTCALL
614 WinPosFixupFlags(WINDOWPOS *WinPos, PWINDOW_OBJECT Window)
615 {
616 if (Window->Style & WS_VISIBLE)
617 {
618 WinPos->flags &= ~SWP_SHOWWINDOW;
619 }
620 else
621 {
622 WinPos->flags &= ~SWP_HIDEWINDOW;
623 if (!(WinPos->flags & SWP_SHOWWINDOW))
624 WinPos->flags |= SWP_NOREDRAW;
625 }
626
627 WinPos->cx = max(WinPos->cx, 0);
628 WinPos->cy = max(WinPos->cy, 0);
629
630 /* Check for right size */
631 if (Window->WindowRect.right - Window->WindowRect.left == WinPos->cx &&
632 Window->WindowRect.bottom - Window->WindowRect.top == WinPos->cy)
633 {
634 WinPos->flags |= SWP_NOSIZE;
635 }
636
637 /* Check for right position */
638 if (Window->WindowRect.left == WinPos->x &&
639 Window->WindowRect.top == WinPos->y)
640 {
641 WinPos->flags |= SWP_NOMOVE;
642 }
643
644 /* FIXME: We don't have NtUserGetForegroundWindow yet. */
645 #if 0
646 if (WinPos->hwnd == NtUserGetForegroundWindow())
647 {
648 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
649 }
650 else
651 #endif
652 if ((Window->Style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
653 {
654 /* Bring to the top when activating */
655 if (!(WinPos->flags & SWP_NOACTIVATE))
656 {
657 WinPos->flags &= ~SWP_NOZORDER;
658 WinPos->hwndInsertAfter = HWND_TOP;
659 return TRUE;
660 }
661 }
662
663 /* Check hwndInsertAfter */
664 if (!(WinPos->flags & SWP_NOZORDER))
665 {
666 /* Fix sign extension */
667 if (WinPos->hwndInsertAfter == (HWND)0xffff)
668 {
669 WinPos->hwndInsertAfter = HWND_TOPMOST;
670 }
671 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
672 {
673 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
674 }
675
676 /* FIXME: TOPMOST not supported yet */
677 if ((WinPos->hwndInsertAfter == HWND_TOPMOST) ||
678 (WinPos->hwndInsertAfter == HWND_NOTOPMOST))
679 {
680 WinPos->hwndInsertAfter = HWND_TOP;
681 }
682
683 /* hwndInsertAfter must be a sibling of the window */
684 if ((WinPos->hwndInsertAfter != HWND_TOP) &&
685 (WinPos->hwndInsertAfter != HWND_BOTTOM))
686 {
687 if (NtUserGetAncestor(WinPos->hwndInsertAfter, GA_PARENT) !=
688 Window->Parent)
689 {
690 return FALSE;
691 }
692 else
693 {
694 /*
695 * We don't need to change the Z order of hwnd if it's already
696 * inserted after hwndInsertAfter or when inserting hwnd after
697 * itself.
698 */
699 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
700 (WinPos->hwnd == NtUserGetWindow(WinPos->hwndInsertAfter, GW_HWNDNEXT)))
701 {
702 WinPos->flags |= SWP_NOZORDER;
703 }
704 }
705 }
706 }
707
708 return TRUE;
709 }
710
711 /* x and y are always screen relative */
712 BOOLEAN STDCALL
713 WinPosSetWindowPos(HWND Wnd, HWND WndInsertAfter, INT x, INT y, INT cx,
714 INT cy, UINT flags)
715 {
716 PWINDOW_OBJECT Window;
717 WINDOWPOS WinPos;
718 RECT NewWindowRect;
719 RECT NewClientRect;
720 HRGN VisBefore = NULL;
721 HRGN VisAfter = NULL;
722 HRGN DirtyRgn = NULL;
723 HRGN ExposedRgn = NULL;
724 HRGN CopyRgn = NULL;
725 ULONG WvrFlags = 0;
726 RECT OldWindowRect, OldClientRect;
727 int RgnType;
728 HDC Dc;
729 RECT CopyRect;
730 RECT TempRect;
731
732 /* FIXME: Get current active window from active queue. */
733
734 /* Check if the window is for a desktop. */
735 if (Wnd == IntGetDesktopWindow())
736 {
737 return FALSE;
738 }
739
740 Window = IntGetWindowObject(Wnd);
741 if (!Window)
742 {
743 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
744 return FALSE;
745 }
746
747 WinPos.hwnd = Wnd;
748 WinPos.hwndInsertAfter = WndInsertAfter;
749 WinPos.x = x;
750 WinPos.y = y;
751 WinPos.cx = cx;
752 WinPos.cy = cy;
753 WinPos.flags = flags;
754 if (Window->Style & WS_CHILD)
755 {
756 WinPos.x -= Window->Parent->ClientRect.left;
757 WinPos.y -= Window->Parent->ClientRect.top;
758 }
759
760 WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
761
762 /* Fix up the flags. */
763 if (!WinPosFixupFlags(&WinPos, Window))
764 {
765 SetLastWin32Error(ERROR_INVALID_PARAMETER);
766 IntReleaseWindowObject(Window);
767 return FALSE;
768 }
769
770 /* Does the window still exist? */
771 if (!IntIsWindow(WinPos.hwnd))
772 {
773 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
774 return FALSE;
775 }
776
777 if ((WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
778 SWP_NOZORDER &&
779 NtUserGetAncestor(WinPos.hwnd, GA_PARENT) == IntGetDesktopWindow())
780 {
781 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(WinPos.hwnd, WinPos.hwndInsertAfter);
782 }
783
784 /* Compute the visible region before the window position is changed */
785 if ((!(WinPos.flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
786 WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
787 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
788 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
789 {
790 VisBefore = VIS_ComputeVisibleRegion(
791 PsGetWin32Thread()->Desktop, Window, FALSE, FALSE, TRUE);
792
793 if (UnsafeIntGetRgnBox(VisBefore, &TempRect) == NULLREGION)
794 {
795 NtGdiDeleteObject(VisBefore);
796 VisBefore = NULL;
797 }
798 }
799
800 WvrFlags = WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
801
802 /* Relink windows. (also take into account shell window in hwndShellWindow) */
803 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != NtUserGetShellWindow())
804 {
805 PWINDOW_OBJECT ParentWindow;
806 PWINDOW_OBJECT InsertAfterWindow;
807
808 ParentWindow = Window->Parent;
809 if (ParentWindow)
810 {
811 if (WinPos.hwndInsertAfter == HWND_TOP)
812 InsertAfterWindow = NULL;
813 else if (WinPos.hwndInsertAfter == HWND_BOTTOM)
814 InsertAfterWindow = ParentWindow->LastChild;
815 else
816 InsertAfterWindow = IntGetWindowObject(WinPos.hwndInsertAfter);
817 ExAcquireFastMutexUnsafe(&ParentWindow->ChildrenListLock);
818 IntUnlinkWindow(Window);
819 IntLinkWindow(Window, ParentWindow, InsertAfterWindow);
820 ExReleaseFastMutexUnsafe(&ParentWindow->ChildrenListLock);
821 if (InsertAfterWindow != NULL)
822 IntReleaseWindowObject(InsertAfterWindow);
823 }
824 }
825
826 /* FIXME: Reset active DCEs */
827
828 OldWindowRect = Window->WindowRect;
829 OldClientRect = Window->ClientRect;
830
831 if (OldClientRect.bottom - OldClientRect.top ==
832 NewClientRect.bottom - NewClientRect.top)
833 {
834 WvrFlags &= ~WVR_VREDRAW;
835 }
836
837 if (OldClientRect.right - OldClientRect.left ==
838 NewClientRect.right - NewClientRect.left)
839 {
840 WvrFlags &= ~WVR_HREDRAW;
841 }
842
843 /* FIXME: Actually do something with WVR_VALIDRECTS */
844
845 if (!(WinPos.flags & SWP_NOMOVE))
846 {
847 WinPosInternalMoveWindow(Window,
848 NewWindowRect.left - OldWindowRect.left,
849 NewWindowRect.top - OldWindowRect.top);
850 }
851
852 Window->WindowRect = NewWindowRect;
853 Window->ClientRect = NewClientRect;
854
855 if (!(WinPos.flags & SWP_SHOWWINDOW) && (WinPos.flags & SWP_HIDEWINDOW))
856 {
857 /* Clear the update region */
858 IntRedrawWindow(Window, NULL, 0, RDW_VALIDATE | RDW_NOFRAME |
859 RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
860 Window->Style &= ~WS_VISIBLE;
861 }
862 else if (WinPos.flags & SWP_SHOWWINDOW)
863 {
864 Window->Style |= WS_VISIBLE;
865 }
866
867 if (!(WinPos.flags & SWP_NOACTIVATE))
868 {
869 WinPosChangeActiveWindow(WinPos.hwnd, FALSE);
870 }
871
872 /* Determine the new visible region */
873 VisAfter = VIS_ComputeVisibleRegion(
874 PsGetWin32Thread()->Desktop, Window, FALSE, FALSE, TRUE);
875
876 if (UnsafeIntGetRgnBox(VisAfter, &TempRect) == NULLREGION)
877 {
878 NtGdiDeleteObject(VisAfter);
879 VisAfter = NULL;
880 }
881
882 /*
883 * Determine which pixels can be copied from the old window position
884 * to the new. Those pixels must be visible in both the old and new
885 * position. Also, check the class style to see if the windows of this
886 * class need to be completely repainted on (horizontal/vertical) size
887 * change.
888 */
889 if (VisBefore != NULL && VisAfter != NULL && !(WinPos.flags & SWP_NOCOPYBITS) &&
890 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)))
891 {
892 CopyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
893 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
894
895 /*
896 * If this is (also) a window resize, the whole nonclient area
897 * needs to be repainted. So we limit the copy to the client area,
898 * 'cause there is no use in copying it (would possibly cause
899 * "flashing" too). However, if the copy region is already empty,
900 * we don't have to crop (can't take anything away from an empty
901 * region...)
902 */
903 if (!(WinPos.flags & (SWP_NOSIZE | SWP_NOZORDER)) && RgnType != ERROR &&
904 RgnType != NULLREGION)
905 {
906 RECT ORect = OldClientRect;
907 RECT NRect = NewClientRect;
908 NtGdiOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
909 NtGdiOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
910 NtGdiIntersectRect(&CopyRect, &ORect, &NRect);
911 REGION_CropRgn(CopyRgn, CopyRgn, &CopyRect, NULL);
912 }
913
914 /* No use in copying bits which are in the update region. */
915 if (Window->UpdateRegion != NULL)
916 {
917 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->UpdateRegion, RGN_DIFF);
918 }
919
920 /*
921 * Now, get the bounding box of the copy region. If it's empty
922 * there's nothing to copy. Also, it's no use copying bits onto
923 * themselves.
924 */
925 if (UnsafeIntGetRgnBox(CopyRgn, &CopyRect) == NULLREGION)
926 {
927 /* Nothing to copy, clean up */
928 NtGdiDeleteObject(CopyRgn);
929 CopyRgn = NULL;
930 }
931 else if (OldWindowRect.left != NewWindowRect.left ||
932 OldWindowRect.top != NewWindowRect.top)
933 {
934 /*
935 * Small trick here: there is no function to bitblt a region. So
936 * we set the region as the clipping region, take the bounding box
937 * of the region and bitblt that. Since nothing outside the clipping
938 * region is copied, this has the effect of bitblt'ing the region.
939 *
940 * Since NtUserGetDCEx takes ownership of the clip region, we need
941 * to create a copy of CopyRgn and pass that. We need CopyRgn later
942 */
943 HRGN ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
944 NtGdiCombineRgn(ClipRgn, CopyRgn, NULL, RGN_COPY);
945 Dc = NtUserGetDCEx(Wnd, ClipRgn, DCX_WINDOW | DCX_CACHE |
946 DCX_INTERSECTRGN | DCX_CLIPSIBLINGS);
947 NtGdiBitBlt(Dc,
948 CopyRect.left, CopyRect.top, CopyRect.right - CopyRect.left,
949 CopyRect.bottom - CopyRect.top, Dc,
950 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
951 CopyRect.top + (OldWindowRect.top - NewWindowRect.top), SRCCOPY);
952 NtUserReleaseDC(Wnd, Dc);
953 }
954 }
955 else
956 {
957 CopyRgn = NULL;
958 }
959
960 /* We need to redraw what wasn't visible before */
961 if (VisAfter != NULL)
962 {
963 if (CopyRgn != NULL)
964 {
965 DirtyRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
966 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
967 if (RgnType != ERROR && RgnType != NULLREGION)
968 {
969 NtGdiOffsetRgn(DirtyRgn,
970 Window->WindowRect.left - Window->ClientRect.left,
971 Window->WindowRect.top - Window->ClientRect.top);
972 IntRedrawWindow(Window, NULL, DirtyRgn,
973 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
974 }
975 NtGdiDeleteObject(DirtyRgn);
976 }
977 else
978 {
979 IntRedrawWindow(Window, NULL, 0,
980 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
981 }
982 }
983
984 if (CopyRgn != NULL)
985 {
986 NtGdiDeleteObject(CopyRgn);
987 }
988
989 /* Expose what was covered before but not covered anymore */
990 if (VisBefore != NULL)
991 {
992 ExposedRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
993 NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
994 NtGdiOffsetRgn(ExposedRgn, OldWindowRect.left - NewWindowRect.left,
995 OldWindowRect.top - NewWindowRect.top);
996 if (VisAfter != NULL)
997 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
998 else
999 RgnType = SIMPLEREGION;
1000
1001 if (RgnType != ERROR && RgnType != NULLREGION)
1002 {
1003 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, Window,
1004 ExposedRgn);
1005 }
1006 NtGdiDeleteObject(ExposedRgn);
1007 NtGdiDeleteObject(VisBefore);
1008 }
1009
1010 if (VisAfter != NULL)
1011 {
1012 NtGdiDeleteObject(VisAfter);
1013 }
1014
1015 if (!(WinPos.flags & SWP_NOREDRAW))
1016 {
1017 IntRedrawWindow(Window, NULL, 0, RDW_ALLCHILDREN | RDW_ERASENOW);
1018 }
1019
1020 /* FIXME: Check some conditions before doing this. */
1021 IntSendWINDOWPOSCHANGEDMessage(WinPos.hwnd, &WinPos);
1022
1023 IntReleaseWindowObject(Window);
1024
1025 return TRUE;
1026 }
1027
1028 LRESULT STDCALL
1029 WinPosGetNonClientSize(HWND Wnd, RECT* WindowRect, RECT* ClientRect)
1030 {
1031 *ClientRect = *WindowRect;
1032 return(IntSendNCCALCSIZEMessage(Wnd, FALSE, ClientRect, NULL));
1033 }
1034
1035 BOOLEAN FASTCALL
1036 WinPosShowWindow(HWND Wnd, INT Cmd)
1037 {
1038 BOOLEAN WasVisible;
1039 PWINDOW_OBJECT Window;
1040 NTSTATUS Status;
1041 UINT Swp = 0;
1042 RECT NewPos;
1043 BOOLEAN ShowFlag;
1044 // HRGN VisibleRgn;
1045
1046 Status =
1047 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation->HandleTable,
1048 Wnd,
1049 otWindow,
1050 (PVOID*)&Window);
1051 if (!NT_SUCCESS(Status))
1052 {
1053 return(FALSE);
1054 }
1055
1056 WasVisible = (Window->Style & WS_VISIBLE) != 0;
1057
1058 switch (Cmd)
1059 {
1060 case SW_HIDE:
1061 {
1062 if (!WasVisible)
1063 {
1064 ObmDereferenceObject(Window);
1065 return(FALSE);
1066 }
1067 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE |
1068 SWP_NOZORDER;
1069 break;
1070 }
1071
1072 case SW_SHOWMINNOACTIVE:
1073 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1074 /* Fall through. */
1075 case SW_SHOWMINIMIZED:
1076 Swp |= SWP_SHOWWINDOW;
1077 /* Fall through. */
1078 case SW_MINIMIZE:
1079 {
1080 Swp |= SWP_FRAMECHANGED;
1081 if (!(Window->Style & WS_MINIMIZE))
1082 {
1083 Swp |= WinPosMinMaximize(Window, SW_MINIMIZE, &NewPos);
1084 }
1085 else
1086 {
1087 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1088 }
1089 break;
1090 }
1091
1092 case SW_SHOWMAXIMIZED:
1093 {
1094 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1095 if (!(Window->Style & WS_MAXIMIZE))
1096 {
1097 Swp |= WinPosMinMaximize(Window, SW_MAXIMIZE, &NewPos);
1098 }
1099 else
1100 {
1101 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1102 }
1103 break;
1104 }
1105
1106 case SW_SHOWNA:
1107 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1108 /* Fall through. */
1109 case SW_SHOW:
1110 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1111 /* Don't activate the topmost window. */
1112 break;
1113
1114 case SW_SHOWNOACTIVATE:
1115 Swp |= SWP_NOZORDER;
1116 /* Fall through. */
1117 case SW_SHOWNORMAL:
1118 case SW_SHOWDEFAULT:
1119 case SW_RESTORE:
1120 Swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1121 if (Window->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1122 {
1123 Swp |= WinPosMinMaximize(Window, SW_RESTORE, &NewPos);
1124 }
1125 else
1126 {
1127 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1128 }
1129 break;
1130 }
1131
1132 ShowFlag = (Cmd != SW_HIDE);
1133 if (ShowFlag != WasVisible)
1134 {
1135 NtUserSendMessage(Wnd, WM_SHOWWINDOW, ShowFlag, 0);
1136 /*
1137 * FIXME: Need to check the window wasn't destroyed during the
1138 * window procedure.
1139 */
1140 }
1141
1142 #if 1
1143 /* We can't activate a child window */
1144 if ((Window->Style & WS_CHILD) &&
1145 !(Window->ExStyle & WS_EX_MDICHILD))
1146 {
1147 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1148 }
1149
1150 WinPosSetWindowPos(Window->Self, HWND_TOP, NewPos.left, NewPos.top,
1151 NewPos.right, NewPos.bottom, LOWORD(Swp));
1152
1153 if (Cmd == SW_HIDE)
1154 {
1155 /* FIXME: This will cause the window to be activated irrespective
1156 * of whether it is owned by the same thread. Has to be done
1157 * asynchronously.
1158 */
1159
1160 if (Window->Self == IntGetActiveWindow())
1161 {
1162 WinPosActivateOtherWindow(Window);
1163 }
1164
1165 /* Revert focus to parent */
1166 if (Wnd == IntGetFocusWindow() ||
1167 IntIsChildWindow(Wnd, IntGetFocusWindow()))
1168 {
1169 IntSetFocusWindow(Window->Parent->Self);
1170 }
1171 }
1172
1173 /* FIXME: Check for window destruction. */
1174 /* Show title for minimized windows. */
1175 if (Window->Style & WS_MINIMIZE)
1176 {
1177 WinPosShowIconTitle(Window, TRUE);
1178 }
1179 #else
1180 if (Window->Style & WS_CHILD &&
1181 !IntIsWindowVisible(Window->Parent->Self) &&
1182 (Swp & (SWP_NOSIZE | SWP_NOMOVE)) == (SWP_NOSIZE | SWP_NOMOVE))
1183 {
1184 if (Cmd == SW_HIDE)
1185 {
1186 VisibleRgn = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop, Window,
1187 FALSE, FALSE, FALSE);
1188 Window->Style &= ~WS_VISIBLE;
1189 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop, Window, VisibleRgn);
1190 NtGdiDeleteObject(VisibleRgn);
1191 }
1192 else
1193 {
1194 Window->Style |= WS_VISIBLE;
1195 }
1196 }
1197 else
1198 {
1199 if (Window->Style & WS_CHILD &&
1200 !(Window->ExStyle & WS_EX_MDICHILD))
1201 {
1202 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1203 }
1204 if (!(Swp & MINMAX_NOSWP))
1205 {
1206 WinPosSetWindowPos(Wnd, HWND_TOP, NewPos.left, NewPos.top,
1207 NewPos.right, NewPos.bottom, LOWORD(Swp));
1208 if (Cmd == SW_HIDE)
1209 {
1210 /* Hide the window. */
1211 if (Wnd == IntGetActiveWindow())
1212 {
1213 WinPosActivateOtherWindow(Window);
1214 }
1215 /* Revert focus to parent. */
1216 if (Wnd == IntGetFocusWindow() ||
1217 IntIsChildWindow(Wnd, IntGetFocusWindow()))
1218 {
1219 IntSetFocusWindow(Window->Parent->Self);
1220 }
1221 }
1222 }
1223 /* FIXME: Check for window destruction. */
1224 /* Show title for minimized windows. */
1225 if (Window->Style & WS_MINIMIZE)
1226 {
1227 WinPosShowIconTitle(Window, TRUE);
1228 }
1229 }
1230 #endif
1231
1232 if (Window->Flags & WINDOWOBJECT_NEED_SIZE)
1233 {
1234 WPARAM wParam = SIZE_RESTORED;
1235
1236 Window->Flags &= ~WINDOWOBJECT_NEED_SIZE;
1237 if (Window->Style & WS_MAXIMIZE)
1238 {
1239 wParam = SIZE_MAXIMIZED;
1240 }
1241 else if (Window->Style & WS_MINIMIZE)
1242 {
1243 wParam = SIZE_MINIMIZED;
1244 }
1245
1246 NtUserSendMessage(Wnd, WM_SIZE, wParam,
1247 MAKELONG(Window->ClientRect.right -
1248 Window->ClientRect.left,
1249 Window->ClientRect.bottom -
1250 Window->ClientRect.top));
1251 NtUserSendMessage(Wnd, WM_MOVE, 0,
1252 MAKELONG(Window->ClientRect.left,
1253 Window->ClientRect.top));
1254 }
1255
1256 /* Activate the window if activation is not requested and the window is not minimized */
1257 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1258 {
1259 WinPosChangeActiveWindow(Wnd, FALSE);
1260 }
1261
1262 ObmDereferenceObject(Window);
1263 return(WasVisible);
1264 }
1265
1266 BOOL STATIC FASTCALL
1267 WinPosPtInWindow(PWINDOW_OBJECT Window, POINT Point)
1268 {
1269 return(Point.x >= Window->WindowRect.left &&
1270 Point.x < Window->WindowRect.right &&
1271 Point.y >= Window->WindowRect.top &&
1272 Point.y < Window->WindowRect.bottom);
1273 }
1274
1275 USHORT STATIC STDCALL
1276 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, POINT Point,
1277 PWINDOW_OBJECT* Window)
1278 {
1279 PWINDOW_OBJECT Current;
1280
1281 ExAcquireFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1282 Current = ScopeWin->FirstChild;
1283 while (Current)
1284 {
1285 if (Current->Style & WS_VISIBLE &&
1286 ((!(Current->Style & WS_DISABLED)) ||
1287 (Current->Style & (WS_CHILD | WS_POPUP)) != WS_CHILD) &&
1288 WinPosPtInWindow(Current, Point))
1289 {
1290 *Window = Current;
1291 if (Current->Style & WS_DISABLED)
1292 {
1293 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1294 return(HTERROR);
1295 }
1296 if (Current->Style & WS_MINIMIZE)
1297 {
1298 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1299 return(HTCAPTION);
1300 }
1301 if (Point.x >= Current->ClientRect.left &&
1302 Point.x < Current->ClientRect.right &&
1303 Point.y >= Current->ClientRect.top &&
1304 Point.y < Current->ClientRect.bottom)
1305 {
1306
1307 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1308 return(WinPosSearchChildren(Current, Point, Window));
1309 }
1310
1311 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1312 return(0);
1313 }
1314 Current = Current->NextSibling;
1315 }
1316
1317 ExReleaseFastMutexUnsafe(&ScopeWin->ChildrenListLock);
1318 return(0);
1319 }
1320
1321 USHORT STDCALL
1322 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, POINT WinPoint,
1323 PWINDOW_OBJECT* Window)
1324 {
1325 HWND DesktopWindowHandle;
1326 PWINDOW_OBJECT DesktopWindow;
1327 POINT Point = WinPoint;
1328 USHORT HitTest;
1329
1330 *Window = NULL;
1331
1332 if (ScopeWin->Style & WS_DISABLED)
1333 {
1334 return(HTERROR);
1335 }
1336
1337 /* Translate the point to the space of the scope window. */
1338 DesktopWindowHandle = IntGetDesktopWindow();
1339 DesktopWindow = IntGetWindowObject(DesktopWindowHandle);
1340 Point.x += ScopeWin->ClientRect.left - DesktopWindow->ClientRect.left;
1341 Point.y += ScopeWin->ClientRect.top - DesktopWindow->ClientRect.top;
1342 IntReleaseWindowObject(DesktopWindow);
1343
1344 HitTest = WinPosSearchChildren(ScopeWin, Point, Window);
1345 if (HitTest != 0)
1346 {
1347 return(HitTest);
1348 }
1349
1350 if ((*Window) == NULL)
1351 {
1352 return(HTNOWHERE);
1353 }
1354 if ((*Window)->MessageQueue == PsGetWin32Thread()->MessageQueue)
1355 {
1356 HitTest = IntSendMessage((*Window)->Self, WM_NCHITTEST, 0,
1357 MAKELONG(Point.x, Point.y), FALSE);
1358 /* FIXME: Check for HTTRANSPARENT here. */
1359 }
1360 else
1361 {
1362 HitTest = HTCLIENT;
1363 }
1364
1365 return(HitTest);
1366 }
1367
1368 BOOL
1369 WinPosSetActiveWindow(PWINDOW_OBJECT Window, BOOL Mouse, BOOL ChangeFocus)
1370 {
1371 PUSER_MESSAGE_QUEUE ActiveQueue;
1372 HWND PrevActive;
1373
1374 ActiveQueue = IntGetFocusMessageQueue();
1375 if (ActiveQueue != NULL)
1376 {
1377 PrevActive = ActiveQueue->ActiveWindow;
1378 }
1379 else
1380 {
1381 PrevActive = NULL;
1382 }
1383
1384 if (Window->Self == IntGetActiveDesktop() || Window->Self == PrevActive)
1385 {
1386 return(FALSE);
1387 }
1388 if (PrevActive != NULL)
1389 {
1390 PWINDOW_OBJECT PrevActiveWindow = IntGetWindowObject(PrevActive);
1391 if(PrevActiveWindow)
1392 {
1393 WORD Iconised = HIWORD(PrevActiveWindow->Style & WS_MINIMIZE);
1394 if (!IntSendMessage(PrevActive, WM_NCACTIVATE, FALSE, 0, TRUE))
1395 {
1396 /* FIXME: Check if the new window is system modal. */
1397 return(FALSE);
1398 }
1399 IntSendMessage(PrevActive,
1400 WM_ACTIVATE,
1401 MAKEWPARAM(WA_INACTIVE, Iconised),
1402 (LPARAM)Window->Self,
1403 TRUE);
1404 /* FIXME: Check if anything changed while processing the message. */
1405 IntReleaseWindowObject(PrevActiveWindow);
1406 }
1407 else
1408 {
1409 if(ActiveQueue)
1410 ActiveQueue->ActiveWindow = NULL;
1411 PrevActive = NULL;
1412 }
1413 }
1414
1415 if (Window != NULL)
1416 {
1417 Window->MessageQueue->ActiveWindow = Window->Self;
1418 }
1419 else if (ActiveQueue != NULL)
1420 {
1421 ActiveQueue->ActiveWindow = NULL;
1422 }
1423 /* FIXME: Unset this flag for inactive windows */
1424 //if ((Window->Style) & WS_CHILD) Window->Flags |= WIN_NCACTIVATED;
1425
1426 /* FIXME: Send palette messages. */
1427
1428 /* FIXME: Redraw icon title of previously active window. */
1429
1430 /* FIXME: Bring the window to the top. */
1431
1432 /* FIXME: Send WM_ACTIVATEAPP */
1433
1434 IntSetFocusMessageQueue(Window->MessageQueue);
1435
1436 /* FIXME: Send activate messages. */
1437
1438 /* FIXME: Change focus. */
1439
1440 /* FIXME: Redraw new window icon title. */
1441
1442 return(TRUE);
1443 }
1444
1445 HWND STDCALL
1446 NtUserGetActiveWindow(VOID)
1447 {
1448 PUSER_MESSAGE_QUEUE ActiveQueue;
1449
1450 ActiveQueue = IntGetFocusMessageQueue();
1451 if (ActiveQueue == NULL)
1452 {
1453 return(NULL);
1454 }
1455 return(ActiveQueue->ActiveWindow);
1456 }
1457
1458 HWND STDCALL
1459 NtUserSetActiveWindow(HWND hWnd)
1460 {
1461 PWINDOW_OBJECT Window;
1462 PUSER_MESSAGE_QUEUE ThreadQueue;
1463 HWND Prev;
1464
1465 Window = IntGetWindowObject(hWnd);
1466 if (Window == NULL || (Window->Style & (WS_DISABLED | WS_CHILD)))
1467 {
1468 IntReleaseWindowObject(Window);
1469 return(0);
1470 }
1471 ThreadQueue = (PUSER_MESSAGE_QUEUE)PsGetWin32Thread()->MessageQueue;
1472 if (Window->MessageQueue != ThreadQueue)
1473 {
1474 IntReleaseWindowObject(Window);
1475 return(0);
1476 }
1477 Prev = Window->MessageQueue->ActiveWindow;
1478 WinPosSetActiveWindow(Window, FALSE, FALSE);
1479 IntReleaseWindowObject(Window);
1480 return(Prev);
1481 }
1482
1483
1484 /* EOF */