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.82 2004/01/18 08:29:31 navaraf Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH NtGdid
29 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <internal/safe.h>
33 #include <win32k/win32k.h>
34 #include <include/object.h>
35 #include <include/guicheck.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/desktop.h>
41 #include <include/winpos.h>
42 #include <include/rect.h>
43 #include <include/callback.h>
44 #include <include/painting.h>
45 #include <include/dce.h>
46 #include <include/vis.h>
47 #include <include/focus.h>
52 /* GLOBALS *******************************************************************/
54 #define MINMAX_NOSWP (0x00010000)
56 #define SWP_EX_NOCOPY 0x0001
57 #define SWP_EX_PAINTSELF 0x0002
59 #define SWP_AGG_NOGEOMETRYCHANGE \
60 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
61 #define SWP_AGG_NOPOSCHANGE \
62 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
63 #define SWP_AGG_STATUSFLAGS \
64 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
66 /* FUNCTIONS *****************************************************************/
68 #define HAS_DLGFRAME(Style, ExStyle) \
69 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
70 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME))))
72 #define HAS_THICKFRAME(Style, ExStyle) \
73 (((Style) & WS_THICKFRAME) && \
74 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
76 #define HAS_THINFRAME(Style, ExStyle) \
77 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP))))
80 IntGetClientOrigin(HWND hWnd
, LPPOINT Point
)
82 PWINDOW_OBJECT WindowObject
;
84 WindowObject
= IntGetWindowObject(hWnd
);
85 if (WindowObject
== NULL
)
87 Point
->x
= Point
->y
= 0;
90 Point
->x
= WindowObject
->ClientRect
.left
;
91 Point
->y
= WindowObject
->ClientRect
.top
;
93 IntReleaseWindowObject(WindowObject
);
98 NtUserGetClientOrigin(HWND hWnd
, LPPOINT Point
)
104 Ret
= IntGetClientOrigin(hWnd
, &pt
);
106 Status
= MmCopyToCaller(Point
, &pt
, sizeof(POINT
));
107 if(!NT_SUCCESS(Status
))
109 SetLastNtError(Status
);
116 /*******************************************************************
117 * WinPosActivateOtherWindow
119 * Activates window other than pWnd.
122 WinPosActivateOtherWindow(PWINDOW_OBJECT Window
)
124 PWINDOW_OBJECT Child
;
125 PWINDOW_OBJECT TabooWindow
= Window
;
129 if (NULL
== Window
|| IntIsDesktopWindow(Window
))
131 IntSetFocusMessageQueue(NULL
);
134 Window
= Window
->Parent
;
135 ExAcquireFastMutex(&(Window
->ChildrenListLock
));
136 Child
= Window
->FirstChild
;
137 while (NULL
!= Child
)
139 if (Child
!= TabooWindow
)
141 ExReleaseFastMutex(&(Window
->ChildrenListLock
));
142 if (IntSetForegroundWindow(Child
))
146 ExAcquireFastMutex(&(Window
->ChildrenListLock
));
148 Child
= Child
->NextSibling
;
150 ExReleaseFastMutex(&(Window
->ChildrenListLock
));
155 WinPosFindIconPos(HWND hWnd
, POINT
*Pos
)
160 PINTERNALPOS FASTCALL
161 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject
, POINT pt
, PRECT RestoreRect
)
165 if (WindowObject
->InternalPos
== NULL
)
168 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
170 if(WindowObject
->Parent
== NULL
)
171 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
173 WorkArea
= WindowObject
->Parent
->ClientRect
;
175 WindowObject
->InternalPos
= ExAllocatePool(NonPagedPool
, sizeof(INTERNALPOS
));
176 if(!WindowObject
->InternalPos
)
178 DPRINT1("Failed to allocate INTERNALPOS structure for window 0x%x\n", WindowObject
->Self
);
181 WindowObject
->InternalPos
->NormalRect
= WindowObject
->WindowRect
;
182 if (HAS_DLGFRAME(WindowObject
->Style
, WindowObject
->ExStyle
) && !(WindowObject
->Style
& WS_MINIMIZE
))
184 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
185 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
190 if (HAS_THICKFRAME(WindowObject
->Style
, WindowObject
->ExStyle
)&& !(WindowObject
->Style
& WS_MINIMIZE
))
192 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
193 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
195 else if (HAS_THINFRAME(WindowObject
->Style
, WindowObject
->ExStyle
))
197 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
198 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
201 WindowObject
->InternalPos
->MaxPos
.x
= WorkArea
.left
- XInc
;
202 WindowObject
->InternalPos
->MaxPos
.y
= WorkArea
.top
- YInc
;
203 WindowObject
->InternalPos
->IconPos
.x
= WorkArea
.left
;
204 WindowObject
->InternalPos
->IconPos
.y
= WorkArea
.bottom
- NtUserGetSystemMetrics(SM_CYMINIMIZED
);
206 if (WindowObject
->Style
& WS_MINIMIZE
)
208 WindowObject
->InternalPos
->IconPos
= pt
;
210 else if (WindowObject
->Style
& WS_MAXIMIZE
)
212 WindowObject
->InternalPos
->MaxPos
= pt
;
214 else if (RestoreRect
!= NULL
)
216 WindowObject
->InternalPos
->NormalRect
= *RestoreRect
;
218 return(WindowObject
->InternalPos
);
222 WinPosMinMaximize(PWINDOW_OBJECT WindowObject
, UINT ShowFlag
, RECT
* NewPos
)
225 PINTERNALPOS InternalPos
;
228 Size
.x
= WindowObject
->WindowRect
.left
;
229 Size
.y
= WindowObject
->WindowRect
.top
;
230 InternalPos
= WinPosInitInternalPos(WindowObject
, Size
,
231 &WindowObject
->WindowRect
);
235 if (WindowObject
->Style
& WS_MINIMIZE
)
237 if (!IntSendMessage(WindowObject
->Self
, WM_QUERYOPEN
, 0, 0))
239 return(SWP_NOSIZE
| SWP_NOMOVE
);
241 SwpFlags
|= SWP_NOCOPYBITS
;
247 if (WindowObject
->Style
& WS_MAXIMIZE
)
249 WindowObject
->Flags
|= WINDOWOBJECT_RESTOREMAX
;
250 WindowObject
->Style
&= ~WS_MAXIMIZE
;
254 WindowObject
->Flags
&= ~WINDOWOBJECT_RESTOREMAX
;
256 IntRedrawWindow(WindowObject
, NULL
, 0, RDW_VALIDATE
| RDW_NOERASE
|
257 RDW_NOINTERNALPAINT
);
258 WindowObject
->Style
|= WS_MINIMIZE
;
259 WinPosFindIconPos(WindowObject
, &InternalPos
->IconPos
);
260 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
261 NtUserGetSystemMetrics(SM_CXMINIMIZED
),
262 NtUserGetSystemMetrics(SM_CYMINIMIZED
));
263 SwpFlags
|= SWP_NOCOPYBITS
;
269 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
271 DPRINT1("Maximize: %d,%d %dx%d\n",
272 InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
273 if (WindowObject
->Style
& WS_MINIMIZE
)
275 WindowObject
->Style
&= ~WS_MINIMIZE
;
277 WindowObject
->Style
|= WS_MAXIMIZE
;
278 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
,
285 if (WindowObject
->Style
& WS_MINIMIZE
)
287 WindowObject
->Style
&= ~WS_MINIMIZE
;
288 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
290 WinPosGetMinMaxInfo(WindowObject
, &Size
,
291 &InternalPos
->MaxPos
, NULL
, NULL
);
292 WindowObject
->Style
|= WS_MAXIMIZE
;
293 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
294 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
299 *NewPos
= InternalPos
->NormalRect
;
300 NewPos
->right
-= NewPos
->left
;
301 NewPos
->bottom
-= NewPos
->top
;
307 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
311 WindowObject
->Style
&= ~WS_MAXIMIZE
;
312 *NewPos
= InternalPos
->NormalRect
;
313 NewPos
->right
-= NewPos
->left
;
314 NewPos
->bottom
-= NewPos
->top
;
322 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
328 WinPosFillMinMaxInfoStruct(PWINDOW_OBJECT Window
, MINMAXINFO
*Info
)
332 PDESKTOP_OBJECT Desktop
= PsGetWin32Thread()->Desktop
; /* Or rather get it from the window? */
334 if(Window
->Parent
== NULL
)
335 WorkArea
= *IntGetDesktopWorkArea(Desktop
);
337 WorkArea
= Window
->Parent
->ClientRect
;
339 /* Get default values. */
340 Info
->ptMaxSize
.x
= WorkArea
.right
- WorkArea
.left
;
341 Info
->ptMaxSize
.y
= WorkArea
.bottom
- WorkArea
.top
;
342 Info
->ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
343 Info
->ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
344 Info
->ptMaxTrackSize
.x
= Info
->ptMaxSize
.x
;
345 Info
->ptMaxTrackSize
.y
= Info
->ptMaxSize
.y
;
347 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
349 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
350 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
355 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
357 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
358 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
360 else if (HAS_THINFRAME(Window
->Style
, Window
->ExStyle
))
362 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
363 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
366 Info
->ptMaxSize
.x
+= 2 * XInc
;
367 Info
->ptMaxSize
.y
+= 2 * YInc
;
369 if (Window
->InternalPos
!= NULL
)
371 Info
->ptMaxPosition
= Window
->InternalPos
->MaxPos
;
375 Info
->ptMaxPosition
.x
-= WorkArea
.left
+ XInc
;
376 Info
->ptMaxPosition
.y
-= WorkArea
.top
+ YInc
;
381 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
382 POINT
* MinTrack
, POINT
* MaxTrack
)
386 WinPosFillMinMaxInfoStruct(Window
, &MinMax
);
388 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
);
390 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
391 MinMax
.ptMinTrackSize
.x
);
392 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
393 MinMax
.ptMinTrackSize
.y
);
395 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
396 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
397 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
398 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
400 return 0; //FIXME: what does it return?
404 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
405 RECT
* WindowRect
, RECT
* ClientRect
)
409 /* Send WM_NCCALCSIZE message to get new client area */
410 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
412 NCCALCSIZE_PARAMS params
;
413 WINDOWPOS winposCopy
;
415 params
.rgrc
[0] = *WindowRect
;
416 params
.rgrc
[1] = Window
->WindowRect
;
417 params
.rgrc
[2] = Window
->ClientRect
;
418 if (0 != (Window
->Style
& WS_CHILD
))
420 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
421 - Window
->Parent
->ClientRect
.top
);
422 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
423 - Window
->Parent
->ClientRect
.top
);
424 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
425 - Window
->Parent
->ClientRect
.top
);
427 params
.lppos
= &winposCopy
;
428 winposCopy
= *WinPos
;
430 wvrFlags
= IntSendMessage(Window
->Self
, WM_NCCALCSIZE
, TRUE
, (LPARAM
) ¶ms
);
432 /* If the application send back garbage, ignore it */
433 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
434 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
436 *ClientRect
= params
.rgrc
[0];
437 if (Window
->Style
& WS_CHILD
)
439 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
440 Window
->Parent
->ClientRect
.top
);
444 /* FIXME: WVR_ALIGNxxx */
446 if (ClientRect
->left
!= Window
->ClientRect
.left
||
447 ClientRect
->top
!= Window
->ClientRect
.top
)
449 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
452 if ((ClientRect
->right
- ClientRect
->left
!=
453 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
454 (ClientRect
->bottom
- ClientRect
->top
!=
455 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
457 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
462 if (! (WinPos
->flags
& SWP_NOMOVE
)
463 && (ClientRect
->left
!= Window
->ClientRect
.left
||
464 ClientRect
->top
!= Window
->ClientRect
.top
))
466 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
474 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
481 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
483 IntSendMessage(WindowObject
->Self
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
) WinPos
);
486 *WindowRect
= WindowObject
->WindowRect
;
487 *ClientRect
= WindowObject
->ClientRect
;
489 if (!(WinPos
->flags
& SWP_NOSIZE
))
491 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
492 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
495 if (!(WinPos
->flags
& SWP_NOMOVE
))
499 if (0 != (WindowObject
->Style
& WS_CHILD
))
501 X
+= WindowObject
->Parent
->ClientRect
.left
;
502 Y
+= WindowObject
->Parent
->ClientRect
.top
;
504 WindowRect
->left
= X
;
506 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
507 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
508 NtGdiOffsetRect(ClientRect
,
509 X
- WindowObject
->WindowRect
.left
,
510 Y
- WindowObject
->WindowRect
.top
);
513 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
519 * Fix Z order taking into account owned popups -
520 * basically we need to maintain them above the window that owns them
523 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
526 HWND Owner
= NtUserGetWindow(hWnd
, GW_OWNER
);
527 LONG Style
= NtUserGetWindowLong(hWnd
, GWL_STYLE
, FALSE
);
528 PWINDOW_OBJECT DesktopWindow
;
531 if ((Style
& WS_POPUP
) && Owner
)
533 /* Make sure this popup stays above the owner */
534 HWND hWndLocalPrev
= HWND_TOP
;
536 if (hWndInsertAfter
!= HWND_TOP
)
538 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
539 List
= IntWinListChildren(DesktopWindow
);
540 IntReleaseWindowObject(DesktopWindow
);
543 for (i
= 0; List
[i
]; i
++)
545 if (List
[i
] == Owner
) break;
546 if (List
[i
] != hWnd
) hWndLocalPrev
= List
[i
];
547 if (hWndLocalPrev
== hWndInsertAfter
) break;
549 hWndInsertAfter
= hWndLocalPrev
;
553 else if (Style
& WS_CHILD
)
555 return hWndInsertAfter
;
560 DesktopWindow
= IntGetWindowObject(IntGetDesktopWindow());
561 List
= IntWinListChildren(DesktopWindow
);
562 IntReleaseWindowObject(DesktopWindow
);
566 for (i
= 0; List
[i
]; i
++)
570 if ((NtUserGetWindowLong(List
[i
], GWL_STYLE
, FALSE
) & WS_POPUP
) &&
571 NtUserGetWindow(List
[i
], GW_OWNER
) == hWnd
)
573 WinPosSetWindowPos(List
[i
], hWndInsertAfter
, 0, 0, 0, 0,
574 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
);
575 hWndInsertAfter
= List
[i
];
581 return hWndInsertAfter
;
584 /***********************************************************************
585 * WinPosInternalMoveWindow
587 * Update WindowRect and ClientRect of Window and all of its children
588 * We keep both WindowRect and ClientRect in screen coordinates internally
591 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
593 PWINDOW_OBJECT Child
;
595 Window
->WindowRect
.left
+= MoveX
;
596 Window
->WindowRect
.right
+= MoveX
;
597 Window
->WindowRect
.top
+= MoveY
;
598 Window
->WindowRect
.bottom
+= MoveY
;
600 Window
->ClientRect
.left
+= MoveX
;
601 Window
->ClientRect
.right
+= MoveX
;
602 Window
->ClientRect
.top
+= MoveY
;
603 Window
->ClientRect
.bottom
+= MoveY
;
605 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
606 Child
= Window
->FirstChild
;
609 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
610 Child
= Child
->NextSibling
;
612 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
616 * WinPosFixupSWPFlags
618 * Fix redundant flags and values in the WINDOWPOS structure.
622 WinPosFixupFlags(WINDOWPOS
*WinPos
, PWINDOW_OBJECT Window
)
624 if (Window
->Style
& WS_VISIBLE
)
626 WinPos
->flags
&= ~SWP_SHOWWINDOW
;
630 WinPos
->flags
&= ~SWP_HIDEWINDOW
;
631 if (!(WinPos
->flags
& SWP_SHOWWINDOW
))
632 WinPos
->flags
|= SWP_NOREDRAW
;
635 WinPos
->cx
= max(WinPos
->cx
, 0);
636 WinPos
->cy
= max(WinPos
->cy
, 0);
638 /* Check for right size */
639 if (Window
->WindowRect
.right
- Window
->WindowRect
.left
== WinPos
->cx
&&
640 Window
->WindowRect
.bottom
- Window
->WindowRect
.top
== WinPos
->cy
)
642 WinPos
->flags
|= SWP_NOSIZE
;
645 /* Check for right position */
646 if (Window
->WindowRect
.left
== WinPos
->x
&&
647 Window
->WindowRect
.top
== WinPos
->y
)
649 WinPos
->flags
|= SWP_NOMOVE
;
652 if (WinPos
->hwnd
== NtUserGetForegroundWindow())
654 WinPos
->flags
|= SWP_NOACTIVATE
; /* Already active */
657 if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
659 /* Bring to the top when activating */
660 if (!(WinPos
->flags
& SWP_NOACTIVATE
))
662 WinPos
->flags
&= ~SWP_NOZORDER
;
663 WinPos
->hwndInsertAfter
= HWND_TOP
;
668 /* Check hwndInsertAfter */
669 if (!(WinPos
->flags
& SWP_NOZORDER
))
671 /* Fix sign extension */
672 if (WinPos
->hwndInsertAfter
== (HWND
)0xffff)
674 WinPos
->hwndInsertAfter
= HWND_TOPMOST
;
676 else if (WinPos
->hwndInsertAfter
== (HWND
)0xfffe)
678 WinPos
->hwndInsertAfter
= HWND_NOTOPMOST
;
681 /* FIXME: TOPMOST not supported yet */
682 if ((WinPos
->hwndInsertAfter
== HWND_TOPMOST
) ||
683 (WinPos
->hwndInsertAfter
== HWND_NOTOPMOST
))
685 WinPos
->hwndInsertAfter
= HWND_TOP
;
688 /* hwndInsertAfter must be a sibling of the window */
689 if ((WinPos
->hwndInsertAfter
!= HWND_TOP
) &&
690 (WinPos
->hwndInsertAfter
!= HWND_BOTTOM
))
692 if (NtUserGetAncestor(WinPos
->hwndInsertAfter
, GA_PARENT
) !=
693 Window
->Parent
->Self
)
700 * We don't need to change the Z order of hwnd if it's already
701 * inserted after hwndInsertAfter or when inserting hwnd after
704 if ((WinPos
->hwnd
== WinPos
->hwndInsertAfter
) ||
705 (WinPos
->hwnd
== NtUserGetWindow(WinPos
->hwndInsertAfter
, GW_HWNDNEXT
)))
707 WinPos
->flags
|= SWP_NOZORDER
;
716 /* x and y are always screen relative */
718 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
721 PWINDOW_OBJECT Window
;
725 HRGN VisBefore
= NULL
;
726 HRGN VisAfter
= NULL
;
727 HRGN DirtyRgn
= NULL
;
728 HRGN ExposedRgn
= NULL
;
731 RECT OldWindowRect
, OldClientRect
;
737 /* FIXME: Get current active window from active queue. */
739 Window
= IntGetWindowObject(Wnd
);
742 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
747 * Only allow CSRSS to mess with the desktop window
749 if (Wnd
== IntGetDesktopWindow() &&
750 Window
->OwnerThread
->ThreadsProcess
!= PsGetCurrentProcess())
756 WinPos
.hwndInsertAfter
= WndInsertAfter
;
761 WinPos
.flags
= flags
;
763 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
765 /* Fix up the flags. */
766 if (!WinPosFixupFlags(&WinPos
, Window
))
768 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
769 IntReleaseWindowObject(Window
);
773 /* Does the window still exist? */
774 if (!IntIsWindow(WinPos
.hwnd
))
776 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
780 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
782 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) == IntGetDesktopWindow())
784 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
787 /* Compute the visible region before the window position is changed */
788 if (!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
789 (WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
790 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
791 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
793 VisBefore
= VIS_ComputeVisibleRegion(Window
, FALSE
, FALSE
, TRUE
);
795 if (VisBefore
!= NULL
&&
796 UnsafeIntGetRgnBox(VisBefore
, &TempRect
) == NULLREGION
)
798 NtGdiDeleteObject(VisBefore
);
803 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
805 /* Relink windows. (also take into account shell window in hwndShellWindow) */
806 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwnd
!= NtUserGetShellWindow())
808 PWINDOW_OBJECT ParentWindow
;
809 PWINDOW_OBJECT InsertAfterWindow
;
811 ParentWindow
= Window
->Parent
;
814 if (WinPos
.hwndInsertAfter
== HWND_TOP
)
815 InsertAfterWindow
= NULL
;
816 else if (WinPos
.hwndInsertAfter
== HWND_BOTTOM
)
817 InsertAfterWindow
= IntGetWindowObject(ParentWindow
->LastChild
->Self
);
819 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
820 /* Do nothing if hwndInsertAfter is HWND_BOTTOM and Window is already
822 if (InsertAfterWindow
!= Window
)
824 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
825 IntUnlinkWindow(Window
);
826 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
827 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
829 if (InsertAfterWindow
!= NULL
)
830 IntReleaseWindowObject(InsertAfterWindow
);
834 /* FIXME: Reset active DCEs */
836 OldWindowRect
= Window
->WindowRect
;
837 OldClientRect
= Window
->ClientRect
;
839 if (OldClientRect
.bottom
- OldClientRect
.top
==
840 NewClientRect
.bottom
- NewClientRect
.top
)
842 WvrFlags
&= ~WVR_VREDRAW
;
845 if (OldClientRect
.right
- OldClientRect
.left
==
846 NewClientRect
.right
- NewClientRect
.left
)
848 WvrFlags
&= ~WVR_HREDRAW
;
851 /* FIXME: Actually do something with WVR_VALIDRECTS */
853 if (! (WinPos
.flags
& SWP_NOMOVE
)
854 && (NewWindowRect
.left
!= OldWindowRect
.left
855 || NewWindowRect
.top
!= OldWindowRect
.top
))
857 WinPosInternalMoveWindow(Window
,
858 NewWindowRect
.left
- OldWindowRect
.left
,
859 NewWindowRect
.top
- OldWindowRect
.top
);
862 Window
->WindowRect
= NewWindowRect
;
863 Window
->ClientRect
= NewClientRect
;
865 if (!(WinPos
.flags
& SWP_SHOWWINDOW
) && (WinPos
.flags
& SWP_HIDEWINDOW
))
867 /* Clear the update region */
868 IntRedrawWindow(Window
, NULL
, 0, RDW_VALIDATE
| RDW_NOFRAME
|
869 RDW_NOERASE
| RDW_NOINTERNALPAINT
| RDW_ALLCHILDREN
);
870 Window
->Style
&= ~WS_VISIBLE
;
872 else if (WinPos
.flags
& SWP_SHOWWINDOW
)
874 Window
->Style
|= WS_VISIBLE
;
877 /* Determine the new visible region */
878 VisAfter
= VIS_ComputeVisibleRegion(Window
, FALSE
, FALSE
, TRUE
);
880 if (VisAfter
!= NULL
&&
881 UnsafeIntGetRgnBox(VisAfter
, &TempRect
) == NULLREGION
)
883 NtGdiDeleteObject(VisAfter
);
888 * Determine which pixels can be copied from the old window position
889 * to the new. Those pixels must be visible in both the old and new
890 * position. Also, check the class style to see if the windows of this
891 * class need to be completely repainted on (horizontal/vertical) size
894 if (VisBefore
!= NULL
&& VisAfter
!= NULL
&& !(WinPos
.flags
& SWP_NOCOPYBITS
) &&
895 ((WinPos
.flags
& SWP_NOSIZE
) || !(WvrFlags
& WVR_REDRAW
)))
897 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
898 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
901 * If this is (also) a window resize, the whole nonclient area
902 * needs to be repainted. So we limit the copy to the client area,
903 * 'cause there is no use in copying it (would possibly cause
904 * "flashing" too). However, if the copy region is already empty,
905 * we don't have to crop (can't take anything away from an empty
908 if (!(WinPos
.flags
& SWP_NOSIZE
) && RgnType
!= ERROR
&&
909 RgnType
!= NULLREGION
)
911 RECT ORect
= OldClientRect
;
912 RECT NRect
= NewClientRect
;
913 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
914 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
915 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
916 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
919 /* No use in copying bits which are in the update region. */
920 if (Window
->UpdateRegion
!= NULL
)
922 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
924 if (Window
->NCUpdateRegion
!= NULL
)
926 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->NCUpdateRegion
, RGN_DIFF
);
930 * Now, get the bounding box of the copy region. If it's empty
931 * there's nothing to copy. Also, it's no use copying bits onto
934 if (UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
) == NULLREGION
)
936 /* Nothing to copy, clean up */
937 NtGdiDeleteObject(CopyRgn
);
940 else if (OldWindowRect
.left
!= NewWindowRect
.left
||
941 OldWindowRect
.top
!= NewWindowRect
.top
)
944 * Small trick here: there is no function to bitblt a region. So
945 * we set the region as the clipping region, take the bounding box
946 * of the region and bitblt that. Since nothing outside the clipping
947 * region is copied, this has the effect of bitblt'ing the region.
949 * Since NtUserGetDCEx takes ownership of the clip region, we need
950 * to create a copy of CopyRgn and pass that. We need CopyRgn later
952 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
954 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
955 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
956 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
958 CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
959 CopyRect
.bottom
- CopyRect
.top
, Dc
,
960 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
961 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
962 NtUserReleaseDC(Wnd
, Dc
);
963 IntValidateParent(Window
, CopyRgn
);
971 /* We need to redraw what wasn't visible before */
972 if (VisAfter
!= NULL
)
974 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
977 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
981 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, 0, RGN_COPY
);
983 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
985 NtGdiOffsetRgn(DirtyRgn
,
986 Window
->WindowRect
.left
- Window
->ClientRect
.left
,
987 Window
->WindowRect
.top
- Window
->ClientRect
.top
);
988 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
989 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
991 NtGdiDeleteObject(DirtyRgn
);
996 NtGdiDeleteObject(CopyRgn
);
999 /* Expose what was covered before but not covered anymore */
1000 if (VisBefore
!= NULL
)
1002 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
1003 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
1004 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
1005 OldWindowRect
.top
- NewWindowRect
.top
);
1006 if (VisAfter
!= NULL
)
1007 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
1009 RgnType
= SIMPLEREGION
;
1011 if (RgnType
!= ERROR
&& RgnType
!= NULLREGION
)
1013 VIS_WindowLayoutChanged(Window
, ExposedRgn
);
1015 NtGdiDeleteObject(ExposedRgn
);
1016 NtGdiDeleteObject(VisBefore
);
1019 if (VisAfter
!= NULL
)
1021 NtGdiDeleteObject(VisAfter
);
1024 if (!(WinPos
.flags
& SWP_NOREDRAW
))
1026 IntRedrawWindow(Window
, NULL
, 0, RDW_ALLCHILDREN
| RDW_ERASENOW
);
1029 if (!(WinPos
.flags
& SWP_NOACTIVATE
))
1031 if ((Window
->Style
& (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
1033 IntSendMessage(WinPos
.hwnd
, WM_CHILDACTIVATE
, 0, 0);
1037 IntSetForegroundWindow(Window
);
1041 if ((WinPos
.flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
1042 IntSendMessage(WinPos
.hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
) &WinPos
);
1044 IntReleaseWindowObject(Window
);
1050 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
1052 *ClientRect
= *WindowRect
;
1053 return(IntSendMessage(Wnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
) ClientRect
));
1057 WinPosShowWindow(HWND Wnd
, INT Cmd
)
1060 PWINDOW_OBJECT Window
;
1068 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
1072 if (!NT_SUCCESS(Status
))
1077 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1085 ObmDereferenceObject(Window
);
1088 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1093 case SW_SHOWMINNOACTIVE
:
1094 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1096 case SW_SHOWMINIMIZED
:
1097 Swp
|= SWP_SHOWWINDOW
;
1101 Swp
|= SWP_FRAMECHANGED
| SWP_NOACTIVATE
;
1102 if (!(Window
->Style
& WS_MINIMIZE
))
1104 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1108 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1113 case SW_SHOWMAXIMIZED
:
1115 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1116 if (!(Window
->Style
& WS_MAXIMIZE
))
1118 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1122 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1128 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1131 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1132 /* Don't activate the topmost window. */
1135 case SW_SHOWNOACTIVATE
:
1136 Swp
|= SWP_NOZORDER
;
1139 case SW_SHOWDEFAULT
:
1141 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1142 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1144 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1148 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1153 ShowFlag
= (Cmd
!= SW_HIDE
);
1154 if (ShowFlag
!= WasVisible
)
1156 IntSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0);
1158 * FIXME: Need to check the window wasn't destroyed during the
1163 /* We can't activate a child window */
1164 if ((Window
->Style
& WS_CHILD
) &&
1165 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1167 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1170 WinPosSetWindowPos(Window
->Self
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1171 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1175 /* FIXME: This will cause the window to be activated irrespective
1176 * of whether it is owned by the same thread. Has to be done
1180 if (Window
->Self
== NtUserGetActiveWindow())
1182 WinPosActivateOtherWindow(Window
);
1185 /* Revert focus to parent */
1186 if (Wnd
== IntGetThreadFocusWindow() ||
1187 IntIsChildWindow(Wnd
, IntGetThreadFocusWindow()))
1189 NtUserSetFocus(Window
->Parent
->Self
);
1193 /* FIXME: Check for window destruction. */
1195 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1197 WPARAM wParam
= SIZE_RESTORED
;
1199 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1200 if (Window
->Style
& WS_MAXIMIZE
)
1202 wParam
= SIZE_MAXIMIZED
;
1204 else if (Window
->Style
& WS_MINIMIZE
)
1206 wParam
= SIZE_MINIMIZED
;
1209 IntSendMessage(Wnd
, WM_SIZE
, wParam
,
1210 MAKELONG(Window
->ClientRect
.right
-
1211 Window
->ClientRect
.left
,
1212 Window
->ClientRect
.bottom
-
1213 Window
->ClientRect
.top
));
1214 IntSendMessage(Wnd
, WM_MOVE
, 0,
1215 MAKELONG(Window
->ClientRect
.left
,
1216 Window
->ClientRect
.top
));
1219 /* Activate the window if activation is not requested and the window is not minimized */
1221 if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->Style & WS_MINIMIZE))
1223 WinPosChangeActiveWindow(Wnd, FALSE);
1227 ObmDereferenceObject(Window
);
1231 BOOL STATIC FASTCALL
1232 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1234 return(Point
.x
>= Window
->WindowRect
.left
&&
1235 Point
.x
< Window
->WindowRect
.right
&&
1236 Point
.y
>= Window
->WindowRect
.top
&&
1237 Point
.y
< Window
->WindowRect
.bottom
);
1240 USHORT STATIC FASTCALL
1241 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1242 PWINDOW_OBJECT
* Window
)
1244 PWINDOW_OBJECT Current
;
1246 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1247 Current
= ScopeWin
->FirstChild
;
1250 if (Current
->Style
& WS_VISIBLE
&&
1251 ((!(Current
->Style
& WS_DISABLED
)) ||
1252 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1253 WinPosPtInWindow(Current
, Point
))
1256 ObmDereferenceObject(*Window
);
1257 ObmReferenceObjectByPointer(Current
, otWindow
);
1261 if (Current
->Style
& WS_DISABLED
)
1263 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1266 if (Point
.x
>= Current
->ClientRect
.left
&&
1267 Point
.x
< Current
->ClientRect
.right
&&
1268 Point
.y
>= Current
->ClientRect
.top
&&
1269 Point
.y
< Current
->ClientRect
.bottom
)
1272 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1273 return(WinPosSearchChildren(Current
, Point
, Window
));
1276 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1279 Current
= Current
->NextSibling
;
1282 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1287 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1288 PWINDOW_OBJECT
* Window
)
1290 HWND DesktopWindowHandle
;
1291 PWINDOW_OBJECT DesktopWindow
;
1292 POINT Point
= WinPoint
;
1299 DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
1303 if (ScopeWin
->Style
& WS_DISABLED
)
1308 /* Translate the point to the space of the scope window. */
1309 DesktopWindowHandle
= IntGetDesktopWindow();
1310 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1311 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1312 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1313 IntReleaseWindowObject(DesktopWindow
);
1315 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1321 if ((*Window
) == NULL
)
1325 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1327 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1328 MAKELONG(Point
.x
, Point
.y
));
1329 /* FIXME: Check for HTTRANSPARENT here. */
1341 NtUserGetMinMaxInfo(
1343 MINMAXINFO
*MinMaxInfo
,
1347 PINTERNALPOS InternalPos
;
1348 PWINDOW_OBJECT Window
;
1349 MINMAXINFO SafeMinMax
;
1352 Window
= IntGetWindowObject(hwnd
);
1355 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE
);
1359 Size
.x
= Window
->WindowRect
.left
;
1360 Size
.y
= Window
->WindowRect
.top
;
1361 InternalPos
= WinPosInitInternalPos(Window
, Size
,
1362 &Window
->WindowRect
);
1367 WinPosGetMinMaxInfo(Window
, &SafeMinMax
.ptMaxSize
, &SafeMinMax
.ptMaxPosition
,
1368 &SafeMinMax
.ptMinTrackSize
, &SafeMinMax
.ptMaxTrackSize
);
1372 WinPosFillMinMaxInfoStruct(Window
, &SafeMinMax
);
1374 Status
= MmCopyToCaller(MinMaxInfo
, &SafeMinMax
, sizeof(MINMAXINFO
));
1375 if(!NT_SUCCESS(Status
))
1377 IntReleaseWindowObject(Window
);
1378 SetLastNtError(Status
);
1381 IntReleaseWindowObject(Window
);
1385 IntReleaseWindowObject(Window
);