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.70 2003/12/26 12:37:53 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))))
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
)
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 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
310 POINT
* MinTrack
, POINT
* MaxTrack
)
315 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
317 if(Window
->Parent
== NULL
)
318 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
320 WorkArea
= Window
->Parent
->ClientRect
;
322 /* Get default values. */
323 MinMax
.ptMaxSize
.x
= WorkArea
.right
- WorkArea
.left
;
324 MinMax
.ptMaxSize
.y
= WorkArea
.bottom
- WorkArea
.top
;
325 MinMax
.ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
326 MinMax
.ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
327 MinMax
.ptMaxTrackSize
.x
= MinMax
.ptMaxSize
.x
;
328 MinMax
.ptMaxTrackSize
.y
= MinMax
.ptMaxSize
.y
;
330 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
332 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
333 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
338 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
340 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
341 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
343 else if (HAS_THINFRAME(Window
->Style
, Window
->ExStyle
))
345 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
346 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
349 MinMax
.ptMaxSize
.x
+= 2 * XInc
;
350 MinMax
.ptMaxSize
.y
+= 2 * YInc
;
352 if (Window
->InternalPos
!= NULL
)
354 MinMax
.ptMaxPosition
= Window
->InternalPos
->MaxPos
;
358 MinMax
.ptMaxPosition
.x
-= WorkArea
.left
+ XInc
;
359 MinMax
.ptMaxPosition
.y
-= WorkArea
.top
+ YInc
;
362 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
, TRUE
);
364 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
365 MinMax
.ptMinTrackSize
.x
);
366 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
367 MinMax
.ptMinTrackSize
.y
);
369 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
370 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
371 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
372 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
374 return 0; //FIXME: what does it return?
379 WinPosChangeActiveWindow(HWND hWnd
, BOOL MouseMsg
)
381 PWINDOW_OBJECT WindowObject
;
383 WindowObject
= IntGetWindowObject(hWnd
);
384 if (WindowObject
== NULL
)
392 MAKELONG(MouseMsg
? WA_CLICKACTIVE
: WA_CLICKACTIVE
,
393 (WindowObject
->Style
& WS_MINIMIZE
) ? 1 : 0),
394 (LPARAM
)IntGetDesktopWindow(), /* FIXME: Previous active window */
397 IntSetForegroundWindow(WindowObject
);
399 IntReleaseWindowObject(WindowObject
);
406 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
407 RECT
* WindowRect
, RECT
* ClientRect
)
411 /* Send WM_NCCALCSIZE message to get new client area */
412 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
414 NCCALCSIZE_PARAMS params
;
415 WINDOWPOS winposCopy
;
417 params
.rgrc
[0] = *WindowRect
;
418 params
.rgrc
[1] = Window
->WindowRect
;
419 params
.rgrc
[2] = Window
->ClientRect
;
420 if (0 != (Window
->Style
& WS_CHILD
))
422 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
423 - Window
->Parent
->ClientRect
.top
);
424 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
425 - Window
->Parent
->ClientRect
.top
);
426 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
427 - Window
->Parent
->ClientRect
.top
);
429 params
.lppos
= &winposCopy
;
430 winposCopy
= *WinPos
;
432 wvrFlags
= IntSendNCCALCSIZEMessage(Window
->Self
, TRUE
, NULL
, ¶ms
);
434 /* If the application send back garbage, ignore it */
435 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
436 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
438 *ClientRect
= params
.rgrc
[0];
439 if (Window
->Style
& WS_CHILD
)
441 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
442 Window
->Parent
->ClientRect
.top
);
446 /* FIXME: WVR_ALIGNxxx */
448 if (ClientRect
->left
!= Window
->ClientRect
.left
||
449 ClientRect
->top
!= Window
->ClientRect
.top
)
451 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
454 if ((ClientRect
->right
- ClientRect
->left
!=
455 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
456 (ClientRect
->bottom
- ClientRect
->top
!=
457 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
459 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
464 if (! (WinPos
->flags
& SWP_NOMOVE
)
465 && (ClientRect
->left
!= Window
->ClientRect
.left
||
466 ClientRect
->top
!= Window
->ClientRect
.top
))
468 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
476 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
483 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
485 IntSendWINDOWPOSCHANGINGMessage(WindowObject
->Self
, WinPos
);
488 *WindowRect
= WindowObject
->WindowRect
;
490 (WindowObject
->Style
& WS_MINIMIZE
) ? WindowObject
->WindowRect
:
491 WindowObject
->ClientRect
;
493 if (!(WinPos
->flags
& SWP_NOSIZE
))
495 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
496 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
499 if (!(WinPos
->flags
& SWP_NOMOVE
))
503 if (0 != (WindowObject
->Style
& WS_CHILD
))
505 X
+= WindowObject
->Parent
->ClientRect
.left
;
506 Y
+= WindowObject
->Parent
->ClientRect
.top
;
508 WindowRect
->left
= X
;
510 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
511 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
512 NtGdiOffsetRect(ClientRect
,
513 X
- WindowObject
->WindowRect
.left
,
514 Y
- WindowObject
->WindowRect
.top
);
517 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
523 * Fix Z order taking into account owned popups -
524 * basically we need to maintain them above the window that owns them
527 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
531 return hWndInsertAfter
;
534 HWND Owner
= NtUserGetWindow(hWnd
, GW_OWNER
);
535 LONG Style
= NtUserGetWindowLong(hWnd
, GWL_STYLE
, FALSE
);
536 PWINDOW_OBJECT DesktopWindow
;
539 if ((Style
& WS_POPUP
) && Owner
)
541 /* Make sure this popup stays above the owner */
542 HWND hWndLocalPrev
= HWND_TOP
;
544 if (hWndInsertAfter
!= HWND_TOP
)
546 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
547 List
= IntWinListChildren(DesktopWindow
);
548 IntReleaseWindowObject(DesktopWindow
);
551 for (i
= 0; List
[i
]; i
++)
553 if (List
[i
] == Owner
) break;
554 if (List
[i
] != hWnd
) hWndLocalPrev
= List
[i
];
555 if (hWndLocalPrev
== hWndInsertAfter
) break;
557 hWndInsertAfter
= hWndLocalPrev
;
561 else if (Style
& WS_CHILD
)
563 return hWndInsertAfter
;
568 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
569 List
= IntWinListChildren(DesktopWindow
);
570 IntReleaseWindowObject(DesktopWindow
);
574 for (i
= 0; List
[i
]; i
++)
578 if ((NtUserGetWindowLong(List
[i
], GWL_STYLE
, FALSE
) & WS_POPUP
) &&
579 NtUserGetWindow(List
[i
], GW_OWNER
) == hWnd
)
581 WinPosSetWindowPos(List
[i
], hWndInsertAfter
, 0, 0, 0, 0,
582 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
583 hWndInsertAfter
= List
[i
];
589 return hWndInsertAfter
;
592 /***********************************************************************
593 * WinPosInternalMoveWindow
595 * Update WindowRect and ClientRect of Window and all of its children
596 * We keep both WindowRect and ClientRect in screen coordinates internally
599 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
601 PWINDOW_OBJECT Child
;
603 Window
->WindowRect
.left
+= MoveX
;
604 Window
->WindowRect
.right
+= MoveX
;
605 Window
->WindowRect
.top
+= MoveY
;
606 Window
->WindowRect
.bottom
+= MoveY
;
608 Window
->ClientRect
.left
+= MoveX
;
609 Window
->ClientRect
.right
+= MoveX
;
610 Window
->ClientRect
.top
+= MoveY
;
611 Window
->ClientRect
.bottom
+= MoveY
;
613 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
614 Child
= Window
->FirstChild
;
617 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
618 Child
= Child
->NextSibling
;
620 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
624 * WinPosFixupSWPFlags
626 * Fix redundant flags and values in the WINDOWPOS structure.
630 WinPosFixupFlags(WINDOWPOS
*WinPos
, PWINDOW_OBJECT Window
)
632 if (Window
->Style
& WS_VISIBLE
)
634 WinPos
->flags
&= ~SWP_SHOWWINDOW
;
638 WinPos
->flags
&= ~SWP_HIDEWINDOW
;
639 if (!(WinPos
->flags
& SWP_SHOWWINDOW
))
640 WinPos
->flags
|= SWP_NOREDRAW
;
643 WinPos
->cx
= max(WinPos
->cx
, 0);
644 WinPos
->cy
= max(WinPos
->cy
, 0);
646 /* Check for right size */
647 if (Window
->WindowRect
.right
- Window
->WindowRect
.left
== WinPos
->cx
&&
648 Window
->WindowRect
.bottom
- Window
->WindowRect
.top
== WinPos
->cy
)
650 WinPos
->flags
|= SWP_NOSIZE
;
653 /* Check for right position */
654 if (Window
->WindowRect
.left
== WinPos
->x
&&
655 Window
->WindowRect
.top
== WinPos
->y
)
657 WinPos
->flags
|= SWP_NOMOVE
;
660 if (WinPos
->hwnd
== NtUserGetForegroundWindow())
662 WinPos
->flags
|= SWP_NOACTIVATE
; /* Already active */
665 if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
667 /* Bring to the top when activating */
668 if (!(WinPos
->flags
& SWP_NOACTIVATE
))
670 WinPos
->flags
&= ~SWP_NOZORDER
;
671 WinPos
->hwndInsertAfter
= HWND_TOP
;
676 /* Check hwndInsertAfter */
677 if (!(WinPos
->flags
& SWP_NOZORDER
))
679 /* Fix sign extension */
680 if (WinPos
->hwndInsertAfter
== (HWND
)0xffff)
682 WinPos
->hwndInsertAfter
= HWND_TOPMOST
;
684 else if (WinPos
->hwndInsertAfter
== (HWND
)0xfffe)
686 WinPos
->hwndInsertAfter
= HWND_NOTOPMOST
;
689 /* FIXME: TOPMOST not supported yet */
690 if ((WinPos
->hwndInsertAfter
== HWND_TOPMOST
) ||
691 (WinPos
->hwndInsertAfter
== HWND_NOTOPMOST
))
693 WinPos
->hwndInsertAfter
= HWND_TOP
;
696 /* hwndInsertAfter must be a sibling of the window */
697 if ((WinPos
->hwndInsertAfter
!= HWND_TOP
) &&
698 (WinPos
->hwndInsertAfter
!= HWND_BOTTOM
))
700 if (NtUserGetAncestor(WinPos
->hwndInsertAfter
, GA_PARENT
) !=
708 * We don't need to change the Z order of hwnd if it's already
709 * inserted after hwndInsertAfter or when inserting hwnd after
712 if ((WinPos
->hwnd
== WinPos
->hwndInsertAfter
) ||
713 (WinPos
->hwnd
== NtUserGetWindow(WinPos
->hwndInsertAfter
, GW_HWNDNEXT
)))
715 WinPos
->flags
|= SWP_NOZORDER
;
724 /* x and y are always screen relative */
726 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
729 PWINDOW_OBJECT Window
;
733 HRGN VisBefore
= NULL
;
734 HRGN VisAfter
= NULL
;
735 HRGN DirtyRgn
= NULL
;
736 HRGN ExposedRgn
= NULL
;
739 RECT OldWindowRect
, OldClientRect
;
745 /* FIXME: Get current active window from active queue. */
747 Window
= IntGetWindowObject(Wnd
);
750 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
755 * Only allow CSRSS to mess with the desktop window
757 if (Wnd
== IntGetDesktopWindow() &&
758 Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
764 WinPos
.hwndInsertAfter
= WndInsertAfter
;
769 WinPos
.flags
= flags
;
770 if (Window
->Style
& WS_CHILD
)
772 WinPos
.x
-= Window
->Parent
->ClientRect
.left
;
773 WinPos
.y
-= Window
->Parent
->ClientRect
.top
;
776 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
778 /* Fix up the flags. */
779 if (!WinPosFixupFlags(&WinPos
, Window
))
781 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
782 IntReleaseWindowObject(Window
);
786 /* Does the window still exist? */
787 if (!IntIsWindow(WinPos
.hwnd
))
789 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
793 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
795 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) == IntGetDesktopWindow())
797 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
800 /* Compute the visible region before the window position is changed */
801 if ((!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
802 WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
803 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
804 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
806 VisBefore
= VIS_ComputeVisibleRegion(
807 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
809 if (UnsafeIntGetRgnBox(VisBefore
, &TempRect
) == NULLREGION
)
811 NtGdiDeleteObject(VisBefore
);
816 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
818 /* Relink windows. (also take into account shell window in hwndShellWindow) */
819 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwnd
!= NtUserGetShellWindow())
821 PWINDOW_OBJECT ParentWindow
;
822 PWINDOW_OBJECT InsertAfterWindow
;
824 ParentWindow
= Window
->Parent
;
827 if (WinPos
.hwndInsertAfter
== HWND_TOP
)
828 InsertAfterWindow
= NULL
;
829 else if (WinPos
.hwndInsertAfter
== HWND_BOTTOM
)
830 InsertAfterWindow
= ParentWindow
->LastChild
;
832 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
833 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
835 if (InsertAfterWindow
!= Window
)
837 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
838 IntUnlinkWindow(Window
);
839 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
840 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
842 if (InsertAfterWindow
!= NULL
)
843 IntReleaseWindowObject(InsertAfterWindow
);
847 /* FIXME: Reset active DCEs */
849 OldWindowRect
= Window
->WindowRect
;
850 OldClientRect
= Window
->ClientRect
;
852 if (OldClientRect
.bottom
- OldClientRect
.top
==
853 NewClientRect
.bottom
- NewClientRect
.top
)
855 WvrFlags
&= ~WVR_VREDRAW
;
858 if (OldClientRect
.right
- OldClientRect
.left
==
859 NewClientRect
.right
- NewClientRect
.left
)
861 WvrFlags
&= ~WVR_HREDRAW
;
864 /* FIXME: Actually do something with WVR_VALIDRECTS */
866 if (! (WinPos
.flags
& SWP_NOMOVE
)
867 && (NewWindowRect
.left
!= OldWindowRect
.left
868 || NewWindowRect
.top
!= OldWindowRect
.top
))
870 WinPosInternalMoveWindow(Window
,
871 NewWindowRect
.left
- OldWindowRect
.left
,
872 NewWindowRect
.top
- OldWindowRect
.top
);
875 Window
->WindowRect
= NewWindowRect
;
876 Window
->ClientRect
= NewClientRect
;
878 if (!(WinPos
.flags
& SWP_SHOWWINDOW
) && (WinPos
.flags
& SWP_HIDEWINDOW
))
880 /* Clear the update region */
881 IntRedrawWindow(Window
, NULL
, 0, RDW_VALIDATE
| RDW_NOFRAME
|
882 RDW_NOERASE
| RDW_NOINTERNALPAINT
| RDW_ALLCHILDREN
);
883 Window
->Style
&= ~WS_VISIBLE
;
885 else if (WinPos
.flags
& SWP_SHOWWINDOW
)
887 Window
->Style
|= WS_VISIBLE
;
890 /* Determine the new visible region */
891 VisAfter
= VIS_ComputeVisibleRegion(
892 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
894 if (UnsafeIntGetRgnBox(VisAfter
, &TempRect
) == NULLREGION
)
896 NtGdiDeleteObject(VisAfter
);
901 * Determine which pixels can be copied from the old window position
902 * to the new. Those pixels must be visible in both the old and new
903 * position. Also, check the class style to see if the windows of this
904 * class need to be completely repainted on (horizontal/vertical) size
907 if (VisBefore
!= NULL
&& VisAfter
!= NULL
&& !(WinPos
.flags
& SWP_NOCOPYBITS
) &&
908 ((WinPos
.flags
& SWP_NOSIZE
) || !(WvrFlags
& WVR_REDRAW
)))
910 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
911 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
914 * If this is (also) a window resize, the whole nonclient area
915 * needs to be repainted. So we limit the copy to the client area,
916 * 'cause there is no use in copying it (would possibly cause
917 * "flashing" too). However, if the copy region is already empty,
918 * we don't have to crop (can't take anything away from an empty
921 if (!(WinPos
.flags
& (SWP_NOSIZE
| SWP_NOZORDER
)) && RgnType
!= ERROR
&&
922 RgnType
!= NULLREGION
)
924 RECT ORect
= OldClientRect
;
925 RECT NRect
= NewClientRect
;
926 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
927 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
928 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
929 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
932 /* No use in copying bits which are in the update region. */
933 if (Window
->UpdateRegion
!= NULL
)
935 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
939 * Now, get the bounding box of the copy region. If it's empty
940 * there's nothing to copy. Also, it's no use copying bits onto
943 if (UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
) == NULLREGION
)
945 /* Nothing to copy, clean up */
946 NtGdiDeleteObject(CopyRgn
);
949 else if (OldWindowRect
.left
!= NewWindowRect
.left
||
950 OldWindowRect
.top
!= NewWindowRect
.top
)
953 * Small trick here: there is no function to bitblt a region. So
954 * we set the region as the clipping region, take the bounding box
955 * of the region and bitblt that. Since nothing outside the clipping
956 * region is copied, this has the effect of bitblt'ing the region.
958 * Since NtUserGetDCEx takes ownership of the clip region, we need
959 * to create a copy of CopyRgn and pass that. We need CopyRgn later
961 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
962 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
963 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
964 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
966 CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
967 CopyRect
.bottom
- CopyRect
.top
, Dc
,
968 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
969 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
970 NtUserReleaseDC(Wnd
, Dc
);
978 /* We need to redraw what wasn't visible before */
979 if (VisAfter
!= NULL
)
983 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
984 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
985 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
987 NtGdiOffsetRgn(DirtyRgn
,
988 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
989 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
990 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
991 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
993 NtGdiDeleteObject(DirtyRgn
);
997 IntRedrawWindow(Window
, NULL
, 0,
998 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1002 if (CopyRgn
!= NULL
)
1004 NtGdiDeleteObject(CopyRgn
);
1007 /* Expose what was covered before but not covered anymore */
1008 if (VisBefore
!= NULL
)
1010 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1011 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
1012 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
1013 OldWindowRect
.top
- NewWindowRect
.top
);
1014 if (VisAfter
!= NULL
)
1015 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
1017 RgnType
= SIMPLEREGION
;
1019 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
1021 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
,
1024 NtGdiDeleteObject(ExposedRgn
);
1025 NtGdiDeleteObject(VisBefore
);
1028 if (VisAfter
!= NULL
)
1030 NtGdiDeleteObject(VisAfter
);
1033 if (!(WinPos
.flags
& SWP_NOREDRAW
))
1035 IntRedrawWindow(Window
, NULL
, 0, RDW_ALLCHILDREN
| RDW_ERASENOW
);
1038 if (!(WinPos
.flags
& SWP_NOACTIVATE
))
1040 if ((Window
->Style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
1042 IntSendMessage(WinPos
.hwnd
, WM_CHILDACTIVATE
, 0, 0, TRUE
);
1046 IntSetForegroundWindow(Window
);
1050 if ((WinPos
.flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
1051 IntSendWINDOWPOSCHANGEDMessage(WinPos
.hwnd
, &WinPos
);
1053 IntReleaseWindowObject(Window
);
1059 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
1061 *ClientRect
= *WindowRect
;
1062 return(IntSendNCCALCSIZEMessage(Wnd
, FALSE
, ClientRect
, NULL
));
1066 WinPosShowWindow(HWND Wnd
, INT Cmd
)
1069 PWINDOW_OBJECT Window
;
1077 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
1081 if (!NT_SUCCESS(Status
))
1086 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1094 ObmDereferenceObject(Window
);
1097 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1102 case SW_SHOWMINNOACTIVE
:
1103 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1105 case SW_SHOWMINIMIZED
:
1106 Swp
|= SWP_SHOWWINDOW
;
1110 Swp
|= SWP_FRAMECHANGED
| SWP_NOACTIVATE
;
1111 if (!(Window
->Style
& WS_MINIMIZE
))
1113 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1117 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1122 case SW_SHOWMAXIMIZED
:
1124 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1125 if (!(Window
->Style
& WS_MAXIMIZE
))
1127 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1131 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1137 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1140 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1141 /* Don't activate the topmost window. */
1144 case SW_SHOWNOACTIVATE
:
1145 Swp
|= SWP_NOZORDER
;
1148 case SW_SHOWDEFAULT
:
1150 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1151 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1153 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1157 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1162 ShowFlag
= (Cmd
!= SW_HIDE
);
1163 if (ShowFlag
!= WasVisible
)
1165 IntSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0, TRUE
);
1167 * FIXME: Need to check the window wasn't destroyed during the
1172 /* We can't activate a child window */
1173 if ((Window
->Style
& WS_CHILD
) &&
1174 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1176 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1179 WinPosSetWindowPos(Window
->Self
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1180 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1184 /* FIXME: This will cause the window to be activated irrespective
1185 * of whether it is owned by the same thread. Has to be done
1189 if (Window
->Self
== NtUserGetActiveWindow())
1191 WinPosActivateOtherWindow(Window
);
1194 /* Revert focus to parent */
1195 if (Wnd
== IntGetThreadFocusWindow() ||
1196 IntIsChildWindow(Wnd
, IntGetThreadFocusWindow()))
1198 NtUserSetFocus(Window
->Parent
->Self
);
1202 /* FIXME: Check for window destruction. */
1204 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1206 WPARAM wParam
= SIZE_RESTORED
;
1208 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1209 if (Window
->Style
& WS_MAXIMIZE
)
1211 wParam
= SIZE_MAXIMIZED
;
1213 else if (Window
->Style
& WS_MINIMIZE
)
1215 wParam
= SIZE_MINIMIZED
;
1218 IntSendMessage(Wnd
, WM_SIZE
, wParam
,
1219 MAKELONG(Window
->ClientRect
.right
-
1220 Window
->ClientRect
.left
,
1221 Window
->ClientRect
.bottom
-
1222 Window
->ClientRect
.top
), TRUE
);
1223 IntSendMessage(Wnd
, WM_MOVE
, 0,
1224 MAKELONG(Window
->ClientRect
.left
,
1225 Window
->ClientRect
.top
), TRUE
);
1228 /* Activate the window if activation is not requested and the window is not minimized */
1230 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1232 WinPosChangeActiveWindow(Wnd, FALSE);
1236 ObmDereferenceObject(Window
);
1240 BOOL STATIC FASTCALL
1241 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1243 return(Point
.x
>= Window
->WindowRect
.left
&&
1244 Point
.x
< Window
->WindowRect
.right
&&
1245 Point
.y
>= Window
->WindowRect
.top
&&
1246 Point
.y
< Window
->WindowRect
.bottom
);
1249 USHORT STATIC FASTCALL
1250 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1251 PWINDOW_OBJECT
* Window
)
1253 PWINDOW_OBJECT Current
;
1255 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1256 Current
= ScopeWin
->FirstChild
;
1259 if (Current
->Style
& WS_VISIBLE
&&
1260 ((!(Current
->Style
& WS_DISABLED
)) ||
1261 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1262 WinPosPtInWindow(Current
, Point
))
1265 ObmDereferenceObject(*Window
);
1266 ObmReferenceObjectByPointer(Current
, otWindow
);
1270 if (Current
->Style
& WS_DISABLED
)
1272 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1275 if (Current
->Style
& WS_MINIMIZE
)
1277 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1280 if (Point
.x
>= Current
->ClientRect
.left
&&
1281 Point
.x
< Current
->ClientRect
.right
&&
1282 Point
.y
>= Current
->ClientRect
.top
&&
1283 Point
.y
< Current
->ClientRect
.bottom
)
1286 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1287 return(WinPosSearchChildren(Current
, Point
, Window
));
1290 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1293 Current
= Current
->NextSibling
;
1296 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1301 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1302 PWINDOW_OBJECT
* Window
)
1304 HWND DesktopWindowHandle
;
1305 PWINDOW_OBJECT DesktopWindow
;
1306 POINT Point
= WinPoint
;
1313 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1317 if (ScopeWin
->Style
& WS_DISABLED
)
1322 /* Translate the point to the space of the scope window. */
1323 DesktopWindowHandle
= IntGetDesktopWindow();
1324 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1325 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1326 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1327 IntReleaseWindowObject(DesktopWindow
);
1329 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1335 if ((*Window
) == NULL
)
1339 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1341 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1342 MAKELONG(Point
.x
, Point
.y
), FALSE
);
1343 /* FIXME: Check for HTTRANSPARENT here. */