2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
19 /* $Id: winpos.c,v 1.79 2004/01/12 22:26:00 gvg Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH NtGdid
29 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <internal/safe.h>
33 #include <win32k/win32k.h>
34 #include <include/object.h>
35 #include <include/guicheck.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/desktop.h>
41 #include <include/winpos.h>
42 #include <include/rect.h>
43 #include <include/callback.h>
44 #include <include/painting.h>
45 #include <include/dce.h>
46 #include <include/vis.h>
47 #include <include/focus.h>
52 /* GLOBALS *******************************************************************/
54 #define MINMAX_NOSWP (0x00010000)
56 #define SWP_EX_NOCOPY 0x0001
57 #define SWP_EX_PAINTSELF 0x0002
59 #define SWP_AGG_NOGEOMETRYCHANGE \
60 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
61 #define SWP_AGG_NOPOSCHANGE \
62 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
63 #define SWP_AGG_STATUSFLAGS \
64 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
66 /* FUNCTIONS *****************************************************************/
68 #define HAS_DLGFRAME(Style, ExStyle) \
69 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
70 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
72 #define HAS_THICKFRAME(Style, ExStyle) \
73 (((Style) & WS_THICKFRAME) && \
74 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
76 #define HAS_THINFRAME(Style, ExStyle) \
77 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
80 IntGetClientOrigin(HWND hWnd
, LPPOINT Point
)
82 PWINDOW_OBJECT WindowObject
;
84 WindowObject
= IntGetWindowObject(hWnd
);
85 if (WindowObject
== NULL
)
87 Point
->x
= Point
->y
= 0;
90 Point
->x
= WindowObject
->ClientRect
.left
;
91 Point
->y
= WindowObject
->ClientRect
.top
;
93 IntReleaseWindowObject(WindowObject
);
98 NtUserGetClientOrigin(HWND hWnd
, LPPOINT Point
)
104 Ret
= IntGetClientOrigin(hWnd
, &pt
);
106 Status
= MmCopyToCaller(Point
, &pt
, sizeof(POINT
));
107 if(!NT_SUCCESS(Status
))
109 SetLastNtError(Status
);
116 /*******************************************************************
117 * WinPosActivateOtherWindow
119 * Activates window other than pWnd.
122 WinPosActivateOtherWindow(PWINDOW_OBJECT Window
)
124 PWINDOW_OBJECT Child
;
125 PWINDOW_OBJECT TabooWindow
= Window
;
129 if (NULL
== Window
|| IntIsDesktopWindow(Window
))
131 IntSetFocusMessageQueue(NULL
);
134 Window
= Window
->Parent
;
135 ExAcquireFastMutex(&(Window
->ChildrenListLock
));
136 Child
= Window
->FirstChild
;
137 while (NULL
!= Child
)
139 if (Child
!= TabooWindow
)
141 ExReleaseFastMutex(&(Window
->ChildrenListLock
));
142 if (IntSetForegroundWindow(Child
))
146 ExAcquireFastMutex(&(Window
->ChildrenListLock
));
148 Child
= Child
->NextSibling
;
150 ExReleaseFastMutex(&(Window
->ChildrenListLock
));
155 WinPosFindIconPos(HWND hWnd
, POINT
*Pos
)
160 PINTERNALPOS FASTCALL
161 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject
, POINT pt
, PRECT RestoreRect
)
165 if (WindowObject
->InternalPos
== NULL
)
168 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
170 if(WindowObject
->Parent
== NULL
)
171 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
173 WorkArea
= WindowObject
->Parent
->ClientRect
;
175 WindowObject
->InternalPos
= ExAllocatePool(NonPagedPool
, sizeof(INTERNALPOS
));
176 if(!WindowObject
->InternalPos
)
178 DPRINT1("Failed to allocate INTERNALPOS structure for window 0x%x\n", WindowObject
->Self
);
181 WindowObject
->InternalPos
->NormalRect
= WindowObject
->WindowRect
;
182 if (HAS_DLGFRAME(WindowObject
->Style
, WindowObject
->ExStyle
) && !(WindowObject
->Style
& WS_MINIMIZE
))
184 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
185 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
190 if (HAS_THICKFRAME(WindowObject
->Style
, WindowObject
->ExStyle
)&& !(WindowObject
->Style
& WS_MINIMIZE
))
192 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
193 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
195 else if (HAS_THINFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
197 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
198 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
201 WindowObject
->InternalPos
->MaxPos
.x
= WorkArea
.left
- XInc
;
202 WindowObject
->InternalPos
->MaxPos
.y
= WorkArea
.top
- YInc
;
203 WindowObject
->InternalPos
->IconPos
.x
= WorkArea
.left
;
204 WindowObject
->InternalPos
->IconPos
.y
= WorkArea
.bottom
- NtUserGetSystemMetrics(SM_CYMINIMIZED
);
206 if (WindowObject
->Style
& WS_MINIMIZE
)
208 WindowObject
->InternalPos
->IconPos
= pt
;
210 else if (WindowObject
->Style
& WS_MAXIMIZE
)
212 WindowObject
->InternalPos
->MaxPos
= pt
;
214 else if (RestoreRect
!= NULL
)
216 WindowObject
->InternalPos
->NormalRect
= *RestoreRect
;
218 return(WindowObject
->InternalPos
);
222 WinPosMinMaximize(PWINDOW_OBJECT WindowObject
, UINT ShowFlag
, RECT
* NewPos
)
225 PINTERNALPOS InternalPos
;
228 Size
.x
= WindowObject
->WindowRect
.left
;
229 Size
.y
= WindowObject
->WindowRect
.top
;
230 InternalPos
= WinPosInitInternalPos(WindowObject
, Size
,
231 &WindowObject
->WindowRect
);
235 if (WindowObject
->Style
& WS_MINIMIZE
)
237 if (!IntSendMessage(WindowObject
->Self
, WM_QUERYOPEN
, 0, 0))
239 return(SWP_NOSIZE
| SWP_NOMOVE
);
241 SwpFlags
|= SWP_NOCOPYBITS
;
247 if (WindowObject
->Style
& WS_MAXIMIZE
)
249 WindowObject
->Flags
|= WINDOWOBJECT_RESTOREMAX
;
250 WindowObject
->Style
&= ~WS_MAXIMIZE
;
254 WindowObject
->Flags
&= ~WINDOWOBJECT_RESTOREMAX
;
256 IntRedrawWindow(WindowObject
, NULL
, 0, RDW_VALIDATE
| RDW_NOERASE
|
257 RDW_NOINTERNALPAINT
);
258 WindowObject
->Style
|= WS_MINIMIZE
;
259 WinPosFindIconPos(WindowObject
, &InternalPos
->IconPos
);
260 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
261 NtUserGetSystemMetrics(SM_CXMINIMIZED
),
262 NtUserGetSystemMetrics(SM_CYMINIMIZED
));
263 SwpFlags
|= SWP_NOCOPYBITS
;
269 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
271 if (WindowObject
->Style
& WS_MINIMIZE
)
273 WindowObject
->Style
&= ~WS_MINIMIZE
;
275 WindowObject
->Style
|= WS_MAXIMIZE
;
276 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
,
283 if (WindowObject
->Style
& WS_MINIMIZE
)
285 WindowObject
->Style
&= ~WS_MINIMIZE
;
286 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
288 WinPosGetMinMaxInfo(WindowObject
, &Size
,
289 &InternalPos
->MaxPos
, NULL
, NULL
);
290 WindowObject
->Style
|= WS_MAXIMIZE
;
291 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
292 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
297 *NewPos
= InternalPos
->NormalRect
;
298 NewPos
->right
-= NewPos
->left
;
299 NewPos
->bottom
-= NewPos
->top
;
305 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
309 WindowObject
->Style
&= ~WS_MAXIMIZE
;
310 *NewPos
= InternalPos
->NormalRect
;
311 NewPos
->right
-= NewPos
->left
;
312 NewPos
->bottom
-= NewPos
->top
;
320 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
326 WinPosFillMinMaxInfoStruct(PWINDOW_OBJECT Window
, MINMAXINFO
*Info
)
330 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
332 if(Window
->Parent
== NULL
)
333 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
335 WorkArea
= Window
->Parent
->ClientRect
;
337 /* Get default values. */
338 Info
->ptMaxSize
.x
= WorkArea
.right
- WorkArea
.left
;
339 Info
->ptMaxSize
.y
= WorkArea
.bottom
- WorkArea
.top
;
340 Info
->ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
341 Info
->ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
342 Info
->ptMaxTrackSize
.x
= Info
->ptMaxSize
.x
;
343 Info
->ptMaxTrackSize
.y
= Info
->ptMaxSize
.y
;
345 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
347 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
348 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
353 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
355 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
356 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
358 else if (HAS_THINFRAME(Window
->Style
, Window
->ExStyle
))
360 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
361 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
364 Info
->ptMaxSize
.x
+= 2 * XInc
;
365 Info
->ptMaxSize
.y
+= 2 * YInc
;
367 if (Window
->InternalPos
!= NULL
)
369 Info
->ptMaxPosition
= Window
->InternalPos
->MaxPos
;
373 Info
->ptMaxPosition
.x
-= WorkArea
.left
+ XInc
;
374 Info
->ptMaxPosition
.y
-= WorkArea
.top
+ YInc
;
379 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
380 POINT
* MinTrack
, POINT
* MaxTrack
)
384 WinPosFillMinMaxInfoStruct(Window
, &MinMax
);
386 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
);
388 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
389 MinMax
.ptMinTrackSize
.x
);
390 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
391 MinMax
.ptMinTrackSize
.y
);
393 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
394 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
395 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
396 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
398 return 0; //FIXME: what does it return?
402 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
403 RECT
* WindowRect
, RECT
* ClientRect
)
407 /* Send WM_NCCALCSIZE message to get new client area */
408 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
410 NCCALCSIZE_PARAMS params
;
411 WINDOWPOS winposCopy
;
413 params
.rgrc
[0] = *WindowRect
;
414 params
.rgrc
[1] = Window
->WindowRect
;
415 params
.rgrc
[2] = Window
->ClientRect
;
416 if (0 != (Window
->Style
& WS_CHILD
))
418 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
419 - Window
->Parent
->ClientRect
.top
);
420 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
421 - Window
->Parent
->ClientRect
.top
);
422 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
423 - Window
->Parent
->ClientRect
.top
);
425 params
.lppos
= &winposCopy
;
426 winposCopy
= *WinPos
;
428 wvrFlags
= IntSendMessage(Window
->Self
, WM_NCCALCSIZE
, TRUE
, (LPARAM
) ¶ms
);
430 /* If the application send back garbage, ignore it */
431 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
432 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
434 *ClientRect
= params
.rgrc
[0];
435 if (Window
->Style
& WS_CHILD
)
437 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
438 Window
->Parent
->ClientRect
.top
);
442 /* FIXME: WVR_ALIGNxxx */
444 if (ClientRect
->left
!= Window
->ClientRect
.left
||
445 ClientRect
->top
!= Window
->ClientRect
.top
)
447 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
450 if ((ClientRect
->right
- ClientRect
->left
!=
451 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
452 (ClientRect
->bottom
- ClientRect
->top
!=
453 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
455 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
460 if (! (WinPos
->flags
& SWP_NOMOVE
)
461 && (ClientRect
->left
!= Window
->ClientRect
.left
||
462 ClientRect
->top
!= Window
->ClientRect
.top
))
464 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
472 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
479 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
481 IntSendMessage(WindowObject
->Self
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
) WinPos
);
484 *WindowRect
= WindowObject
->WindowRect
;
485 *ClientRect
= WindowObject
->ClientRect
;
487 if (!(WinPos
->flags
& SWP_NOSIZE
))
489 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
490 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
493 if (!(WinPos
->flags
& SWP_NOMOVE
))
497 if (0 != (WindowObject
->Style
& WS_CHILD
))
499 X
+= WindowObject
->Parent
->ClientRect
.left
;
500 Y
+= WindowObject
->Parent
->ClientRect
.top
;
502 WindowRect
->left
= X
;
504 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
505 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
506 NtGdiOffsetRect(ClientRect
,
507 X
- WindowObject
->WindowRect
.left
,
508 Y
- WindowObject
->WindowRect
.top
);
511 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
517 * Fix Z order taking into account owned popups -
518 * basically we need to maintain them above the window that owns them
521 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
524 HWND Owner
= NtUserGetWindow(hWnd
, GW_OWNER
);
525 LONG Style
= NtUserGetWindowLong(hWnd
, GWL_STYLE
, FALSE
);
526 PWINDOW_OBJECT DesktopWindow
;
529 if ((Style
& WS_POPUP
) && Owner
)
531 /* Make sure this popup stays above the owner */
532 HWND hWndLocalPrev
= HWND_TOP
;
534 if (hWndInsertAfter
!= HWND_TOP
)
536 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
537 List
= IntWinListChildren(DesktopWindow
);
538 IntReleaseWindowObject(DesktopWindow
);
541 for (i
= 0; List
[i
]; i
++)
543 if (List
[i
] == Owner
) break;
544 if (List
[i
] != hWnd
) hWndLocalPrev
= List
[i
];
545 if (hWndLocalPrev
== hWndInsertAfter
) break;
547 hWndInsertAfter
= hWndLocalPrev
;
551 else if (Style
& WS_CHILD
)
553 return hWndInsertAfter
;
558 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
559 List
= IntWinListChildren(DesktopWindow
);
560 IntReleaseWindowObject(DesktopWindow
);
564 for (i
= 0; List
[i
]; i
++)
568 if ((NtUserGetWindowLong(List
[i
], GWL_STYLE
, FALSE
) & WS_POPUP
) &&
569 NtUserGetWindow(List
[i
], GW_OWNER
) == hWnd
)
571 WinPosSetWindowPos(List
[i
], hWndInsertAfter
, 0, 0, 0, 0,
572 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
573 hWndInsertAfter
= List
[i
];
579 return hWndInsertAfter
;
582 /***********************************************************************
583 * WinPosInternalMoveWindow
585 * Update WindowRect and ClientRect of Window and all of its children
586 * We keep both WindowRect and ClientRect in screen coordinates internally
589 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
591 PWINDOW_OBJECT Child
;
593 Window
->WindowRect
.left
+= MoveX
;
594 Window
->WindowRect
.right
+= MoveX
;
595 Window
->WindowRect
.top
+= MoveY
;
596 Window
->WindowRect
.bottom
+= MoveY
;
598 Window
->ClientRect
.left
+= MoveX
;
599 Window
->ClientRect
.right
+= MoveX
;
600 Window
->ClientRect
.top
+= MoveY
;
601 Window
->ClientRect
.bottom
+= MoveY
;
603 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
604 Child
= Window
->FirstChild
;
607 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
608 Child
= Child
->NextSibling
;
610 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
614 * WinPosFixupSWPFlags
616 * Fix redundant flags and values in the WINDOWPOS structure.
620 WinPosFixupFlags(WINDOWPOS
*WinPos
, PWINDOW_OBJECT Window
)
622 if (Window
->Style
& WS_VISIBLE
)
624 WinPos
->flags
&= ~SWP_SHOWWINDOW
;
628 WinPos
->flags
&= ~SWP_HIDEWINDOW
;
629 if (!(WinPos
->flags
& SWP_SHOWWINDOW
))
630 WinPos
->flags
|= SWP_NOREDRAW
;
633 WinPos
->cx
= max(WinPos
->cx
, 0);
634 WinPos
->cy
= max(WinPos
->cy
, 0);
636 /* Check for right size */
637 if (Window
->WindowRect
.right
- Window
->WindowRect
.left
== WinPos
->cx
&&
638 Window
->WindowRect
.bottom
- Window
->WindowRect
.top
== WinPos
->cy
)
640 WinPos
->flags
|= SWP_NOSIZE
;
643 /* Check for right position */
644 if (Window
->WindowRect
.left
== WinPos
->x
&&
645 Window
->WindowRect
.top
== WinPos
->y
)
647 WinPos
->flags
|= SWP_NOMOVE
;
650 if (WinPos
->hwnd
== NtUserGetForegroundWindow())
652 WinPos
->flags
|= SWP_NOACTIVATE
; /* Already active */
655 if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
657 /* Bring to the top when activating */
658 if (!(WinPos
->flags
& SWP_NOACTIVATE
))
660 WinPos
->flags
&= ~SWP_NOZORDER
;
661 WinPos
->hwndInsertAfter
= HWND_TOP
;
666 /* Check hwndInsertAfter */
667 if (!(WinPos
->flags
& SWP_NOZORDER
))
669 /* Fix sign extension */
670 if (WinPos
->hwndInsertAfter
== (HWND
)0xffff)
672 WinPos
->hwndInsertAfter
= HWND_TOPMOST
;
674 else if (WinPos
->hwndInsertAfter
== (HWND
)0xfffe)
676 WinPos
->hwndInsertAfter
= HWND_NOTOPMOST
;
679 /* FIXME: TOPMOST not supported yet */
680 if ((WinPos
->hwndInsertAfter
== HWND_TOPMOST
) ||
681 (WinPos
->hwndInsertAfter
== HWND_NOTOPMOST
))
683 WinPos
->hwndInsertAfter
= HWND_TOP
;
686 /* hwndInsertAfter must be a sibling of the window */
687 if ((WinPos
->hwndInsertAfter
!= HWND_TOP
) &&
688 (WinPos
->hwndInsertAfter
!= HWND_BOTTOM
))
690 if (NtUserGetAncestor(WinPos
->hwndInsertAfter
, GA_PARENT
) !=
698 * We don't need to change the Z order of hwnd if it's already
699 * inserted after hwndInsertAfter or when inserting hwnd after
702 if ((WinPos
->hwnd
== WinPos
->hwndInsertAfter
) ||
703 (WinPos
->hwnd
== NtUserGetWindow(WinPos
->hwndInsertAfter
, GW_HWNDNEXT
)))
705 WinPos
->flags
|= SWP_NOZORDER
;
714 /* x and y are always screen relative */
716 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
719 PWINDOW_OBJECT Window
;
723 HRGN VisBefore
= NULL
;
724 HRGN VisAfter
= NULL
;
725 HRGN DirtyRgn
= NULL
;
726 HRGN ExposedRgn
= NULL
;
729 RECT OldWindowRect
, OldClientRect
;
735 /* FIXME: Get current active window from active queue. */
737 Window
= IntGetWindowObject(Wnd
);
740 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
745 * Only allow CSRSS to mess with the desktop window
747 if (Wnd
== IntGetDesktopWindow() &&
748 Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
754 WinPos
.hwndInsertAfter
= WndInsertAfter
;
759 WinPos
.flags
= flags
;
760 if (Window
->Style
& WS_CHILD
)
762 WinPos
.x
-= Window
->Parent
->ClientRect
.left
;
763 WinPos
.y
-= Window
->Parent
->ClientRect
.top
;
766 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
768 /* Fix up the flags. */
769 if (!WinPosFixupFlags(&WinPos
, Window
))
771 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
772 IntReleaseWindowObject(Window
);
776 /* Does the window still exist? */
777 if (!IntIsWindow(WinPos
.hwnd
))
779 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
783 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
785 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) == IntGetDesktopWindow())
787 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
790 /* Compute the visible region before the window position is changed */
791 if (!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
792 (WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
793 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
794 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
796 VisBefore
= VIS_ComputeVisibleRegion(
797 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
799 if (UnsafeIntGetRgnBox(VisBefore
, &TempRect
) == NULLREGION
)
801 NtGdiDeleteObject(VisBefore
);
806 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
808 /* Relink windows. (also take into account shell window in hwndShellWindow) */
809 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwnd
!= NtUserGetShellWindow())
811 PWINDOW_OBJECT ParentWindow
;
812 PWINDOW_OBJECT InsertAfterWindow
;
814 ParentWindow
= Window
->Parent
;
817 if (WinPos
.hwndInsertAfter
== HWND_TOP
)
818 InsertAfterWindow
= NULL
;
819 else if (WinPos
.hwndInsertAfter
== HWND_BOTTOM
)
820 InsertAfterWindow
= ParentWindow
->LastChild
;
822 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
823 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
825 if (InsertAfterWindow
!= Window
)
827 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
828 IntUnlinkWindow(Window
);
829 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
830 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
832 if (InsertAfterWindow
!= NULL
)
833 IntReleaseWindowObject(InsertAfterWindow
);
837 /* FIXME: Reset active DCEs */
839 OldWindowRect
= Window
->WindowRect
;
840 OldClientRect
= Window
->ClientRect
;
842 if (OldClientRect
.bottom
- OldClientRect
.top
==
843 NewClientRect
.bottom
- NewClientRect
.top
)
845 WvrFlags
&= ~WVR_VREDRAW
;
848 if (OldClientRect
.right
- OldClientRect
.left
==
849 NewClientRect
.right
- NewClientRect
.left
)
851 WvrFlags
&= ~WVR_HREDRAW
;
854 /* FIXME: Actually do something with WVR_VALIDRECTS */
856 if (! (WinPos
.flags
& SWP_NOMOVE
)
857 && (NewWindowRect
.left
!= OldWindowRect
.left
858 || NewWindowRect
.top
!= OldWindowRect
.top
))
860 WinPosInternalMoveWindow(Window
,
861 NewWindowRect
.left
- OldWindowRect
.left
,
862 NewWindowRect
.top
- OldWindowRect
.top
);
865 Window
->WindowRect
= NewWindowRect
;
866 Window
->ClientRect
= NewClientRect
;
868 if (!(WinPos
.flags
& SWP_SHOWWINDOW
) && (WinPos
.flags
& SWP_HIDEWINDOW
))
870 /* Clear the update region */
871 IntRedrawWindow(Window
, NULL
, 0, RDW_VALIDATE
| RDW_NOFRAME
|
872 RDW_NOERASE
| RDW_NOINTERNALPAINT
| RDW_ALLCHILDREN
);
873 Window
->Style
&= ~WS_VISIBLE
;
875 else if (WinPos
.flags
& SWP_SHOWWINDOW
)
877 Window
->Style
|= WS_VISIBLE
;
880 /* Determine the new visible region */
881 VisAfter
= VIS_ComputeVisibleRegion(
882 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
884 if (UnsafeIntGetRgnBox(VisAfter
, &TempRect
) == NULLREGION
)
886 NtGdiDeleteObject(VisAfter
);
891 * Determine which pixels can be copied from the old window position
892 * to the new. Those pixels must be visible in both the old and new
893 * position. Also, check the class style to see if the windows of this
894 * class need to be completely repainted on (horizontal/vertical) size
897 if (VisBefore
!= NULL
&& VisAfter
!= NULL
&& !(WinPos
.flags
& SWP_NOCOPYBITS
) &&
898 ((WinPos
.flags
& SWP_NOSIZE
) || !(WvrFlags
& WVR_REDRAW
)))
900 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
901 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
904 * If this is (also) a window resize, the whole nonclient area
905 * needs to be repainted. So we limit the copy to the client area,
906 * 'cause there is no use in copying it (would possibly cause
907 * "flashing" too). However, if the copy region is already empty,
908 * we don't have to crop (can't take anything away from an empty
911 if (!(WinPos
.flags
& SWP_NOSIZE
) && RgnType
!= ERROR
&&
912 RgnType
!= NULLREGION
)
914 RECT ORect
= OldClientRect
;
915 RECT NRect
= NewClientRect
;
916 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
917 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
918 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
919 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
922 /* No use in copying bits which are in the update region. */
923 if (Window
->UpdateRegion
!= NULL
)
925 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
927 if (Window
->NCUpdateRegion
!= NULL
)
929 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->NCUpdateRegion
, RGN_DIFF
);
933 * Now, get the bounding box of the copy region. If it's empty
934 * there's nothing to copy. Also, it's no use copying bits onto
937 if (UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
) == NULLREGION
)
939 /* Nothing to copy, clean up */
940 NtGdiDeleteObject(CopyRgn
);
943 else if (OldWindowRect
.left
!= NewWindowRect
.left
||
944 OldWindowRect
.top
!= NewWindowRect
.top
)
947 * Small trick here: there is no function to bitblt a region. So
948 * we set the region as the clipping region, take the bounding box
949 * of the region and bitblt that. Since nothing outside the clipping
950 * region is copied, this has the effect of bitblt'ing the region.
952 * Since NtUserGetDCEx takes ownership of the clip region, we need
953 * to create a copy of CopyRgn and pass that. We need CopyRgn later
955 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
957 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
958 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
959 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
961 CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
962 CopyRect
.bottom
- CopyRect
.top
, Dc
,
963 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
964 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
965 NtUserReleaseDC(Wnd
, Dc
);
966 IntValidateParent(Window
, CopyRgn
);
974 /* We need to redraw what wasn't visible before */
975 if (VisAfter
!= NULL
)
979 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
980 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
981 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
983 NtGdiOffsetRgn(DirtyRgn
,
984 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
985 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
986 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
987 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
989 NtGdiDeleteObject(DirtyRgn
);
993 IntRedrawWindow(Window
, NULL
, 0,
994 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1000 NtGdiDeleteObject(CopyRgn
);
1003 /* Expose what was covered before but not covered anymore */
1004 if (VisBefore
!= NULL
)
1006 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1007 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
1008 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
1009 OldWindowRect
.top
- NewWindowRect
.top
);
1010 if (VisAfter
!= NULL
)
1011 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
1013 RgnType
= SIMPLEREGION
;
1015 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
1017 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
,
1020 NtGdiDeleteObject(ExposedRgn
);
1021 NtGdiDeleteObject(VisBefore
);
1024 if (VisAfter
!= NULL
)
1026 NtGdiDeleteObject(VisAfter
);
1029 if (!(WinPos
.flags
& SWP_NOREDRAW
))
1031 IntRedrawWindow(Window
, NULL
, 0, RDW_ALLCHILDREN
| RDW_ERASENOW
);
1034 if (!(WinPos
.flags
& SWP_NOACTIVATE
))
1036 if ((Window
->Style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
1038 IntSendMessage(WinPos
.hwnd
, WM_CHILDACTIVATE
, 0, 0);
1042 IntSetForegroundWindow(Window
);
1046 if ((WinPos
.flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
1047 IntSendMessage(WinPos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
) &WinPos
);
1049 IntReleaseWindowObject(Window
);
1055 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
1057 *ClientRect
= *WindowRect
;
1058 return(IntSendMessage(Wnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
) ClientRect
));
1062 WinPosShowWindow(HWND Wnd
, INT Cmd
)
1065 PWINDOW_OBJECT Window
;
1073 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
1077 if (!NT_SUCCESS(Status
))
1082 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1090 ObmDereferenceObject(Window
);
1093 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1098 case SW_SHOWMINNOACTIVE
:
1099 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1101 case SW_SHOWMINIMIZED
:
1102 Swp
|= SWP_SHOWWINDOW
;
1106 Swp
|= SWP_FRAMECHANGED
| SWP_NOACTIVATE
;
1107 if (!(Window
->Style
& WS_MINIMIZE
))
1109 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1113 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1118 case SW_SHOWMAXIMIZED
:
1120 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1121 if (!(Window
->Style
& WS_MAXIMIZE
))
1123 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1127 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1133 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1136 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1137 /* Don't activate the topmost window. */
1140 case SW_SHOWNOACTIVATE
:
1141 Swp
|= SWP_NOZORDER
;
1144 case SW_SHOWDEFAULT
:
1146 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1147 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1149 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1153 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1158 ShowFlag
= (Cmd
!= SW_HIDE
);
1159 if (ShowFlag
!= WasVisible
)
1161 IntSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0);
1163 * FIXME: Need to check the window wasn't destroyed during the
1168 /* We can't activate a child window */
1169 if ((Window
->Style
& WS_CHILD
) &&
1170 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1172 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1175 WinPosSetWindowPos(Window
->Self
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1176 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1180 /* FIXME: This will cause the window to be activated irrespective
1181 * of whether it is owned by the same thread. Has to be done
1185 if (Window
->Self
== NtUserGetActiveWindow())
1187 WinPosActivateOtherWindow(Window
);
1190 /* Revert focus to parent */
1191 if (Wnd
== IntGetThreadFocusWindow() ||
1192 IntIsChildWindow(Wnd
, IntGetThreadFocusWindow()))
1194 NtUserSetFocus(Window
->Parent
->Self
);
1198 /* FIXME: Check for window destruction. */
1200 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1202 WPARAM wParam
= SIZE_RESTORED
;
1204 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1205 if (Window
->Style
& WS_MAXIMIZE
)
1207 wParam
= SIZE_MAXIMIZED
;
1209 else if (Window
->Style
& WS_MINIMIZE
)
1211 wParam
= SIZE_MINIMIZED
;
1214 IntSendMessage(Wnd
, WM_SIZE
, wParam
,
1215 MAKELONG(Window
->ClientRect
.right
-
1216 Window
->ClientRect
.left
,
1217 Window
->ClientRect
.bottom
-
1218 Window
->ClientRect
.top
));
1219 IntSendMessage(Wnd
, WM_MOVE
, 0,
1220 MAKELONG(Window
->ClientRect
.left
,
1221 Window
->ClientRect
.top
));
1224 /* Activate the window if activation is not requested and the window is not minimized */
1226 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1228 WinPosChangeActiveWindow(Wnd, FALSE);
1232 ObmDereferenceObject(Window
);
1236 BOOL STATIC FASTCALL
1237 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1239 return(Point
.x
>= Window
->WindowRect
.left
&&
1240 Point
.x
< Window
->WindowRect
.right
&&
1241 Point
.y
>= Window
->WindowRect
.top
&&
1242 Point
.y
< Window
->WindowRect
.bottom
);
1245 USHORT STATIC FASTCALL
1246 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1247 PWINDOW_OBJECT
* Window
)
1249 PWINDOW_OBJECT Current
;
1251 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1252 Current
= ScopeWin
->FirstChild
;
1255 if (Current
->Style
& WS_VISIBLE
&&
1256 ((!(Current
->Style
& WS_DISABLED
)) ||
1257 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1258 WinPosPtInWindow(Current
, Point
))
1261 ObmDereferenceObject(*Window
);
1262 ObmReferenceObjectByPointer(Current
, otWindow
);
1266 if (Current
->Style
& WS_DISABLED
)
1268 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1271 if (Point
.x
>= Current
->ClientRect
.left
&&
1272 Point
.x
< Current
->ClientRect
.right
&&
1273 Point
.y
>= Current
->ClientRect
.top
&&
1274 Point
.y
< Current
->ClientRect
.bottom
)
1277 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1278 return(WinPosSearchChildren(Current
, Point
, Window
));
1281 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1284 Current
= Current
->NextSibling
;
1287 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1292 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1293 PWINDOW_OBJECT
* Window
)
1295 HWND DesktopWindowHandle
;
1296 PWINDOW_OBJECT DesktopWindow
;
1297 POINT Point
= WinPoint
;
1304 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1308 if (ScopeWin
->Style
& WS_DISABLED
)
1313 /* Translate the point to the space of the scope window. */
1314 DesktopWindowHandle
= IntGetDesktopWindow();
1315 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1316 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1317 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1318 IntReleaseWindowObject(DesktopWindow
);
1320 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1326 if ((*Window
) == NULL
)
1330 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1332 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1333 MAKELONG(Point
.x
, Point
.y
));
1334 /* FIXME: Check for HTTRANSPARENT here. */
1346 NtUserGetMinMaxInfo(
1348 MINMAXINFO
*MinMaxInfo
,
1352 PINTERNALPOS InternalPos
;
1353 PWINDOW_OBJECT Window
;
1354 MINMAXINFO SafeMinMax
;
1357 Window
= IntGetWindowObject(hwnd
);
1360 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1364 Size
.x
= Window
->WindowRect
.left
;
1365 Size
.y
= Window
->WindowRect
.top
;
1366 InternalPos
= WinPosInitInternalPos(Window
, Size
,
1367 &Window
->WindowRect
);
1372 WinPosGetMinMaxInfo(Window
, &SafeMinMax
.ptMaxSize
, &SafeMinMax
.ptMaxPosition
,
1373 &SafeMinMax
.ptMinTrackSize
, &SafeMinMax
.ptMaxTrackSize
);
1377 WinPosFillMinMaxInfoStruct(Window
, &SafeMinMax
);
1379 Status
= MmCopyToCaller(MinMaxInfo
, &SafeMinMax
, sizeof(MINMAXINFO
));
1380 if(!NT_SUCCESS(Status
))
1382 IntReleaseWindowObject(Window
);
1383 SetLastNtError(Status
);
1386 IntReleaseWindowObject(Window
);
1390 IntReleaseWindowObject(Window
);