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.63 2003/12/23 17:56:55 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 <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/guicheck.h>
35 #include <include/window.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/winsta.h>
39 #include <include/desktop.h>
40 #include <include/winpos.h>
41 #include <include/rect.h>
42 #include <include/callback.h>
43 #include <include/painting.h>
44 #include <include/dce.h>
45 #include <include/vis.h>
46 #include <include/focus.h>
51 /* GLOBALS *******************************************************************/
53 #define MINMAX_NOSWP (0x00010000)
55 #define SWP_EX_NOCOPY 0x0001
56 #define SWP_EX_PAINTSELF 0x0002
58 #define SWP_AGG_NOGEOMETRYCHANGE \
59 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
60 #define SWP_AGG_NOPOSCHANGE \
61 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
62 #define SWP_AGG_STATUSFLAGS \
63 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
65 /* FUNCTIONS *****************************************************************/
67 #define HAS_DLGFRAME(Style, ExStyle) \
68 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
69 (((Style) & WS_DLGFRAME) && !((Style) & WS_BORDER)))
71 #define HAS_THICKFRAME(Style, ExStyle) \
72 (((Style) & WS_THICKFRAME) && \
73 !((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)
76 NtUserGetClientOrigin(HWND hWnd
, LPPOINT Point
)
78 PWINDOW_OBJECT WindowObject
;
80 WindowObject
= IntGetWindowObject(hWnd
);
81 if (WindowObject
== NULL
)
83 Point
->x
= Point
->y
= 0;
86 Point
->x
= WindowObject
->ClientRect
.left
;
87 Point
->y
= WindowObject
->ClientRect
.top
;
91 /*******************************************************************
92 * WinPosActivateOtherWindow
94 * Activates window other than pWnd.
97 WinPosActivateOtherWindow(PWINDOW_OBJECT Window
)
101 Window
= IntGetParent(Window
);
102 if (!Window
|| IntIsDesktopWindow(Window
))
104 IntSetFocusMessageQueue(NULL
);
107 if (IntSetForegroundWindow(Window
))
115 WinPosFindIconPos(HWND hWnd
, POINT
*Pos
)
121 WinPosNtGdiIconTitle(PWINDOW_OBJECT WindowObject
)
127 WinPosShowIconTitle(PWINDOW_OBJECT WindowObject
, BOOL Show
)
129 PWINDOW_OBJECT IconWindow
;
132 if (WindowObject
->InternalPos
)
134 HWND hWnd
= WindowObject
->InternalPos
->IconTitle
;
138 hWnd
= WinPosNtGdiIconTitle(WindowObject
);
143 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->
147 (PVOID
*)&IconWindow
);
148 if (NT_SUCCESS(Status
))
150 if (!(IconWindow
->Style
& WS_VISIBLE
))
152 IntSendMessage(hWnd
, WM_SHOWWINDOW
, TRUE
, 0, TRUE
);
153 WinPosSetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
|
154 SWP_NOMOVE
| SWP_NOACTIVATE
|
155 SWP_NOZORDER
| SWP_SHOWWINDOW
);
157 ObmDereferenceObject(IconWindow
);
162 WinPosShowWindow(hWnd
, SW_HIDE
);
168 PINTERNALPOS STATIC STDCALL
169 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject
, POINT pt
, PRECT RestoreRect
)
173 if (WindowObject
->InternalPos
== NULL
)
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
->IconTitle
= 0;
182 WindowObject
->InternalPos
->NormalRect
= WindowObject
->WindowRect
;
183 if (HAS_DLGFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
185 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
186 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
191 if (HAS_THICKFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
193 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
194 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
196 if (WindowObject
->Style
& WS_BORDER
)
198 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
199 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
202 WindowObject
->InternalPos
->MaxPos
.x
= -XInc
;
203 WindowObject
->InternalPos
->MaxPos
.y
= -YInc
;
204 WindowObject
->InternalPos
->IconPos
.x
= 0;
205 WindowObject
->InternalPos
->IconPos
.y
= 0;
207 if (WindowObject
->Style
& WS_MINIMIZE
)
209 WindowObject
->InternalPos
->IconPos
= pt
;
211 else if (WindowObject
->Style
& WS_MAXIMIZE
)
213 WindowObject
->InternalPos
->MaxPos
= pt
;
215 else if (RestoreRect
!= NULL
)
217 WindowObject
->InternalPos
->NormalRect
= *RestoreRect
;
219 return(WindowObject
->InternalPos
);
223 WinPosMinMaximize(PWINDOW_OBJECT WindowObject
, UINT ShowFlag
, RECT
* NewPos
)
226 PINTERNALPOS InternalPos
;
229 Size
.x
= WindowObject
->WindowRect
.left
;
230 Size
.y
= WindowObject
->WindowRect
.top
;
231 InternalPos
= WinPosInitInternalPos(WindowObject
, Size
,
232 &WindowObject
->WindowRect
);
236 if (WindowObject
->Style
& WS_MINIMIZE
)
238 if (!IntSendMessage(WindowObject
->Self
, WM_QUERYOPEN
, 0, 0, TRUE
))
240 return(SWP_NOSIZE
| SWP_NOMOVE
);
242 SwpFlags
|= SWP_NOCOPYBITS
;
248 if (WindowObject
->Style
& WS_MAXIMIZE
)
250 WindowObject
->Flags
|= WINDOWOBJECT_RESTOREMAX
;
251 WindowObject
->Style
&= ~WS_MAXIMIZE
;
255 WindowObject
->Flags
&= ~WINDOWOBJECT_RESTOREMAX
;
257 WindowObject
->Style
|= WS_MINIMIZE
;
258 WinPosFindIconPos(WindowObject
, &InternalPos
->IconPos
);
259 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
260 NtUserGetSystemMetrics(SM_CXMINIMIZED
),
261 NtUserGetSystemMetrics(SM_CYMINIMIZED
));
262 SwpFlags
|= SWP_NOCOPYBITS
;
268 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
270 if (WindowObject
->Style
& WS_MINIMIZE
)
272 WinPosShowIconTitle(WindowObject
, FALSE
);
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 WinPosShowIconTitle(WindowObject
, FALSE
);
287 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
289 WinPosGetMinMaxInfo(WindowObject
, &Size
,
290 &InternalPos
->MaxPos
, NULL
, NULL
);
291 WindowObject
->Style
|= WS_MAXIMIZE
;
292 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
293 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
299 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
303 WindowObject
->Style
&= ~WS_MAXIMIZE
;
304 *NewPos
= InternalPos
->NormalRect
;
305 NewPos
->right
-= NewPos
->left
;
306 NewPos
->bottom
-= NewPos
->top
;
314 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
320 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
321 POINT
* MinTrack
, POINT
* MaxTrack
)
326 /* Get default values. */
327 MinMax
.ptMaxSize
.x
= NtUserGetSystemMetrics(SM_CXSCREEN
);
328 MinMax
.ptMaxSize
.y
= NtUserGetSystemMetrics(SM_CYSCREEN
);
329 MinMax
.ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
330 MinMax
.ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
331 MinMax
.ptMaxTrackSize
.x
= NtUserGetSystemMetrics(SM_CXSCREEN
);
332 MinMax
.ptMaxTrackSize
.y
= NtUserGetSystemMetrics(SM_CYSCREEN
);
334 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
336 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
337 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
342 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
344 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
345 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
347 if (Window
->Style
& WS_BORDER
)
349 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
350 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
353 MinMax
.ptMaxSize
.x
+= 2 * XInc
;
354 MinMax
.ptMaxSize
.y
+= 2 * YInc
;
356 if (Window
->InternalPos
!= NULL
)
358 MinMax
.ptMaxPosition
= Window
->InternalPos
->MaxPos
;
362 MinMax
.ptMaxPosition
.x
-= XInc
;
363 MinMax
.ptMaxPosition
.y
-= YInc
;
366 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
, TRUE
);
368 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
369 MinMax
.ptMinTrackSize
.x
);
370 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
371 MinMax
.ptMinTrackSize
.y
);
373 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
374 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
375 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
376 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
378 return 0; //FIXME: what does it return?
383 WinPosChangeActiveWindow(HWND hWnd
, BOOL MouseMsg
)
385 PWINDOW_OBJECT WindowObject
;
387 WindowObject
= IntGetWindowObject(hWnd
);
388 if (WindowObject
== NULL
)
396 MAKELONG(MouseMsg
? WA_CLICKACTIVE
: WA_CLICKACTIVE
,
397 (WindowObject
->Style
& WS_MINIMIZE
) ? 1 : 0),
398 (LPARAM
)IntGetDesktopWindow(), /* FIXME: Previous active window */
401 IntSetForegroundWindow(WindowObject
);
403 IntReleaseWindowObject(WindowObject
);
410 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
411 RECT
* WindowRect
, RECT
* ClientRect
)
415 /* Send WM_NCCALCSIZE message to get new client area */
416 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
418 NCCALCSIZE_PARAMS params
;
419 WINDOWPOS winposCopy
;
421 params
.rgrc
[0] = *WindowRect
;
422 params
.rgrc
[1] = Window
->WindowRect
;
423 params
.rgrc
[2] = Window
->ClientRect
;
424 if (0 != (Window
->Style
& WS_CHILD
))
426 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
427 - Window
->Parent
->ClientRect
.top
);
428 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
429 - Window
->Parent
->ClientRect
.top
);
430 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
431 - Window
->Parent
->ClientRect
.top
);
433 params
.lppos
= &winposCopy
;
434 winposCopy
= *WinPos
;
436 wvrFlags
= IntSendNCCALCSIZEMessage(Window
->Self
, TRUE
, NULL
, ¶ms
);
438 /* If the application send back garbage, ignore it */
439 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
440 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
442 *ClientRect
= params
.rgrc
[0];
443 if (Window
->Style
& WS_CHILD
)
445 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
446 Window
->Parent
->ClientRect
.top
);
450 /* FIXME: WVR_ALIGNxxx */
452 if (ClientRect
->left
!= Window
->ClientRect
.left
||
453 ClientRect
->top
!= Window
->ClientRect
.top
)
455 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
458 if ((ClientRect
->right
- ClientRect
->left
!=
459 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
460 (ClientRect
->bottom
- ClientRect
->top
!=
461 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
463 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
468 if (! (WinPos
->flags
& SWP_NOMOVE
)
469 && (ClientRect
->left
!= Window
->ClientRect
.left
||
470 ClientRect
->top
!= Window
->ClientRect
.top
))
472 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
480 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
487 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
489 IntSendWINDOWPOSCHANGINGMessage(WindowObject
->Self
, WinPos
);
492 *WindowRect
= WindowObject
->WindowRect
;
494 (WindowObject
->Style
& WS_MINIMIZE
) ? WindowObject
->WindowRect
:
495 WindowObject
->ClientRect
;
497 if (!(WinPos
->flags
& SWP_NOSIZE
))
499 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
500 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
503 if (!(WinPos
->flags
& SWP_NOMOVE
))
507 if (0 != (WindowObject
->Style
& WS_CHILD
))
509 X
+= WindowObject
->Parent
->ClientRect
.left
;
510 Y
+= WindowObject
->Parent
->ClientRect
.top
;
512 WindowRect
->left
= X
;
514 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
515 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
516 NtGdiOffsetRect(ClientRect
,
517 X
- WindowObject
->WindowRect
.left
,
518 Y
- WindowObject
->WindowRect
.top
);
521 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
527 * Fix Z order taking into account owned popups -
528 * basically we need to maintain them above the window that owns them
531 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
535 return hWndInsertAfter
;
538 HWND Owner
= NtUserGetWindow(hWnd
, GW_OWNER
);
539 LONG Style
= NtUserGetWindowLong(hWnd
, GWL_STYLE
, FALSE
);
540 PWINDOW_OBJECT DesktopWindow
;
543 if ((Style
& WS_POPUP
) && Owner
)
545 /* Make sure this popup stays above the owner */
546 HWND hWndLocalPrev
= HWND_TOP
;
548 if (hWndInsertAfter
!= HWND_TOP
)
550 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
551 List
= IntWinListChildren(DesktopWindow
);
552 IntReleaseWindowObject(DesktopWindow
);
555 for (i
= 0; List
[i
]; i
++)
557 if (List
[i
] == Owner
) break;
558 if (List
[i
] != hWnd
) hWndLocalPrev
= List
[i
];
559 if (hWndLocalPrev
== hWndInsertAfter
) break;
561 hWndInsertAfter
= hWndLocalPrev
;
565 else if (Style
& WS_CHILD
)
567 return hWndInsertAfter
;
572 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
573 List
= IntWinListChildren(DesktopWindow
);
574 IntReleaseWindowObject(DesktopWindow
);
578 for (i
= 0; List
[i
]; i
++)
582 if ((NtUserGetWindowLong(List
[i
], GWL_STYLE
, FALSE
) & WS_POPUP
) &&
583 NtUserGetWindow(List
[i
], GW_OWNER
) == hWnd
)
585 WinPosSetWindowPos(List
[i
], hWndInsertAfter
, 0, 0, 0, 0,
586 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
587 hWndInsertAfter
= List
[i
];
593 return hWndInsertAfter
;
596 /***********************************************************************
597 * WinPosInternalMoveWindow
599 * Update WindowRect and ClientRect of Window and all of its children
600 * We keep both WindowRect and ClientRect in screen coordinates internally
603 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
605 PWINDOW_OBJECT Child
;
607 Window
->WindowRect
.left
+= MoveX
;
608 Window
->WindowRect
.right
+= MoveX
;
609 Window
->WindowRect
.top
+= MoveY
;
610 Window
->WindowRect
.bottom
+= MoveY
;
612 Window
->ClientRect
.left
+= MoveX
;
613 Window
->ClientRect
.right
+= MoveX
;
614 Window
->ClientRect
.top
+= MoveY
;
615 Window
->ClientRect
.bottom
+= MoveY
;
617 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
618 Child
= Window
->FirstChild
;
621 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
622 Child
= Child
->NextSibling
;
624 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
628 * WinPosFixupSWPFlags
630 * Fix redundant flags and values in the WINDOWPOS structure.
634 WinPosFixupFlags(WINDOWPOS
*WinPos
, PWINDOW_OBJECT Window
)
636 if (Window
->Style
& WS_VISIBLE
)
638 WinPos
->flags
&= ~SWP_SHOWWINDOW
;
642 WinPos
->flags
&= ~SWP_HIDEWINDOW
;
643 if (!(WinPos
->flags
& SWP_SHOWWINDOW
))
644 WinPos
->flags
|= SWP_NOREDRAW
;
647 WinPos
->cx
= max(WinPos
->cx
, 0);
648 WinPos
->cy
= max(WinPos
->cy
, 0);
650 /* Check for right size */
651 if (Window
->WindowRect
.right
- Window
->WindowRect
.left
== WinPos
->cx
&&
652 Window
->WindowRect
.bottom
- Window
->WindowRect
.top
== WinPos
->cy
)
654 WinPos
->flags
|= SWP_NOSIZE
;
657 /* Check for right position */
658 if (Window
->WindowRect
.left
== WinPos
->x
&&
659 Window
->WindowRect
.top
== WinPos
->y
)
661 WinPos
->flags
|= SWP_NOMOVE
;
664 if (WinPos
->hwnd
== NtUserGetForegroundWindow())
666 WinPos
->flags
|= SWP_NOACTIVATE
; /* Already active */
669 if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
671 /* Bring to the top when activating */
672 if (!(WinPos
->flags
& SWP_NOACTIVATE
))
674 WinPos
->flags
&= ~SWP_NOZORDER
;
675 WinPos
->hwndInsertAfter
= HWND_TOP
;
680 /* Check hwndInsertAfter */
681 if (!(WinPos
->flags
& SWP_NOZORDER
))
683 /* Fix sign extension */
684 if (WinPos
->hwndInsertAfter
== (HWND
)0xffff)
686 WinPos
->hwndInsertAfter
= HWND_TOPMOST
;
688 else if (WinPos
->hwndInsertAfter
== (HWND
)0xfffe)
690 WinPos
->hwndInsertAfter
= HWND_NOTOPMOST
;
693 /* FIXME: TOPMOST not supported yet */
694 if ((WinPos
->hwndInsertAfter
== HWND_TOPMOST
) ||
695 (WinPos
->hwndInsertAfter
== HWND_NOTOPMOST
))
697 WinPos
->hwndInsertAfter
= HWND_TOP
;
700 /* hwndInsertAfter must be a sibling of the window */
701 if ((WinPos
->hwndInsertAfter
!= HWND_TOP
) &&
702 (WinPos
->hwndInsertAfter
!= HWND_BOTTOM
))
704 if (NtUserGetAncestor(WinPos
->hwndInsertAfter
, GA_PARENT
) !=
712 * We don't need to change the Z order of hwnd if it's already
713 * inserted after hwndInsertAfter or when inserting hwnd after
716 if ((WinPos
->hwnd
== WinPos
->hwndInsertAfter
) ||
717 (WinPos
->hwnd
== NtUserGetWindow(WinPos
->hwndInsertAfter
, GW_HWNDNEXT
)))
719 WinPos
->flags
|= SWP_NOZORDER
;
728 /* x and y are always screen relative */
730 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
733 PWINDOW_OBJECT Window
;
737 HRGN VisBefore
= NULL
;
738 HRGN VisAfter
= NULL
;
739 HRGN DirtyRgn
= NULL
;
740 HRGN ExposedRgn
= NULL
;
743 RECT OldWindowRect
, OldClientRect
;
749 /* FIXME: Get current active window from active queue. */
751 Window
= IntGetWindowObject(Wnd
);
754 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
759 * Only allow CSRSS to mess with the desktop window
761 if (Wnd
== IntGetDesktopWindow() &&
762 Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
768 WinPos
.hwndInsertAfter
= WndInsertAfter
;
773 WinPos
.flags
= flags
;
774 if (Window
->Style
& WS_CHILD
)
776 WinPos
.x
-= Window
->Parent
->ClientRect
.left
;
777 WinPos
.y
-= Window
->Parent
->ClientRect
.top
;
780 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
782 /* Fix up the flags. */
783 if (!WinPosFixupFlags(&WinPos
, Window
))
785 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
786 IntReleaseWindowObject(Window
);
790 /* Does the window still exist? */
791 if (!IntIsWindow(WinPos
.hwnd
))
793 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
797 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
799 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) == IntGetDesktopWindow())
801 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
804 /* Compute the visible region before the window position is changed */
805 if ((!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
806 WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
807 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
808 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
810 VisBefore
= VIS_ComputeVisibleRegion(
811 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
813 if (UnsafeIntGetRgnBox(VisBefore
, &TempRect
) == NULLREGION
)
815 NtGdiDeleteObject(VisBefore
);
820 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
822 /* Relink windows. (also take into account shell window in hwndShellWindow) */
823 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwnd
!= NtUserGetShellWindow())
825 PWINDOW_OBJECT ParentWindow
;
826 PWINDOW_OBJECT InsertAfterWindow
;
828 ParentWindow
= Window
->Parent
;
831 if (WinPos
.hwndInsertAfter
== HWND_TOP
)
832 InsertAfterWindow
= NULL
;
833 else if (WinPos
.hwndInsertAfter
== HWND_BOTTOM
)
834 InsertAfterWindow
= ParentWindow
->LastChild
;
836 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
837 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
839 if (InsertAfterWindow
!= Window
)
841 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
842 IntUnlinkWindow(Window
);
843 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
844 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
846 if (InsertAfterWindow
!= NULL
)
847 IntReleaseWindowObject(InsertAfterWindow
);
851 /* FIXME: Reset active DCEs */
853 OldWindowRect
= Window
->WindowRect
;
854 OldClientRect
= Window
->ClientRect
;
856 if (OldClientRect
.bottom
- OldClientRect
.top
==
857 NewClientRect
.bottom
- NewClientRect
.top
)
859 WvrFlags
&= ~WVR_VREDRAW
;
862 if (OldClientRect
.right
- OldClientRect
.left
==
863 NewClientRect
.right
- NewClientRect
.left
)
865 WvrFlags
&= ~WVR_HREDRAW
;
868 /* FIXME: Actually do something with WVR_VALIDRECTS */
870 if (! (WinPos
.flags
& SWP_NOMOVE
)
871 && (NewWindowRect
.left
!= OldWindowRect
.left
872 || NewWindowRect
.top
!= OldWindowRect
.top
))
874 WinPosInternalMoveWindow(Window
,
875 NewWindowRect
.left
- OldWindowRect
.left
,
876 NewWindowRect
.top
- OldWindowRect
.top
);
879 Window
->WindowRect
= NewWindowRect
;
880 Window
->ClientRect
= NewClientRect
;
882 if (!(WinPos
.flags
& SWP_SHOWWINDOW
) && (WinPos
.flags
& SWP_HIDEWINDOW
))
884 /* Clear the update region */
885 IntRedrawWindow(Window
, NULL
, 0, RDW_VALIDATE
| RDW_NOFRAME
|
886 RDW_NOERASE
| RDW_NOINTERNALPAINT
| RDW_ALLCHILDREN
);
887 Window
->Style
&= ~WS_VISIBLE
;
889 else if (WinPos
.flags
& SWP_SHOWWINDOW
)
891 Window
->Style
|= WS_VISIBLE
;
894 /* Determine the new visible region */
895 VisAfter
= VIS_ComputeVisibleRegion(
896 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
898 if (UnsafeIntGetRgnBox(VisAfter
, &TempRect
) == NULLREGION
)
900 NtGdiDeleteObject(VisAfter
);
905 * Determine which pixels can be copied from the old window position
906 * to the new. Those pixels must be visible in both the old and new
907 * position. Also, check the class style to see if the windows of this
908 * class need to be completely repainted on (horizontal/vertical) size
911 if (VisBefore
!= NULL
&& VisAfter
!= NULL
&& !(WinPos
.flags
& SWP_NOCOPYBITS
) &&
912 ((WinPos
.flags
& SWP_NOSIZE
) || !(WvrFlags
& WVR_REDRAW
)))
914 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
915 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
918 * If this is (also) a window resize, the whole nonclient area
919 * needs to be repainted. So we limit the copy to the client area,
920 * 'cause there is no use in copying it (would possibly cause
921 * "flashing" too). However, if the copy region is already empty,
922 * we don't have to crop (can't take anything away from an empty
925 if (!(WinPos
.flags
& (SWP_NOSIZE
| SWP_NOZORDER
)) && RgnType
!= ERROR
&&
926 RgnType
!= NULLREGION
)
928 RECT ORect
= OldClientRect
;
929 RECT NRect
= NewClientRect
;
930 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
931 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
932 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
933 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
936 /* No use in copying bits which are in the update region. */
937 if (Window
->UpdateRegion
!= NULL
)
939 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
943 * Now, get the bounding box of the copy region. If it's empty
944 * there's nothing to copy. Also, it's no use copying bits onto
947 if (UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
) == NULLREGION
)
949 /* Nothing to copy, clean up */
950 NtGdiDeleteObject(CopyRgn
);
953 else if (OldWindowRect
.left
!= NewWindowRect
.left
||
954 OldWindowRect
.top
!= NewWindowRect
.top
)
957 * Small trick here: there is no function to bitblt a region. So
958 * we set the region as the clipping region, take the bounding box
959 * of the region and bitblt that. Since nothing outside the clipping
960 * region is copied, this has the effect of bitblt'ing the region.
962 * Since NtUserGetDCEx takes ownership of the clip region, we need
963 * to create a copy of CopyRgn and pass that. We need CopyRgn later
965 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
966 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
967 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
968 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
970 CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
971 CopyRect
.bottom
- CopyRect
.top
, Dc
,
972 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
973 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
974 NtUserReleaseDC(Wnd
, Dc
);
982 /* We need to redraw what wasn't visible before */
983 if (VisAfter
!= NULL
)
987 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
988 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
989 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
991 NtGdiOffsetRgn(DirtyRgn
,
992 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
993 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
994 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
995 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
997 NtGdiDeleteObject(DirtyRgn
);
1001 IntRedrawWindow(Window
, NULL
, 0,
1002 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
1006 if (CopyRgn
!= NULL
)
1008 NtGdiDeleteObject(CopyRgn
);
1011 /* Expose what was covered before but not covered anymore */
1012 if (VisBefore
!= NULL
)
1014 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1015 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
1016 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
1017 OldWindowRect
.top
- NewWindowRect
.top
);
1018 if (VisAfter
!= NULL
)
1019 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
1021 RgnType
= SIMPLEREGION
;
1023 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
1025 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
,
1028 NtGdiDeleteObject(ExposedRgn
);
1029 NtGdiDeleteObject(VisBefore
);
1032 if (VisAfter
!= NULL
)
1034 NtGdiDeleteObject(VisAfter
);
1037 if (!(WinPos
.flags
& SWP_NOREDRAW
))
1039 IntRedrawWindow(Window
, NULL
, 0, RDW_ALLCHILDREN
| RDW_ERASENOW
);
1042 if (!(WinPos
.flags
& SWP_NOACTIVATE
))
1044 if ((Window
->Style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
1046 IntSendMessage(WinPos
.hwnd
, WM_CHILDACTIVATE
, 0, 0, TRUE
);
1050 IntSetForegroundWindow(Window
);
1054 if ((WinPos
.flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
1055 IntSendWINDOWPOSCHANGEDMessage(WinPos
.hwnd
, &WinPos
);
1057 IntReleaseWindowObject(Window
);
1063 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
1065 *ClientRect
= *WindowRect
;
1066 return(IntSendNCCALCSIZEMessage(Wnd
, FALSE
, ClientRect
, NULL
));
1070 WinPosShowWindow(HWND Wnd
, INT Cmd
)
1073 PWINDOW_OBJECT Window
;
1081 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
1085 if (!NT_SUCCESS(Status
))
1090 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1098 ObmDereferenceObject(Window
);
1101 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1106 case SW_SHOWMINNOACTIVE
:
1107 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1109 case SW_SHOWMINIMIZED
:
1110 Swp
|= SWP_SHOWWINDOW
;
1114 Swp
|= SWP_FRAMECHANGED
;
1115 if (!(Window
->Style
& WS_MINIMIZE
))
1117 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1121 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1126 case SW_SHOWMAXIMIZED
:
1128 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1129 if (!(Window
->Style
& WS_MAXIMIZE
))
1131 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1135 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1141 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1144 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1145 /* Don't activate the topmost window. */
1148 case SW_SHOWNOACTIVATE
:
1149 Swp
|= SWP_NOZORDER
;
1152 case SW_SHOWDEFAULT
:
1154 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1155 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1157 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1161 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1166 ShowFlag
= (Cmd
!= SW_HIDE
);
1167 if (ShowFlag
!= WasVisible
)
1169 IntSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0, TRUE
);
1171 * FIXME: Need to check the window wasn't destroyed during the
1176 /* We can't activate a child window */
1177 if ((Window
->Style
& WS_CHILD
) &&
1178 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1180 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1183 WinPosSetWindowPos(Window
->Self
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1184 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1188 /* FIXME: This will cause the window to be activated irrespective
1189 * of whether it is owned by the same thread. Has to be done
1193 if (Window
->Self
== NtUserGetActiveWindow())
1195 WinPosActivateOtherWindow(Window
);
1198 /* Revert focus to parent */
1199 if (Wnd
== IntGetThreadFocusWindow() ||
1200 IntIsChildWindow(Wnd
, IntGetThreadFocusWindow()))
1202 NtUserSetFocus(Window
->Parent
->Self
);
1206 /* FIXME: Check for window destruction. */
1207 /* Show title for minimized windows. */
1208 if (Window
->Style
& WS_MINIMIZE
)
1210 WinPosShowIconTitle(Window
, TRUE
);
1213 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1215 WPARAM wParam
= SIZE_RESTORED
;
1217 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1218 if (Window
->Style
& WS_MAXIMIZE
)
1220 wParam
= SIZE_MAXIMIZED
;
1222 else if (Window
->Style
& WS_MINIMIZE
)
1224 wParam
= SIZE_MINIMIZED
;
1227 IntSendMessage(Wnd
, WM_SIZE
, wParam
,
1228 MAKELONG(Window
->ClientRect
.right
-
1229 Window
->ClientRect
.left
,
1230 Window
->ClientRect
.bottom
-
1231 Window
->ClientRect
.top
), TRUE
);
1232 IntSendMessage(Wnd
, WM_MOVE
, 0,
1233 MAKELONG(Window
->ClientRect
.left
,
1234 Window
->ClientRect
.top
), TRUE
);
1237 /* Activate the window if activation is not requested and the window is not minimized */
1239 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1241 WinPosChangeActiveWindow(Wnd, FALSE);
1245 ObmDereferenceObject(Window
);
1249 BOOL STATIC FASTCALL
1250 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1252 return(Point
.x
>= Window
->WindowRect
.left
&&
1253 Point
.x
< Window
->WindowRect
.right
&&
1254 Point
.y
>= Window
->WindowRect
.top
&&
1255 Point
.y
< Window
->WindowRect
.bottom
);
1258 USHORT STATIC STDCALL
1259 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1260 PWINDOW_OBJECT
* Window
)
1262 PWINDOW_OBJECT Current
;
1264 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1265 Current
= ScopeWin
->FirstChild
;
1268 if (Current
->Style
& WS_VISIBLE
&&
1269 ((!(Current
->Style
& WS_DISABLED
)) ||
1270 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1271 WinPosPtInWindow(Current
, Point
))
1274 ObmDereferenceObject(*Window
);
1275 ObmReferenceObjectByPointer(Current
, otWindow
);
1279 if (Current
->Style
& WS_DISABLED
)
1281 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1284 if (Current
->Style
& WS_MINIMIZE
)
1286 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1289 if (Point
.x
>= Current
->ClientRect
.left
&&
1290 Point
.x
< Current
->ClientRect
.right
&&
1291 Point
.y
>= Current
->ClientRect
.top
&&
1292 Point
.y
< Current
->ClientRect
.bottom
)
1295 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1296 return(WinPosSearchChildren(Current
, Point
, Window
));
1299 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1302 Current
= Current
->NextSibling
;
1305 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1310 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1311 PWINDOW_OBJECT
* Window
)
1313 HWND DesktopWindowHandle
;
1314 PWINDOW_OBJECT DesktopWindow
;
1315 POINT Point
= WinPoint
;
1322 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1326 if (ScopeWin
->Style
& WS_DISABLED
)
1331 /* Translate the point to the space of the scope window. */
1332 DesktopWindowHandle
= IntGetDesktopWindow();
1333 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1334 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1335 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1336 IntReleaseWindowObject(DesktopWindow
);
1338 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1344 if ((*Window
) == NULL
)
1348 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1350 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1351 MAKELONG(Point
.x
, Point
.y
), FALSE
);
1352 /* FIXME: Check for HTTRANSPARENT here. */