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.76 2003/12/28 10:56:20 gvg Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH NtGdid
29 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <internal/safe.h>
33 #include <win32k/win32k.h>
34 #include <include/object.h>
35 #include <include/guicheck.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/desktop.h>
41 #include <include/winpos.h>
42 #include <include/rect.h>
43 #include <include/callback.h>
44 #include <include/painting.h>
45 #include <include/dce.h>
46 #include <include/vis.h>
47 #include <include/focus.h>
52 /* GLOBALS *******************************************************************/
54 #define MINMAX_NOSWP (0x00010000)
56 #define SWP_EX_NOCOPY 0x0001
57 #define SWP_EX_PAINTSELF 0x0002
59 #define SWP_AGG_NOGEOMETRYCHANGE \
60 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
61 #define SWP_AGG_NOPOSCHANGE \
62 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
63 #define SWP_AGG_STATUSFLAGS \
64 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
66 /* FUNCTIONS *****************************************************************/
68 #define HAS_DLGFRAME(Style, ExStyle) \
69 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
70 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
72 #define HAS_THICKFRAME(Style, ExStyle) \
73 (((Style) & WS_THICKFRAME) && \
74 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
76 #define HAS_THINFRAME(Style, ExStyle) \
77 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
80 IntGetClientOrigin(HWND hWnd
, LPPOINT Point
)
82 PWINDOW_OBJECT WindowObject
;
84 WindowObject
= IntGetWindowObject(hWnd
);
85 if (WindowObject
== NULL
)
87 Point
->x
= Point
->y
= 0;
90 Point
->x
= WindowObject
->ClientRect
.left
;
91 Point
->y
= WindowObject
->ClientRect
.top
;
93 IntReleaseWindowObject(WindowObject
);
98 NtUserGetClientOrigin(HWND hWnd
, LPPOINT Point
)
104 Ret
= IntGetClientOrigin(hWnd
, &pt
);
106 Status
= MmCopyToCaller(Point
, &pt
, sizeof(POINT
));
107 if(!NT_SUCCESS(Status
))
109 SetLastNtError(Status
);
116 /*******************************************************************
117 * WinPosActivateOtherWindow
119 * Activates window other than pWnd.
122 WinPosActivateOtherWindow(PWINDOW_OBJECT Window
)
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
) && !(WindowObject
->Style
& WS_MINIMIZE
))
169 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
170 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
175 if (HAS_THICKFRAME(WindowObject
->Style
, WindowObject
->ExStyle
)&& !(WindowObject
->Style
& WS_MINIMIZE
))
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))
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 IntRedrawWindow(WindowObject
, NULL
, 0, RDW_VALIDATE
| RDW_NOERASE
|
242 RDW_NOINTERNALPAINT
);
243 WindowObject
->Style
|= WS_MINIMIZE
;
244 WinPosFindIconPos(WindowObject
, &InternalPos
->IconPos
);
245 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
246 NtUserGetSystemMetrics(SM_CXMINIMIZED
),
247 NtUserGetSystemMetrics(SM_CYMINIMIZED
));
248 SwpFlags
|= SWP_NOCOPYBITS
;
254 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
256 if (WindowObject
->Style
& WS_MINIMIZE
)
258 WindowObject
->Style
&= ~WS_MINIMIZE
;
260 WindowObject
->Style
|= WS_MAXIMIZE
;
261 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
,
268 if (WindowObject
->Style
& WS_MINIMIZE
)
270 WindowObject
->Style
&= ~WS_MINIMIZE
;
271 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
273 WinPosGetMinMaxInfo(WindowObject
, &Size
,
274 &InternalPos
->MaxPos
, NULL
, NULL
);
275 WindowObject
->Style
|= WS_MAXIMIZE
;
276 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
277 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
282 *NewPos
= InternalPos
->NormalRect
;
283 NewPos
->right
-= NewPos
->left
;
284 NewPos
->bottom
-= NewPos
->top
;
290 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
294 WindowObject
->Style
&= ~WS_MAXIMIZE
;
295 *NewPos
= InternalPos
->NormalRect
;
296 NewPos
->right
-= NewPos
->left
;
297 NewPos
->bottom
-= NewPos
->top
;
305 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
311 WinPosFillMinMaxInfoStruct(PWINDOW_OBJECT Window
, MINMAXINFO
*Info
)
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 Info
->ptMaxSize
.x
= WorkArea
.right
- WorkArea
.left
;
324 Info
->ptMaxSize
.y
= WorkArea
.bottom
- WorkArea
.top
;
325 Info
->ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
326 Info
->ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
327 Info
->ptMaxTrackSize
.x
= Info
->ptMaxSize
.x
;
328 Info
->ptMaxTrackSize
.y
= Info
->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 Info
->ptMaxSize
.x
+= 2 * XInc
;
350 Info
->ptMaxSize
.y
+= 2 * YInc
;
352 if (Window
->InternalPos
!= NULL
)
354 Info
->ptMaxPosition
= Window
->InternalPos
->MaxPos
;
358 Info
->ptMaxPosition
.x
-= WorkArea
.left
+ XInc
;
359 Info
->ptMaxPosition
.y
-= WorkArea
.top
+ YInc
;
364 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
365 POINT
* MinTrack
, POINT
* MaxTrack
)
369 WinPosFillMinMaxInfoStruct(Window
, &MinMax
);
371 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
);
373 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
374 MinMax
.ptMinTrackSize
.x
);
375 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
376 MinMax
.ptMinTrackSize
.y
);
378 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
379 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
380 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
381 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
383 return 0; //FIXME: what does it return?
387 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
388 RECT
* WindowRect
, RECT
* ClientRect
)
392 /* Send WM_NCCALCSIZE message to get new client area */
393 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
395 NCCALCSIZE_PARAMS params
;
396 WINDOWPOS winposCopy
;
398 params
.rgrc
[0] = *WindowRect
;
399 params
.rgrc
[1] = Window
->WindowRect
;
400 params
.rgrc
[2] = Window
->ClientRect
;
401 if (0 != (Window
->Style
& WS_CHILD
))
403 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
404 - Window
->Parent
->ClientRect
.top
);
405 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
406 - Window
->Parent
->ClientRect
.top
);
407 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
408 - Window
->Parent
->ClientRect
.top
);
410 params
.lppos
= &winposCopy
;
411 winposCopy
= *WinPos
;
413 wvrFlags
= IntSendMessage(Window
->Self
, WM_NCCALCSIZE
, TRUE
, (LPARAM
) ¶ms
);
415 /* If the application send back garbage, ignore it */
416 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
417 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
419 *ClientRect
= params
.rgrc
[0];
420 if (Window
->Style
& WS_CHILD
)
422 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
423 Window
->Parent
->ClientRect
.top
);
427 /* FIXME: WVR_ALIGNxxx */
429 if (ClientRect
->left
!= Window
->ClientRect
.left
||
430 ClientRect
->top
!= Window
->ClientRect
.top
)
432 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
435 if ((ClientRect
->right
- ClientRect
->left
!=
436 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
437 (ClientRect
->bottom
- ClientRect
->top
!=
438 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
440 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
445 if (! (WinPos
->flags
& SWP_NOMOVE
)
446 && (ClientRect
->left
!= Window
->ClientRect
.left
||
447 ClientRect
->top
!= Window
->ClientRect
.top
))
449 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
457 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
464 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
466 IntSendMessage(WindowObject
->Self
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
) WinPos
);
469 *WindowRect
= WindowObject
->WindowRect
;
471 (WindowObject
->Style
& WS_MINIMIZE
) ? WindowObject
->WindowRect
:
472 WindowObject
->ClientRect
;
474 if (!(WinPos
->flags
& SWP_NOSIZE
))
476 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
477 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
480 if (!(WinPos
->flags
& SWP_NOMOVE
))
484 if (0 != (WindowObject
->Style
& WS_CHILD
))
486 X
+= WindowObject
->Parent
->ClientRect
.left
;
487 Y
+= WindowObject
->Parent
->ClientRect
.top
;
489 WindowRect
->left
= X
;
491 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
492 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
493 NtGdiOffsetRect(ClientRect
,
494 X
- WindowObject
->WindowRect
.left
,
495 Y
- WindowObject
->WindowRect
.top
);
498 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
504 * Fix Z order taking into account owned popups -
505 * basically we need to maintain them above the window that owns them
508 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
511 HWND Owner
= NtUserGetWindow(hWnd
, GW_OWNER
);
512 LONG Style
= NtUserGetWindowLong(hWnd
, GWL_STYLE
, FALSE
);
513 PWINDOW_OBJECT DesktopWindow
;
516 if ((Style
& WS_POPUP
) && Owner
)
518 /* Make sure this popup stays above the owner */
519 HWND hWndLocalPrev
= HWND_TOP
;
521 if (hWndInsertAfter
!= HWND_TOP
)
523 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
524 List
= IntWinListChildren(DesktopWindow
);
525 IntReleaseWindowObject(DesktopWindow
);
528 for (i
= 0; List
[i
]; i
++)
530 if (List
[i
] == Owner
) break;
531 if (List
[i
] != hWnd
) hWndLocalPrev
= List
[i
];
532 if (hWndLocalPrev
== hWndInsertAfter
) break;
534 hWndInsertAfter
= hWndLocalPrev
;
538 else if (Style
& WS_CHILD
)
540 return hWndInsertAfter
;
545 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
546 List
= IntWinListChildren(DesktopWindow
);
547 IntReleaseWindowObject(DesktopWindow
);
551 for (i
= 0; List
[i
]; i
++)
555 if ((NtUserGetWindowLong(List
[i
], GWL_STYLE
, FALSE
) & WS_POPUP
) &&
556 NtUserGetWindow(List
[i
], GW_OWNER
) == hWnd
)
558 WinPosSetWindowPos(List
[i
], hWndInsertAfter
, 0, 0, 0, 0,
559 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
560 hWndInsertAfter
= List
[i
];
566 return hWndInsertAfter
;
569 /***********************************************************************
570 * WinPosInternalMoveWindow
572 * Update WindowRect and ClientRect of Window and all of its children
573 * We keep both WindowRect and ClientRect in screen coordinates internally
576 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
578 PWINDOW_OBJECT Child
;
580 Window
->WindowRect
.left
+= MoveX
;
581 Window
->WindowRect
.right
+= MoveX
;
582 Window
->WindowRect
.top
+= MoveY
;
583 Window
->WindowRect
.bottom
+= MoveY
;
585 Window
->ClientRect
.left
+= MoveX
;
586 Window
->ClientRect
.right
+= MoveX
;
587 Window
->ClientRect
.top
+= MoveY
;
588 Window
->ClientRect
.bottom
+= MoveY
;
590 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
591 Child
= Window
->FirstChild
;
594 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
595 Child
= Child
->NextSibling
;
597 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
601 * WinPosFixupSWPFlags
603 * Fix redundant flags and values in the WINDOWPOS structure.
607 WinPosFixupFlags(WINDOWPOS
*WinPos
, PWINDOW_OBJECT Window
)
609 if (Window
->Style
& WS_VISIBLE
)
611 WinPos
->flags
&= ~SWP_SHOWWINDOW
;
615 WinPos
->flags
&= ~SWP_HIDEWINDOW
;
616 if (!(WinPos
->flags
& SWP_SHOWWINDOW
))
617 WinPos
->flags
|= SWP_NOREDRAW
;
620 WinPos
->cx
= max(WinPos
->cx
, 0);
621 WinPos
->cy
= max(WinPos
->cy
, 0);
623 /* Check for right size */
624 if (Window
->WindowRect
.right
- Window
->WindowRect
.left
== WinPos
->cx
&&
625 Window
->WindowRect
.bottom
- Window
->WindowRect
.top
== WinPos
->cy
)
627 WinPos
->flags
|= SWP_NOSIZE
;
630 /* Check for right position */
631 if (Window
->WindowRect
.left
== WinPos
->x
&&
632 Window
->WindowRect
.top
== WinPos
->y
)
634 WinPos
->flags
|= SWP_NOMOVE
;
637 if (WinPos
->hwnd
== NtUserGetForegroundWindow())
639 WinPos
->flags
|= SWP_NOACTIVATE
; /* Already active */
642 if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
644 /* Bring to the top when activating */
645 if (!(WinPos
->flags
& SWP_NOACTIVATE
))
647 WinPos
->flags
&= ~SWP_NOZORDER
;
648 WinPos
->hwndInsertAfter
= HWND_TOP
;
653 /* Check hwndInsertAfter */
654 if (!(WinPos
->flags
& SWP_NOZORDER
))
656 /* Fix sign extension */
657 if (WinPos
->hwndInsertAfter
== (HWND
)0xffff)
659 WinPos
->hwndInsertAfter
= HWND_TOPMOST
;
661 else if (WinPos
->hwndInsertAfter
== (HWND
)0xfffe)
663 WinPos
->hwndInsertAfter
= HWND_NOTOPMOST
;
666 /* FIXME: TOPMOST not supported yet */
667 if ((WinPos
->hwndInsertAfter
== HWND_TOPMOST
) ||
668 (WinPos
->hwndInsertAfter
== HWND_NOTOPMOST
))
670 WinPos
->hwndInsertAfter
= HWND_TOP
;
673 /* hwndInsertAfter must be a sibling of the window */
674 if ((WinPos
->hwndInsertAfter
!= HWND_TOP
) &&
675 (WinPos
->hwndInsertAfter
!= HWND_BOTTOM
))
677 if (NtUserGetAncestor(WinPos
->hwndInsertAfter
, GA_PARENT
) !=
685 * We don't need to change the Z order of hwnd if it's already
686 * inserted after hwndInsertAfter or when inserting hwnd after
689 if ((WinPos
->hwnd
== WinPos
->hwndInsertAfter
) ||
690 (WinPos
->hwnd
== NtUserGetWindow(WinPos
->hwndInsertAfter
, GW_HWNDNEXT
)))
692 WinPos
->flags
|= SWP_NOZORDER
;
701 /* x and y are always screen relative */
703 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
706 PWINDOW_OBJECT Window
;
710 HRGN VisBefore
= NULL
;
711 HRGN VisAfter
= NULL
;
712 HRGN DirtyRgn
= NULL
;
713 HRGN ExposedRgn
= NULL
;
716 RECT OldWindowRect
, OldClientRect
;
722 /* FIXME: Get current active window from active queue. */
724 Window
= IntGetWindowObject(Wnd
);
727 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
732 * Only allow CSRSS to mess with the desktop window
734 if (Wnd
== IntGetDesktopWindow() &&
735 Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
741 WinPos
.hwndInsertAfter
= WndInsertAfter
;
746 WinPos
.flags
= flags
;
747 if (Window
->Style
& WS_CHILD
)
749 WinPos
.x
-= Window
->Parent
->ClientRect
.left
;
750 WinPos
.y
-= Window
->Parent
->ClientRect
.top
;
753 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
755 /* Fix up the flags. */
756 if (!WinPosFixupFlags(&WinPos
, Window
))
758 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
759 IntReleaseWindowObject(Window
);
763 /* Does the window still exist? */
764 if (!IntIsWindow(WinPos
.hwnd
))
766 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
770 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
772 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) == IntGetDesktopWindow())
774 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
777 /* Compute the visible region before the window position is changed */
778 if ((!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
779 WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
780 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
781 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
783 VisBefore
= VIS_ComputeVisibleRegion(
784 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
786 if (UnsafeIntGetRgnBox(VisBefore
, &TempRect
) == NULLREGION
)
788 NtGdiDeleteObject(VisBefore
);
793 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
795 /* Relink windows. (also take into account shell window in hwndShellWindow) */
796 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwnd
!= NtUserGetShellWindow())
798 PWINDOW_OBJECT ParentWindow
;
799 PWINDOW_OBJECT InsertAfterWindow
;
801 ParentWindow
= Window
->Parent
;
804 if (WinPos
.hwndInsertAfter
== HWND_TOP
)
805 InsertAfterWindow
= NULL
;
806 else if (WinPos
.hwndInsertAfter
== HWND_BOTTOM
)
807 InsertAfterWindow
= ParentWindow
->LastChild
;
809 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
810 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
812 if (InsertAfterWindow
!= Window
)
814 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
815 IntUnlinkWindow(Window
);
816 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
817 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
819 if (InsertAfterWindow
!= NULL
)
820 IntReleaseWindowObject(InsertAfterWindow
);
824 /* FIXME: Reset active DCEs */
826 OldWindowRect
= Window
->WindowRect
;
827 OldClientRect
= Window
->ClientRect
;
829 if (OldClientRect
.bottom
- OldClientRect
.top
==
830 NewClientRect
.bottom
- NewClientRect
.top
)
832 WvrFlags
&= ~WVR_VREDRAW
;
835 if (OldClientRect
.right
- OldClientRect
.left
==
836 NewClientRect
.right
- NewClientRect
.left
)
838 WvrFlags
&= ~WVR_HREDRAW
;
841 /* FIXME: Actually do something with WVR_VALIDRECTS */
843 if (! (WinPos
.flags
& SWP_NOMOVE
)
844 && (NewWindowRect
.left
!= OldWindowRect
.left
845 || NewWindowRect
.top
!= OldWindowRect
.top
))
847 WinPosInternalMoveWindow(Window
,
848 NewWindowRect
.left
- OldWindowRect
.left
,
849 NewWindowRect
.top
- OldWindowRect
.top
);
852 Window
->WindowRect
= NewWindowRect
;
853 Window
->ClientRect
= NewClientRect
;
855 if (!(WinPos
.flags
& SWP_SHOWWINDOW
) && (WinPos
.flags
& SWP_HIDEWINDOW
))
857 /* Clear the update region */
858 IntRedrawWindow(Window
, NULL
, 0, RDW_VALIDATE
| RDW_NOFRAME
|
859 RDW_NOERASE
| RDW_NOINTERNALPAINT
| RDW_ALLCHILDREN
);
860 Window
->Style
&= ~WS_VISIBLE
;
862 else if (WinPos
.flags
& SWP_SHOWWINDOW
)
864 Window
->Style
|= WS_VISIBLE
;
867 /* Determine the new visible region */
868 VisAfter
= VIS_ComputeVisibleRegion(
869 PsGetWin32Thread()->Desktop
, Window
, FALSE
, FALSE
, TRUE
);
871 if (UnsafeIntGetRgnBox(VisAfter
, &TempRect
) == NULLREGION
)
873 NtGdiDeleteObject(VisAfter
);
878 * Determine which pixels can be copied from the old window position
879 * to the new. Those pixels must be visible in both the old and new
880 * position. Also, check the class style to see if the windows of this
881 * class need to be completely repainted on (horizontal/vertical) size
884 if (VisBefore
!= NULL
&& VisAfter
!= NULL
&& !(WinPos
.flags
& SWP_NOCOPYBITS
) &&
885 ((WinPos
.flags
& SWP_NOSIZE
) || !(WvrFlags
& WVR_REDRAW
)))
887 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
888 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
891 * If this is (also) a window resize, the whole nonclient area
892 * needs to be repainted. So we limit the copy to the client area,
893 * 'cause there is no use in copying it (would possibly cause
894 * "flashing" too). However, if the copy region is already empty,
895 * we don't have to crop (can't take anything away from an empty
898 if (!(WinPos
.flags
& SWP_NOSIZE
) && RgnType
!= ERROR
&&
899 RgnType
!= NULLREGION
)
901 RECT ORect
= OldClientRect
;
902 RECT NRect
= NewClientRect
;
903 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
904 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
905 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
906 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
909 /* No use in copying bits which are in the update region. */
910 if (Window
->UpdateRegion
!= NULL
)
912 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
914 if (Window
->NCUpdateRegion
!= NULL
)
916 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->NCUpdateRegion
, RGN_DIFF
);
920 * Now, get the bounding box of the copy region. If it's empty
921 * there's nothing to copy. Also, it's no use copying bits onto
924 if (UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
) == NULLREGION
)
926 /* Nothing to copy, clean up */
927 NtGdiDeleteObject(CopyRgn
);
930 else if (OldWindowRect
.left
!= NewWindowRect
.left
||
931 OldWindowRect
.top
!= NewWindowRect
.top
)
934 * Small trick here: there is no function to bitblt a region. So
935 * we set the region as the clipping region, take the bounding box
936 * of the region and bitblt that. Since nothing outside the clipping
937 * region is copied, this has the effect of bitblt'ing the region.
939 * Since NtUserGetDCEx takes ownership of the clip region, we need
940 * to create a copy of CopyRgn and pass that. We need CopyRgn later
942 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
944 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
945 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
946 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
948 CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
949 CopyRect
.bottom
- CopyRect
.top
, Dc
,
950 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
951 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
952 NtUserReleaseDC(Wnd
, Dc
);
953 IntValidateParent(Window
, CopyRgn
);
961 /* We need to redraw what wasn't visible before */
962 if (VisAfter
!= NULL
)
966 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
967 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
968 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
970 NtGdiOffsetRgn(DirtyRgn
,
971 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
972 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
973 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
974 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
976 NtGdiDeleteObject(DirtyRgn
);
980 IntRedrawWindow(Window
, NULL
, 0,
981 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
987 NtGdiDeleteObject(CopyRgn
);
990 /* Expose what was covered before but not covered anymore */
991 if (VisBefore
!= NULL
)
993 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
994 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
995 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
996 OldWindowRect
.top
- NewWindowRect
.top
);
997 if (VisAfter
!= NULL
)
998 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
1000 RgnType
= SIMPLEREGION
;
1002 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
1004 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
,
1007 NtGdiDeleteObject(ExposedRgn
);
1008 NtGdiDeleteObject(VisBefore
);
1011 if (VisAfter
!= NULL
)
1013 NtGdiDeleteObject(VisAfter
);
1016 if (!(WinPos
.flags
& SWP_NOREDRAW
))
1018 IntRedrawWindow(Window
, NULL
, 0, RDW_ALLCHILDREN
| RDW_ERASENOW
);
1021 if (!(WinPos
.flags
& SWP_NOACTIVATE
))
1023 if ((Window
->Style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
1025 IntSendMessage(WinPos
.hwnd
, WM_CHILDACTIVATE
, 0, 0);
1029 IntSetForegroundWindow(Window
);
1033 if ((WinPos
.flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
1034 IntSendMessage(WinPos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
) &WinPos
);
1036 IntReleaseWindowObject(Window
);
1042 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
1044 *ClientRect
= *WindowRect
;
1045 return(IntSendMessage(Wnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
) ClientRect
));
1049 WinPosShowWindow(HWND Wnd
, INT Cmd
)
1052 PWINDOW_OBJECT Window
;
1060 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
1064 if (!NT_SUCCESS(Status
))
1069 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1077 ObmDereferenceObject(Window
);
1080 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1085 case SW_SHOWMINNOACTIVE
:
1086 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1088 case SW_SHOWMINIMIZED
:
1089 Swp
|= SWP_SHOWWINDOW
;
1093 Swp
|= SWP_FRAMECHANGED
| SWP_NOACTIVATE
;
1094 if (!(Window
->Style
& WS_MINIMIZE
))
1096 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1100 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1105 case SW_SHOWMAXIMIZED
:
1107 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1108 if (!(Window
->Style
& WS_MAXIMIZE
))
1110 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1114 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1120 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1123 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1124 /* Don't activate the topmost window. */
1127 case SW_SHOWNOACTIVATE
:
1128 Swp
|= SWP_NOZORDER
;
1131 case SW_SHOWDEFAULT
:
1133 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1134 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1136 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1140 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1145 ShowFlag
= (Cmd
!= SW_HIDE
);
1146 if (ShowFlag
!= WasVisible
)
1148 IntSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0);
1150 * FIXME: Need to check the window wasn't destroyed during the
1155 /* We can't activate a child window */
1156 if ((Window
->Style
& WS_CHILD
) &&
1157 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1159 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1162 WinPosSetWindowPos(Window
->Self
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1163 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1167 /* FIXME: This will cause the window to be activated irrespective
1168 * of whether it is owned by the same thread. Has to be done
1172 if (Window
->Self
== NtUserGetActiveWindow())
1174 WinPosActivateOtherWindow(Window
);
1177 /* Revert focus to parent */
1178 if (Wnd
== IntGetThreadFocusWindow() ||
1179 IntIsChildWindow(Wnd
, IntGetThreadFocusWindow()))
1181 NtUserSetFocus(Window
->Parent
->Self
);
1185 /* FIXME: Check for window destruction. */
1187 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1189 WPARAM wParam
= SIZE_RESTORED
;
1191 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1192 if (Window
->Style
& WS_MAXIMIZE
)
1194 wParam
= SIZE_MAXIMIZED
;
1196 else if (Window
->Style
& WS_MINIMIZE
)
1198 wParam
= SIZE_MINIMIZED
;
1201 IntSendMessage(Wnd
, WM_SIZE
, wParam
,
1202 MAKELONG(Window
->ClientRect
.right
-
1203 Window
->ClientRect
.left
,
1204 Window
->ClientRect
.bottom
-
1205 Window
->ClientRect
.top
));
1206 IntSendMessage(Wnd
, WM_MOVE
, 0,
1207 MAKELONG(Window
->ClientRect
.left
,
1208 Window
->ClientRect
.top
));
1211 /* Activate the window if activation is not requested and the window is not minimized */
1213 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1215 WinPosChangeActiveWindow(Wnd, FALSE);
1219 ObmDereferenceObject(Window
);
1223 BOOL STATIC FASTCALL
1224 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1226 return(Point
.x
>= Window
->WindowRect
.left
&&
1227 Point
.x
< Window
->WindowRect
.right
&&
1228 Point
.y
>= Window
->WindowRect
.top
&&
1229 Point
.y
< Window
->WindowRect
.bottom
);
1232 USHORT STATIC FASTCALL
1233 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1234 PWINDOW_OBJECT
* Window
)
1236 PWINDOW_OBJECT Current
;
1238 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1239 Current
= ScopeWin
->FirstChild
;
1242 if (Current
->Style
& WS_VISIBLE
&&
1243 ((!(Current
->Style
& WS_DISABLED
)) ||
1244 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1245 WinPosPtInWindow(Current
, Point
))
1248 ObmDereferenceObject(*Window
);
1249 ObmReferenceObjectByPointer(Current
, otWindow
);
1253 if (Current
->Style
& WS_DISABLED
)
1255 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1258 if (Point
.x
>= Current
->ClientRect
.left
&&
1259 Point
.x
< Current
->ClientRect
.right
&&
1260 Point
.y
>= Current
->ClientRect
.top
&&
1261 Point
.y
< Current
->ClientRect
.bottom
)
1264 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1265 return(WinPosSearchChildren(Current
, Point
, Window
));
1268 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1271 Current
= Current
->NextSibling
;
1274 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1279 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1280 PWINDOW_OBJECT
* Window
)
1282 HWND DesktopWindowHandle
;
1283 PWINDOW_OBJECT DesktopWindow
;
1284 POINT Point
= WinPoint
;
1291 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1295 if (ScopeWin
->Style
& WS_DISABLED
)
1300 /* Translate the point to the space of the scope window. */
1301 DesktopWindowHandle
= IntGetDesktopWindow();
1302 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1303 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1304 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1305 IntReleaseWindowObject(DesktopWindow
);
1307 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1313 if ((*Window
) == NULL
)
1317 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1319 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1320 MAKELONG(Point
.x
, Point
.y
));
1321 /* FIXME: Check for HTTRANSPARENT here. */
1333 NtUserGetMinMaxInfo(
1335 MINMAXINFO
*MinMaxInfo
,
1339 PINTERNALPOS InternalPos
;
1340 PWINDOW_OBJECT Window
;
1341 MINMAXINFO SafeMinMax
;
1344 Window
= IntGetWindowObject(hwnd
);
1347 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1351 Size
.x
= Window
->WindowRect
.left
;
1352 Size
.y
= Window
->WindowRect
.top
;
1353 InternalPos
= WinPosInitInternalPos(Window
, Size
,
1354 &Window
->WindowRect
);
1359 WinPosGetMinMaxInfo(Window
, &SafeMinMax
.ptMaxSize
, &SafeMinMax
.ptMaxPosition
,
1360 &SafeMinMax
.ptMinTrackSize
, &SafeMinMax
.ptMaxTrackSize
);
1364 WinPosFillMinMaxInfoStruct(Window
, &SafeMinMax
);
1366 Status
= MmCopyToCaller(MinMaxInfo
, &SafeMinMax
, sizeof(MINMAXINFO
));
1367 if(!NT_SUCCESS(Status
))
1369 IntReleaseWindowObject(Window
);
1370 SetLastNtError(Status
);
1373 IntReleaseWindowObject(Window
);
1377 IntReleaseWindowObject(Window
);