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.72 2003/12/26 14:50:29 weiden 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 | WS_MINIMIZE)))))
72 #define HAS_THICKFRAME(Style, ExStyle) \
73 (((Style) & WS_THICKFRAME) && !((Style) & WS_MINIMIZE) && \
74 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
76 #define HAS_THINFRAME(Style, ExStyle) \
77 (((Style) & (WS_BORDER | WS_MINIMIZE)) || (!((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
)
126 Window
= IntGetParent(Window
);
127 if (!Window
|| IntIsDesktopWindow(Window
))
129 IntSetFocusMessageQueue(NULL
);
132 if (IntSetForegroundWindow(Window
))
140 WinPosFindIconPos(HWND hWnd
, POINT
*Pos
)
145 PINTERNALPOS FASTCALL
146 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject
, POINT pt
, PRECT RestoreRect
)
150 if (WindowObject
->InternalPos
== NULL
)
153 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
155 if(WindowObject
->Parent
== NULL
)
156 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
158 WorkArea
= WindowObject
->Parent
->ClientRect
;
160 WindowObject
->InternalPos
= ExAllocatePool(NonPagedPool
, sizeof(INTERNALPOS
));
161 if(!WindowObject
->InternalPos
)
163 DPRINT1("Failed to allocate INTERNALPOS structure for window 0x%x\n", WindowObject
->Self
);
166 WindowObject
->InternalPos
->NormalRect
= WindowObject
->WindowRect
;
167 if (HAS_DLGFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
169 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
170 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
175 if (HAS_THICKFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
177 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
178 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
180 else if (HAS_THINFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
182 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
183 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
186 WindowObject
->InternalPos
->MaxPos
.x
= WorkArea
.left
- XInc
;
187 WindowObject
->InternalPos
->MaxPos
.y
= WorkArea
.top
- YInc
;
188 WindowObject
->InternalPos
->IconPos
.x
= WorkArea
.left
;
189 WindowObject
->InternalPos
->IconPos
.y
= WorkArea
.bottom
- NtUserGetSystemMetrics(SM_CYMINIMIZED
);
191 if (WindowObject
->Style
& WS_MINIMIZE
)
193 WindowObject
->InternalPos
->IconPos
= pt
;
195 else if (WindowObject
->Style
& WS_MAXIMIZE
)
197 WindowObject
->InternalPos
->MaxPos
= pt
;
199 else if (RestoreRect
!= NULL
)
201 WindowObject
->InternalPos
->NormalRect
= *RestoreRect
;
203 return(WindowObject
->InternalPos
);
207 WinPosMinMaximize(PWINDOW_OBJECT WindowObject
, UINT ShowFlag
, RECT
* NewPos
)
210 PINTERNALPOS InternalPos
;
213 Size
.x
= WindowObject
->WindowRect
.left
;
214 Size
.y
= WindowObject
->WindowRect
.top
;
215 InternalPos
= WinPosInitInternalPos(WindowObject
, Size
,
216 &WindowObject
->WindowRect
);
220 if (WindowObject
->Style
& WS_MINIMIZE
)
222 if (!IntSendMessage(WindowObject
->Self
, WM_QUERYOPEN
, 0, 0, TRUE
))
224 return(SWP_NOSIZE
| SWP_NOMOVE
);
226 SwpFlags
|= SWP_NOCOPYBITS
;
232 if (WindowObject
->Style
& WS_MAXIMIZE
)
234 WindowObject
->Flags
|= WINDOWOBJECT_RESTOREMAX
;
235 WindowObject
->Style
&= ~WS_MAXIMIZE
;
239 WindowObject
->Flags
&= ~WINDOWOBJECT_RESTOREMAX
;
241 WindowObject
->Style
|= WS_MINIMIZE
;
242 WinPosFindIconPos(WindowObject
, &InternalPos
->IconPos
);
243 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
244 NtUserGetSystemMetrics(SM_CXMINIMIZED
),
245 NtUserGetSystemMetrics(SM_CYMINIMIZED
));
246 SwpFlags
|= SWP_NOCOPYBITS
;
252 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
254 if (WindowObject
->Style
& WS_MINIMIZE
)
256 WindowObject
->Style
&= ~WS_MINIMIZE
;
258 WindowObject
->Style
|= WS_MAXIMIZE
;
259 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
,
266 if (WindowObject
->Style
& WS_MINIMIZE
)
268 WindowObject
->Style
&= ~WS_MINIMIZE
;
269 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
271 WinPosGetMinMaxInfo(WindowObject
, &Size
,
272 &InternalPos
->MaxPos
, NULL
, NULL
);
273 WindowObject
->Style
|= WS_MAXIMIZE
;
274 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
275 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
280 *NewPos
= InternalPos
->NormalRect
;
281 NewPos
->right
-= NewPos
->left
;
282 NewPos
->bottom
-= NewPos
->top
;
288 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
292 WindowObject
->Style
&= ~WS_MAXIMIZE
;
293 *NewPos
= InternalPos
->NormalRect
;
294 NewPos
->right
-= NewPos
->left
;
295 NewPos
->bottom
-= NewPos
->top
;
303 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
309 WinPosFillMinMaxInfoStruct(PWINDOW_OBJECT Window
, MINMAXINFO
*Info
)
313 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
315 if(Window
->Parent
== NULL
)
316 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
318 WorkArea
= Window
->Parent
->ClientRect
;
320 /* Get default values. */
321 Info
->ptMaxSize
.x
= WorkArea
.right
- WorkArea
.left
;
322 Info
->ptMaxSize
.y
= WorkArea
.bottom
- WorkArea
.top
;
323 Info
->ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
324 Info
->ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
325 Info
->ptMaxTrackSize
.x
= Info
->ptMaxSize
.x
;
326 Info
->ptMaxTrackSize
.y
= Info
->ptMaxSize
.y
;
328 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
330 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
331 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
336 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
338 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
339 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
341 else if (HAS_THINFRAME(Window
->Style
, Window
->ExStyle
))
343 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
344 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
347 Info
->ptMaxSize
.x
+= 2 * XInc
;
348 Info
->ptMaxSize
.y
+= 2 * YInc
;
350 if (Window
->InternalPos
!= NULL
)
352 Info
->ptMaxPosition
= Window
->InternalPos
->MaxPos
;
356 Info
->ptMaxPosition
.x
-= WorkArea
.left
+ XInc
;
357 Info
->ptMaxPosition
.y
-= WorkArea
.top
+ YInc
;
362 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
363 POINT
* MinTrack
, POINT
* MaxTrack
)
367 WinPosFillMinMaxInfoStruct(Window
, &MinMax
);
369 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
, TRUE
);
371 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
372 MinMax
.ptMinTrackSize
.x
);
373 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
374 MinMax
.ptMinTrackSize
.y
);
376 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
377 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
378 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
379 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
381 return 0; //FIXME: what does it return?
386 WinPosChangeActiveWindow(HWND hWnd
, BOOL MouseMsg
)
388 PWINDOW_OBJECT WindowObject
;
390 WindowObject
= IntGetWindowObject(hWnd
);
391 if (WindowObject
== NULL
)
399 MAKELONG(MouseMsg
? WA_CLICKACTIVE
: WA_CLICKACTIVE
,
400 (WindowObject
->Style
& WS_MINIMIZE
) ? 1 : 0),
401 (LPARAM
)IntGetDesktopWindow(), /* FIXME: Previous active window */
404 IntSetForegroundWindow(WindowObject
);
406 IntReleaseWindowObject(WindowObject
);
413 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
414 RECT
* WindowRect
, RECT
* ClientRect
)
418 /* Send WM_NCCALCSIZE message to get new client area */
419 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
421 NCCALCSIZE_PARAMS params
;
422 WINDOWPOS winposCopy
;
424 params
.rgrc
[0] = *WindowRect
;
425 params
.rgrc
[1] = Window
->WindowRect
;
426 params
.rgrc
[2] = Window
->ClientRect
;
427 if (0 != (Window
->Style
& WS_CHILD
))
429 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
430 - Window
->Parent
->ClientRect
.top
);
431 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
432 - Window
->Parent
->ClientRect
.top
);
433 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
434 - Window
->Parent
->ClientRect
.top
);
436 params
.lppos
= &winposCopy
;
437 winposCopy
= *WinPos
;
439 wvrFlags
= IntSendNCCALCSIZEMessage(Window
->Self
, TRUE
, NULL
, ¶ms
);
441 /* If the application send back garbage, ignore it */
442 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
443 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
445 *ClientRect
= params
.rgrc
[0];
446 if (Window
->Style
& WS_CHILD
)
448 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
449 Window
->Parent
->ClientRect
.top
);
453 /* FIXME: WVR_ALIGNxxx */
455 if (ClientRect
->left
!= Window
->ClientRect
.left
||
456 ClientRect
->top
!= Window
->ClientRect
.top
)
458 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
461 if ((ClientRect
->right
- ClientRect
->left
!=
462 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
463 (ClientRect
->bottom
- ClientRect
->top
!=
464 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
466 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
471 if (! (WinPos
->flags
& SWP_NOMOVE
)
472 && (ClientRect
->left
!= Window
->ClientRect
.left
||
473 ClientRect
->top
!= Window
->ClientRect
.top
))
475 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
483 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
490 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
492 IntSendWINDOWPOSCHANGINGMessage(WindowObject
->Self
, WinPos
);
495 *WindowRect
= WindowObject
->WindowRect
;
497 (WindowObject
->Style
& WS_MINIMIZE
) ? WindowObject
->WindowRect
:
498 WindowObject
->ClientRect
;
500 if (!(WinPos
->flags
& SWP_NOSIZE
))
502 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
503 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
506 if (!(WinPos
->flags
& SWP_NOMOVE
))
510 if (0 != (WindowObject
->Style
& WS_CHILD
))
512 X
+= WindowObject
->Parent
->ClientRect
.left
;
513 Y
+= WindowObject
->Parent
->ClientRect
.top
;
515 WindowRect
->left
= X
;
517 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
518 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
519 NtGdiOffsetRect(ClientRect
,
520 X
- WindowObject
->WindowRect
.left
,
521 Y
- WindowObject
->WindowRect
.top
);
524 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
530 * Fix Z order taking into account owned popups -
531 * basically we need to maintain them above the window that owns them
534 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
538 return hWndInsertAfter
;
541 HWND Owner
= NtUserGetWindow(hWnd
, GW_OWNER
);
542 LONG Style
= NtUserGetWindowLong(hWnd
, GWL_STYLE
, FALSE
);
543 PWINDOW_OBJECT DesktopWindow
;
546 if ((Style
& WS_POPUP
) && Owner
)
548 /* Make sure this popup stays above the owner */
549 HWND hWndLocalPrev
= HWND_TOP
;
551 if (hWndInsertAfter
!= HWND_TOP
)
553 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
554 List
= IntWinListChildren(DesktopWindow
);
555 IntReleaseWindowObject(DesktopWindow
);
558 for (i
= 0; List
[i
]; i
++)
560 if (List
[i
] == Owner
) break;
561 if (List
[i
] != hWnd
) hWndLocalPrev
= List
[i
];
562 if (hWndLocalPrev
== hWndInsertAfter
) break;
564 hWndInsertAfter
= hWndLocalPrev
;
568 else if (Style
& WS_CHILD
)
570 return hWndInsertAfter
;
575 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
576 List
= IntWinListChildren(DesktopWindow
);
577 IntReleaseWindowObject(DesktopWindow
);
581 for (i
= 0; List
[i
]; i
++)
585 if ((NtUserGetWindowLong(List
[i
], GWL_STYLE
, FALSE
) & WS_POPUP
) &&
586 NtUserGetWindow(List
[i
], GW_OWNER
) == hWnd
)
588 WinPosSetWindowPos(List
[i
], hWndInsertAfter
, 0, 0, 0, 0,
589 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
590 hWndInsertAfter
= List
[i
];
596 return hWndInsertAfter
;
599 /***********************************************************************
600 * WinPosInternalMoveWindow
602 * Update WindowRect and ClientRect of Window and all of its children
603 * We keep both WindowRect and ClientRect in screen coordinates internally
606 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
608 PWINDOW_OBJECT Child
;
610 Window
->WindowRect
.left
+= MoveX
;
611 Window
->WindowRect
.right
+= MoveX
;
612 Window
->WindowRect
.top
+= MoveY
;
613 Window
->WindowRect
.bottom
+= MoveY
;
615 Window
->ClientRect
.left
+= MoveX
;
616 Window
->ClientRect
.right
+= MoveX
;
617 Window
->ClientRect
.top
+= MoveY
;
618 Window
->ClientRect
.bottom
+= MoveY
;
620 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
621 Child
= Window
->FirstChild
;
624 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
625 Child
= Child
->NextSibling
;
627 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
631 * WinPosFixupSWPFlags
633 * Fix redundant flags and values in the WINDOWPOS structure.
637 WinPosFixupFlags(WINDOWPOS
*WinPos
, PWINDOW_OBJECT Window
)
639 if (Window
->Style
& WS_VISIBLE
)
641 WinPos
->flags
&= ~SWP_SHOWWINDOW
;
645 WinPos
->flags
&= ~SWP_HIDEWINDOW
;
646 if (!(WinPos
->flags
& SWP_SHOWWINDOW
))
647 WinPos
->flags
|= SWP_NOREDRAW
;
650 WinPos
->cx
= max(WinPos
->cx
, 0);
651 WinPos
->cy
= max(WinPos
->cy
, 0);
653 /* Check for right size */
654 if (Window
->WindowRect
.right
- Window
->WindowRect
.left
== WinPos
->cx
&&
655 Window
->WindowRect
.bottom
- Window
->WindowRect
.top
== WinPos
->cy
)
657 WinPos
->flags
|= SWP_NOSIZE
;
660 /* Check for right position */
661 if (Window
->WindowRect
.left
== WinPos
->x
&&
662 Window
->WindowRect
.top
== WinPos
->y
)
664 WinPos
->flags
|= SWP_NOMOVE
;
667 if (WinPos
->hwnd
== NtUserGetForegroundWindow())
669 WinPos
->flags
|= SWP_NOACTIVATE
; /* Already active */
672 if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
674 /* Bring to the top when activating */
675 if (!(WinPos
->flags
& SWP_NOACTIVATE
))
677 WinPos
->flags
&= ~SWP_NOZORDER
;
678 WinPos
->hwndInsertAfter
= HWND_TOP
;
683 /* Check hwndInsertAfter */
684 if (!(WinPos
->flags
& SWP_NOZORDER
))
686 /* Fix sign extension */
687 if (WinPos
->hwndInsertAfter
== (HWND
)0xffff)
689 WinPos
->hwndInsertAfter
= HWND_TOPMOST
;
691 else if (WinPos
->hwndInsertAfter
== (HWND
)0xfffe)
693 WinPos
->hwndInsertAfter
= HWND_NOTOPMOST
;
696 /* FIXME: TOPMOST not supported yet */
697 if ((WinPos
->hwndInsertAfter
== HWND_TOPMOST
) ||
698 (WinPos
->hwndInsertAfter
== HWND_NOTOPMOST
))
700 WinPos
->hwndInsertAfter
= HWND_TOP
;
703 /* hwndInsertAfter must be a sibling of the window */
704 if ((WinPos
->hwndInsertAfter
!= HWND_TOP
) &&
705 (WinPos
->hwndInsertAfter
!= HWND_BOTTOM
))
707 if (NtUserGetAncestor(WinPos
->hwndInsertAfter
, GA_PARENT
) !=
715 * We don't need to change the Z order of hwnd if it's already
716 * inserted after hwndInsertAfter or when inserting hwnd after
719 if ((WinPos
->hwnd
== WinPos
->hwndInsertAfter
) ||
720 (WinPos
->hwnd
== NtUserGetWindow(WinPos
->hwndInsertAfter
, GW_HWNDNEXT
)))
722 WinPos
->flags
|= SWP_NOZORDER
;
731 /* x and y are always screen relative */
733 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
736 PWINDOW_OBJECT Window
;
740 HRGN VisBefore
= NULL
;
741 HRGN VisAfter
= NULL
;
742 HRGN DirtyRgn
= NULL
;
743 HRGN ExposedRgn
= NULL
;
746 RECT OldWindowRect
, OldClientRect
;
752 /* FIXME: Get current active window from active queue. */
754 Window
= IntGetWindowObject(Wnd
);
757 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
762 * Only allow CSRSS to mess with the desktop window
764 if (Wnd
== IntGetDesktopWindow() &&
765 Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
771 WinPos
.hwndInsertAfter
= WndInsertAfter
;
776 WinPos
.flags
= flags
;
777 if (Window
->Style
& WS_CHILD
)
779 WinPos
.x
-= Window
->Parent
->ClientRect
.left
;
780 WinPos
.y
-= Window
->Parent
->ClientRect
.top
;
783 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
785 /* Fix up the flags. */
786 if (!WinPosFixupFlags(&WinPos
, Window
))
788 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
789 IntReleaseWindowObject(Window
);
793 /* Does the window still exist? */
794 if (!IntIsWindow(WinPos
.hwnd
))
796 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
800 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
802 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) == IntGetDesktopWindow())
804 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
807 /* Compute the visible region before the window position is changed */
808 if ((!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
809 WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
810 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
811 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
813 VisBefore
= VIS_ComputeVisibleRegion(
814 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
816 if (UnsafeIntGetRgnBox(VisBefore
, &TempRect
) == NULLREGION
)
818 NtGdiDeleteObject(VisBefore
);
823 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
825 /* Relink windows. (also take into account shell window in hwndShellWindow) */
826 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwnd
!= NtUserGetShellWindow())
828 PWINDOW_OBJECT ParentWindow
;
829 PWINDOW_OBJECT InsertAfterWindow
;
831 ParentWindow
= Window
->Parent
;
834 if (WinPos
.hwndInsertAfter
== HWND_TOP
)
835 InsertAfterWindow
= NULL
;
836 else if (WinPos
.hwndInsertAfter
== HWND_BOTTOM
)
837 InsertAfterWindow
= ParentWindow
->LastChild
;
839 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
840 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
842 if (InsertAfterWindow
!= Window
)
844 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
845 IntUnlinkWindow(Window
);
846 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
847 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
849 if (InsertAfterWindow
!= NULL
)
850 IntReleaseWindowObject(InsertAfterWindow
);
854 /* FIXME: Reset active DCEs */
856 OldWindowRect
= Window
->WindowRect
;
857 OldClientRect
= Window
->ClientRect
;
859 if (OldClientRect
.bottom
- OldClientRect
.top
==
860 NewClientRect
.bottom
- NewClientRect
.top
)
862 WvrFlags
&= ~WVR_VREDRAW
;
865 if (OldClientRect
.right
- OldClientRect
.left
==
866 NewClientRect
.right
- NewClientRect
.left
)
868 WvrFlags
&= ~WVR_HREDRAW
;
871 /* FIXME: Actually do something with WVR_VALIDRECTS */
873 if (! (WinPos
.flags
& SWP_NOMOVE
)
874 && (NewWindowRect
.left
!= OldWindowRect
.left
875 || NewWindowRect
.top
!= OldWindowRect
.top
))
877 WinPosInternalMoveWindow(Window
,
878 NewWindowRect
.left
- OldWindowRect
.left
,
879 NewWindowRect
.top
- OldWindowRect
.top
);
882 Window
->WindowRect
= NewWindowRect
;
883 Window
->ClientRect
= NewClientRect
;
885 if (!(WinPos
.flags
& SWP_SHOWWINDOW
) && (WinPos
.flags
& SWP_HIDEWINDOW
))
887 /* Clear the update region */
888 IntRedrawWindow(Window
, NULL
, 0, RDW_VALIDATE
| RDW_NOFRAME
|
889 RDW_NOERASE
| RDW_NOINTERNALPAINT
| RDW_ALLCHILDREN
);
890 Window
->Style
&= ~WS_VISIBLE
;
892 else if (WinPos
.flags
& SWP_SHOWWINDOW
)
894 Window
->Style
|= WS_VISIBLE
;
897 /* Determine the new visible region */
898 VisAfter
= VIS_ComputeVisibleRegion(
899 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
901 if (UnsafeIntGetRgnBox(VisAfter
, &TempRect
) == NULLREGION
)
903 NtGdiDeleteObject(VisAfter
);
908 * Determine which pixels can be copied from the old window position
909 * to the new. Those pixels must be visible in both the old and new
910 * position. Also, check the class style to see if the windows of this
911 * class need to be completely repainted on (horizontal/vertical) size
914 if (VisBefore
!= NULL
&& VisAfter
!= NULL
&& !(WinPos
.flags
& SWP_NOCOPYBITS
) &&
915 ((WinPos
.flags
& SWP_NOSIZE
) || !(WvrFlags
& WVR_REDRAW
)))
917 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
918 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
921 * If this is (also) a window resize, the whole nonclient area
922 * needs to be repainted. So we limit the copy to the client area,
923 * 'cause there is no use in copying it (would possibly cause
924 * "flashing" too). However, if the copy region is already empty,
925 * we don't have to crop (can't take anything away from an empty
928 if (!(WinPos
.flags
& (SWP_NOSIZE
| SWP_NOZORDER
)) && RgnType
!= ERROR
&&
929 RgnType
!= NULLREGION
)
931 RECT ORect
= OldClientRect
;
932 RECT NRect
= NewClientRect
;
933 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
934 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
935 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
936 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
939 /* No use in copying bits which are in the update region. */
940 if (Window
->UpdateRegion
!= NULL
)
942 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
946 * Now, get the bounding box of the copy region. If it's empty
947 * there's nothing to copy. Also, it's no use copying bits onto
950 if (UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
) == NULLREGION
)
952 /* Nothing to copy, clean up */
953 NtGdiDeleteObject(CopyRgn
);
956 else if (OldWindowRect
.left
!= NewWindowRect
.left
||
957 OldWindowRect
.top
!= NewWindowRect
.top
)
960 * Small trick here: there is no function to bitblt a region. So
961 * we set the region as the clipping region, take the bounding box
962 * of the region and bitblt that. Since nothing outside the clipping
963 * region is copied, this has the effect of bitblt'ing the region.
965 * Since NtUserGetDCEx takes ownership of the clip region, we need
966 * to create a copy of CopyRgn and pass that. We need CopyRgn later
968 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
969 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
970 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
971 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
973 CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
974 CopyRect
.bottom
- CopyRect
.top
, Dc
,
975 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
976 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
977 NtUserReleaseDC(Wnd
, Dc
);
985 /* We need to redraw what wasn't visible before */
986 if (VisAfter
!= NULL
)
990 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
991 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
992 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
994 NtGdiOffsetRgn(DirtyRgn
,
995 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
996 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
997 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
998 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1000 NtGdiDeleteObject(DirtyRgn
);
1004 IntRedrawWindow(Window
, NULL
, 0,
1005 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1009 if (CopyRgn
!= NULL
)
1011 NtGdiDeleteObject(CopyRgn
);
1014 /* Expose what was covered before but not covered anymore */
1015 if (VisBefore
!= NULL
)
1017 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1018 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
1019 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
1020 OldWindowRect
.top
- NewWindowRect
.top
);
1021 if (VisAfter
!= NULL
)
1022 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
1024 RgnType
= SIMPLEREGION
;
1026 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
1028 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
,
1031 NtGdiDeleteObject(ExposedRgn
);
1032 NtGdiDeleteObject(VisBefore
);
1035 if (VisAfter
!= NULL
)
1037 NtGdiDeleteObject(VisAfter
);
1040 if (!(WinPos
.flags
& SWP_NOREDRAW
))
1042 IntRedrawWindow(Window
, NULL
, 0, RDW_ALLCHILDREN
| RDW_ERASENOW
);
1045 if (!(WinPos
.flags
& SWP_NOACTIVATE
))
1047 if ((Window
->Style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
1049 IntSendMessage(WinPos
.hwnd
, WM_CHILDACTIVATE
, 0, 0, TRUE
);
1053 IntSetForegroundWindow(Window
);
1057 if ((WinPos
.flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
1058 IntSendWINDOWPOSCHANGEDMessage(WinPos
.hwnd
, &WinPos
);
1060 IntReleaseWindowObject(Window
);
1066 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
1068 *ClientRect
= *WindowRect
;
1069 return(IntSendNCCALCSIZEMessage(Wnd
, FALSE
, ClientRect
, NULL
));
1073 WinPosShowWindow(HWND Wnd
, INT Cmd
)
1076 PWINDOW_OBJECT Window
;
1084 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
1088 if (!NT_SUCCESS(Status
))
1093 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1101 ObmDereferenceObject(Window
);
1104 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1109 case SW_SHOWMINNOACTIVE
:
1110 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1112 case SW_SHOWMINIMIZED
:
1113 Swp
|= SWP_SHOWWINDOW
;
1117 Swp
|= SWP_FRAMECHANGED
| SWP_NOACTIVATE
;
1118 if (!(Window
->Style
& WS_MINIMIZE
))
1120 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1124 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1129 case SW_SHOWMAXIMIZED
:
1131 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1132 if (!(Window
->Style
& WS_MAXIMIZE
))
1134 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1138 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1144 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1147 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1148 /* Don't activate the topmost window. */
1151 case SW_SHOWNOACTIVATE
:
1152 Swp
|= SWP_NOZORDER
;
1155 case SW_SHOWDEFAULT
:
1157 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1158 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1160 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1164 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1169 ShowFlag
= (Cmd
!= SW_HIDE
);
1170 if (ShowFlag
!= WasVisible
)
1172 IntSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0, TRUE
);
1174 * FIXME: Need to check the window wasn't destroyed during the
1179 /* We can't activate a child window */
1180 if ((Window
->Style
& WS_CHILD
) &&
1181 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1183 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1186 WinPosSetWindowPos(Window
->Self
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1187 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1191 /* FIXME: This will cause the window to be activated irrespective
1192 * of whether it is owned by the same thread. Has to be done
1196 if (Window
->Self
== NtUserGetActiveWindow())
1198 WinPosActivateOtherWindow(Window
);
1201 /* Revert focus to parent */
1202 if (Wnd
== IntGetThreadFocusWindow() ||
1203 IntIsChildWindow(Wnd
, IntGetThreadFocusWindow()))
1205 NtUserSetFocus(Window
->Parent
->Self
);
1209 /* FIXME: Check for window destruction. */
1211 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1213 WPARAM wParam
= SIZE_RESTORED
;
1215 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1216 if (Window
->Style
& WS_MAXIMIZE
)
1218 wParam
= SIZE_MAXIMIZED
;
1220 else if (Window
->Style
& WS_MINIMIZE
)
1222 wParam
= SIZE_MINIMIZED
;
1225 IntSendMessage(Wnd
, WM_SIZE
, wParam
,
1226 MAKELONG(Window
->ClientRect
.right
-
1227 Window
->ClientRect
.left
,
1228 Window
->ClientRect
.bottom
-
1229 Window
->ClientRect
.top
), TRUE
);
1230 IntSendMessage(Wnd
, WM_MOVE
, 0,
1231 MAKELONG(Window
->ClientRect
.left
,
1232 Window
->ClientRect
.top
), TRUE
);
1235 /* Activate the window if activation is not requested and the window is not minimized */
1237 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1239 WinPosChangeActiveWindow(Wnd, FALSE);
1243 ObmDereferenceObject(Window
);
1247 BOOL STATIC FASTCALL
1248 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1250 return(Point
.x
>= Window
->WindowRect
.left
&&
1251 Point
.x
< Window
->WindowRect
.right
&&
1252 Point
.y
>= Window
->WindowRect
.top
&&
1253 Point
.y
< Window
->WindowRect
.bottom
);
1256 USHORT STATIC FASTCALL
1257 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1258 PWINDOW_OBJECT
* Window
)
1260 PWINDOW_OBJECT Current
;
1262 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1263 Current
= ScopeWin
->FirstChild
;
1266 if (Current
->Style
& WS_VISIBLE
&&
1267 ((!(Current
->Style
& WS_DISABLED
)) ||
1268 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1269 WinPosPtInWindow(Current
, Point
))
1272 ObmDereferenceObject(*Window
);
1273 ObmReferenceObjectByPointer(Current
, otWindow
);
1277 if (Current
->Style
& WS_DISABLED
)
1279 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1282 if (Point
.x
>= Current
->ClientRect
.left
&&
1283 Point
.x
< Current
->ClientRect
.right
&&
1284 Point
.y
>= Current
->ClientRect
.top
&&
1285 Point
.y
< Current
->ClientRect
.bottom
)
1288 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1289 return(WinPosSearchChildren(Current
, Point
, Window
));
1292 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1295 Current
= Current
->NextSibling
;
1298 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1303 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1304 PWINDOW_OBJECT
* Window
)
1306 HWND DesktopWindowHandle
;
1307 PWINDOW_OBJECT DesktopWindow
;
1308 POINT Point
= WinPoint
;
1315 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1319 if (ScopeWin
->Style
& WS_DISABLED
)
1324 /* Translate the point to the space of the scope window. */
1325 DesktopWindowHandle
= IntGetDesktopWindow();
1326 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1327 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1328 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1329 IntReleaseWindowObject(DesktopWindow
);
1331 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1337 if ((*Window
) == NULL
)
1341 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1343 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1344 MAKELONG(Point
.x
, Point
.y
), FALSE
);
1345 /* FIXME: Check for HTTRANSPARENT here. */
1357 NtUserGetMinMaxInfo(
1359 MINMAXINFO
*MinMaxInfo
,
1363 PINTERNALPOS InternalPos
;
1364 PWINDOW_OBJECT Window
;
1365 MINMAXINFO SafeMinMax
;
1368 Window
= IntGetWindowObject(hwnd
);
1371 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1375 Size
.x
= Window
->WindowRect
.left
;
1376 Size
.y
= Window
->WindowRect
.top
;
1377 InternalPos
= WinPosInitInternalPos(Window
, Size
,
1378 &Window
->WindowRect
);
1383 WinPosGetMinMaxInfo(Window
, &SafeMinMax
.ptMaxSize
, &SafeMinMax
.ptMaxPosition
,
1384 &SafeMinMax
.ptMinTrackSize
, &SafeMinMax
.ptMaxTrackSize
);
1388 WinPosFillMinMaxInfoStruct(Window
, &SafeMinMax
);
1390 Status
= MmCopyToCaller(MinMaxInfo
, &SafeMinMax
, sizeof(MINMAXINFO
));
1391 if(!NT_SUCCESS(Status
))
1393 IntReleaseWindowObject(Window
);
1394 SetLastNtError(Status
);
1397 IntReleaseWindowObject(Window
);
1401 IntReleaseWindowObject(Window
);