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.41 2003/11/18 20:49:39 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 <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>
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>
50 /* GLOBALS *******************************************************************/
52 #define MINMAX_NOSWP (0x00010000)
54 #define SWP_EX_NOCOPY 0x0001
55 #define SWP_EX_PAINTSELF 0x0002
57 #define SWP_AGG_NOGEOMETRYCHANGE \
58 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
59 #define SWP_AGG_NOPOSCHANGE \
60 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
61 #define SWP_AGG_STATUSFLAGS \
62 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
64 ATOM AtomInternalPos
= (ATOM
) NULL
;
66 /* FUNCTIONS *****************************************************************/
68 #define HAS_DLGFRAME(Style, ExStyle) \
69 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
70 (((Style) & WS_DLGFRAME) && !((Style) & WS_BORDER)))
72 #define HAS_THICKFRAME(Style, ExStyle) \
73 (((Style) & WS_THICKFRAME) && \
74 !((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)
77 WinPosSetupInternalPos(VOID
)
79 AtomInternalPos
= NtAddAtom(L
"SysIP", (ATOM
*)(PULONG
)&AtomInternalPos
);
83 NtUserGetClientOrigin(HWND hWnd
, LPPOINT Point
)
85 PWINDOW_OBJECT WindowObject
;
87 WindowObject
= IntGetWindowObject(hWnd
);
88 if (WindowObject
== NULL
)
90 Point
->x
= Point
->y
= 0;
93 Point
->x
= WindowObject
->ClientRect
.left
;
94 Point
->y
= WindowObject
->ClientRect
.top
;
98 /*******************************************************************
101 * Check if we can activate the specified window.
104 can_activate_window(HWND hwnd
)
112 style
= NtUserGetWindowLong(hwnd
, GWL_STYLE
, FALSE
);
113 if (! (style
& WS_VISIBLE
))
117 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
)
121 return ! (style
& WS_DISABLED
);
124 /*******************************************************************
125 * WinPosActivateOtherWindow
127 * Activates window other than pWnd.
130 WinPosActivateOtherWindow(PWINDOW_OBJECT Window
)
137 if ((NtUserGetWindowLong(Window
->Self
, GWL_STYLE
, FALSE
) & WS_POPUP
)
138 && (hwndTo
= NtUserGetWindow(Window
->Self
, GW_OWNER
)))
140 hwndTo
= NtUserGetAncestor(hwndTo
, GA_ROOT
);
141 if (can_activate_window(hwndTo
)) goto done
;
144 hwndTo
= Window
->Self
;
147 if (!(hwndTo
= NtUserGetWindow(hwndTo
, GW_HWNDNEXT
)))
151 if (can_activate_window(hwndTo
))
159 fg
= NtUserGetForegroundWindow();
160 /* TRACE("win = %p fg = %p\n", hwndTo, fg); */
161 if (! fg
|| (hwnd
== fg
))
163 if (NtUserSetForegroundWindow(hwndTo
))
170 if (! NtUserSetActiveWindow(hwndTo
))
172 NtUserSetActiveWindow(NULL
);
176 POINT STATIC FASTCALL
177 WinPosFindIconPos(HWND hWnd
, POINT Pos
)
185 WinPosNtGdiIconTitle(PWINDOW_OBJECT WindowObject
)
191 WinPosShowIconTitle(PWINDOW_OBJECT WindowObject
, BOOL Show
)
193 PINTERNALPOS InternalPos
= (PINTERNALPOS
)IntGetProp(WindowObject
, AtomInternalPos
);
194 PWINDOW_OBJECT IconWindow
;
199 HWND hWnd
= InternalPos
->IconTitle
;
203 hWnd
= WinPosNtGdiIconTitle(WindowObject
);
208 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->
212 (PVOID
*)&IconWindow
);
213 if (NT_SUCCESS(Status
))
215 if (!(IconWindow
->Style
& WS_VISIBLE
))
217 NtUserSendMessage(hWnd
, WM_SHOWWINDOW
, TRUE
, 0);
218 WinPosSetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
|
219 SWP_NOMOVE
| SWP_NOACTIVATE
|
220 SWP_NOZORDER
| SWP_SHOWWINDOW
);
222 ObmDereferenceObject(IconWindow
);
227 WinPosShowWindow(hWnd
, SW_HIDE
);
233 PINTERNALPOS STATIC STDCALL
234 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject
, POINT pt
, PRECT RestoreRect
)
236 PINTERNALPOS InternalPos
= (PINTERNALPOS
)IntGetProp(WindowObject
, AtomInternalPos
);
237 if (InternalPos
== NULL
)
240 ExAllocatePool(NonPagedPool
, sizeof(INTERNALPOS
));
241 IntSetProp(WindowObject
, AtomInternalPos
, InternalPos
);
242 InternalPos
->IconTitle
= 0;
243 InternalPos
->NormalRect
= WindowObject
->WindowRect
;
244 InternalPos
->IconPos
.x
= InternalPos
->MaxPos
.x
= 0xFFFFFFFF;
245 InternalPos
->IconPos
.y
= InternalPos
->MaxPos
.y
= 0xFFFFFFFF;
247 if (WindowObject
->Style
& WS_MINIMIZE
)
249 InternalPos
->IconPos
= pt
;
251 else if (WindowObject
->Style
& WS_MAXIMIZE
)
253 InternalPos
->MaxPos
= pt
;
255 else if (RestoreRect
!= NULL
)
257 InternalPos
->NormalRect
= *RestoreRect
;
263 WinPosMinMaximize(PWINDOW_OBJECT WindowObject
, UINT ShowFlag
, RECT
* NewPos
)
266 PINTERNALPOS InternalPos
;
269 Size
.x
= WindowObject
->WindowRect
.left
;
270 Size
.y
= WindowObject
->WindowRect
.top
;
271 InternalPos
= WinPosInitInternalPos(WindowObject
, Size
,
272 &WindowObject
->WindowRect
);
276 if (WindowObject
->Style
& WS_MINIMIZE
)
278 if (!NtUserSendMessage(WindowObject
->Self
, WM_QUERYOPEN
, 0, 0))
280 return(SWP_NOSIZE
| SWP_NOMOVE
);
282 SwpFlags
|= SWP_NOCOPYBITS
;
288 if (WindowObject
->Style
& WS_MAXIMIZE
)
290 WindowObject
->Flags
|= WINDOWOBJECT_RESTOREMAX
;
291 WindowObject
->Style
&= ~WS_MAXIMIZE
;
295 WindowObject
->Style
&= ~WINDOWOBJECT_RESTOREMAX
;
297 WindowObject
->Style
|= WS_MINIMIZE
;
298 InternalPos
->IconPos
= WinPosFindIconPos(WindowObject
,
299 InternalPos
->IconPos
);
300 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
301 NtUserGetSystemMetrics(SM_CXICON
),
302 NtUserGetSystemMetrics(SM_CYICON
));
303 SwpFlags
|= SWP_NOCOPYBITS
;
309 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
311 if (WindowObject
->Style
& WS_MINIMIZE
)
313 WinPosShowIconTitle(WindowObject
, FALSE
);
314 WindowObject
->Style
&= ~WS_MINIMIZE
;
316 WindowObject
->Style
|= WS_MINIMIZE
;
317 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
,
324 if (WindowObject
->Style
& WS_MINIMIZE
)
326 WindowObject
->Style
&= ~WS_MINIMIZE
;
327 WinPosShowIconTitle(WindowObject
, FALSE
);
328 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
330 WinPosGetMinMaxInfo(WindowObject
, &Size
,
331 &InternalPos
->MaxPos
, NULL
, NULL
);
332 WindowObject
->Style
|= WS_MAXIMIZE
;
333 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
334 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
340 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
346 WindowObject
->Style
&= ~WS_MAXIMIZE
;
348 *NewPos
= InternalPos
->NormalRect
;
349 NewPos
->right
-= NewPos
->left
;
350 NewPos
->bottom
-= NewPos
->top
;
358 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
364 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
365 POINT
* MinTrack
, POINT
* MaxTrack
)
371 /* Get default values. */
372 MinMax
.ptMaxSize
.x
= NtUserGetSystemMetrics(SM_CXSCREEN
);
373 MinMax
.ptMaxSize
.y
= NtUserGetSystemMetrics(SM_CYSCREEN
);
374 MinMax
.ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
375 MinMax
.ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
376 MinMax
.ptMaxTrackSize
.x
= NtUserGetSystemMetrics(SM_CXSCREEN
);
377 MinMax
.ptMaxTrackSize
.y
= NtUserGetSystemMetrics(SM_CYSCREEN
);
379 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
381 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
382 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
387 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
389 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
390 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
392 if (Window
->Style
& WS_BORDER
)
394 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
395 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
398 MinMax
.ptMaxSize
.x
+= 2 * XInc
;
399 MinMax
.ptMaxSize
.y
+= 2 * YInc
;
401 Pos
= (PINTERNALPOS
)IntGetProp(Window
, AtomInternalPos
);
404 MinMax
.ptMaxPosition
= Pos
->MaxPos
;
408 MinMax
.ptMaxPosition
.x
-= XInc
;
409 MinMax
.ptMaxPosition
.y
-= YInc
;
412 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
, TRUE
);
414 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
415 MinMax
.ptMinTrackSize
.x
);
416 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
417 MinMax
.ptMinTrackSize
.y
);
419 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
420 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
421 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
422 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
424 return 0; //FIXME: what does it return?
428 WinPosChangeActiveWindow(HWND hWnd
, BOOL MouseMsg
)
430 PWINDOW_OBJECT WindowObject
;
432 WindowObject
= IntGetWindowObject(hWnd
);
433 if (WindowObject
== NULL
)
438 NtUserSendMessage(hWnd
,
440 MAKELONG(MouseMsg
? WA_CLICKACTIVE
: WA_CLICKACTIVE
,
441 (WindowObject
->Style
& WS_MINIMIZE
) ? 1 : 0),
442 (LPARAM
)IntGetDesktopWindow()); /* FIXME: Previous active window */
444 IntReleaseWindowObject(WindowObject
);
450 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
451 RECT
* WindowRect
, RECT
* ClientRect
)
455 /* Send WM_NCCALCSIZE message to get new client area */
456 if ((WinPos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
458 NCCALCSIZE_PARAMS params
;
459 WINDOWPOS winposCopy
;
461 params
.rgrc
[0] = *WindowRect
;
462 params
.rgrc
[1] = Window
->WindowRect
;
463 params
.rgrc
[2] = Window
->ClientRect
;
464 if (0 != (Window
->Style
& WS_CHILD
))
466 NtGdiOffsetRect(&(params
.rgrc
[0]), - Window
->Parent
->ClientRect
.left
,
467 - Window
->Parent
->ClientRect
.top
);
468 NtGdiOffsetRect(&(params
.rgrc
[1]), - Window
->Parent
->ClientRect
.left
,
469 - Window
->Parent
->ClientRect
.top
);
470 NtGdiOffsetRect(&(params
.rgrc
[2]), - Window
->Parent
->ClientRect
.left
,
471 - Window
->Parent
->ClientRect
.top
);
473 params
.lppos
= &winposCopy
;
474 winposCopy
= *WinPos
;
476 wvrFlags
= IntSendNCCALCSIZEMessage(Window
->Self
, TRUE
, NULL
, ¶ms
);
478 /* If the application send back garbage, ignore it */
479 if (params
.rgrc
[0].left
<= params
.rgrc
[0].right
&&
480 params
.rgrc
[0].top
<= params
.rgrc
[0].bottom
)
482 *ClientRect
= params
.rgrc
[0];
483 if (Window
->Style
& WS_CHILD
)
485 NtGdiOffsetRect(ClientRect
, Window
->Parent
->ClientRect
.left
,
486 Window
->Parent
->ClientRect
.top
);
490 /* FIXME: WVR_ALIGNxxx */
492 if (ClientRect
->left
!= Window
->ClientRect
.left
||
493 ClientRect
->top
!= Window
->ClientRect
.top
)
495 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
498 if ((ClientRect
->right
- ClientRect
->left
!=
499 Window
->ClientRect
.right
- Window
->ClientRect
.left
) ||
500 (ClientRect
->bottom
- ClientRect
->top
!=
501 Window
->ClientRect
.bottom
- Window
->ClientRect
.top
))
503 WinPos
->flags
&= ~SWP_NOCLIENTSIZE
;
508 if (! (WinPos
->flags
& SWP_NOMOVE
)
509 && (ClientRect
->left
!= Window
->ClientRect
.left
||
510 ClientRect
->top
!= Window
->ClientRect
.top
))
512 WinPos
->flags
&= ~SWP_NOCLIENTMOVE
;
520 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
527 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
529 IntSendWINDOWPOSCHANGINGMessage(WindowObject
->Self
, WinPos
);
532 *WindowRect
= WindowObject
->WindowRect
;
534 (WindowObject
->Style
& WS_MINIMIZE
) ? WindowObject
->WindowRect
:
535 WindowObject
->ClientRect
;
537 if (!(WinPos
->flags
& SWP_NOSIZE
))
539 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
540 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
543 if (!(WinPos
->flags
& SWP_NOMOVE
))
547 if (0 != (WindowObject
->Style
& WS_CHILD
))
549 X
+= WindowObject
->Parent
->ClientRect
.left
;
550 Y
+= WindowObject
->Parent
->ClientRect
.top
;
552 WindowRect
->left
= X
;
554 WindowRect
->right
+= X
- WindowObject
->WindowRect
.left
;
555 WindowRect
->bottom
+= Y
- WindowObject
->WindowRect
.top
;
556 NtGdiOffsetRect(ClientRect
,
557 X
- WindowObject
->WindowRect
.left
,
558 Y
- WindowObject
->WindowRect
.top
);
561 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
567 * Fix Z order taking into account owned popups -
568 * basically we need to maintain them above the window that owns them
571 WinPosDoOwnedPopups(HWND hWnd
, HWND hWndInsertAfter
)
574 return hWndInsertAfter
;
577 /***********************************************************************
578 * WinPosInternalMoveWindow
580 * Update WindowRect and ClientRect of Window and all of its children
581 * We keep both WindowRect and ClientRect in screen coordinates internally
584 WinPosInternalMoveWindow(PWINDOW_OBJECT Window
, INT MoveX
, INT MoveY
)
586 PWINDOW_OBJECT Child
;
588 Window
->WindowRect
.left
+= MoveX
;
589 Window
->WindowRect
.right
+= MoveX
;
590 Window
->WindowRect
.top
+= MoveY
;
591 Window
->WindowRect
.bottom
+= MoveY
;
593 Window
->ClientRect
.left
+= MoveX
;
594 Window
->ClientRect
.right
+= MoveX
;
595 Window
->ClientRect
.top
+= MoveY
;
596 Window
->ClientRect
.bottom
+= MoveY
;
598 ExAcquireFastMutexUnsafe(&Window
->ChildrenListLock
);
599 Child
= Window
->FirstChild
;
602 WinPosInternalMoveWindow(Child
, MoveX
, MoveY
);
603 Child
= Child
->NextSibling
;
605 ExReleaseFastMutexUnsafe(&Window
->ChildrenListLock
);
609 /* x and y are always screen relative */
611 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
614 PWINDOW_OBJECT Window
;
619 HRGN VisBefore
= NULL
;
620 HRGN VisAfter
= NULL
;
621 HRGN DirtyRgn
= NULL
;
622 HRGN ExposedRgn
= NULL
;
625 RECT OldWindowRect
, OldClientRect
;
632 /* FIXME: Get current active window from active queue. */
634 /* Check if the window is for a desktop. */
635 if (Wnd
== PsGetWin32Thread()->Desktop
->DesktopWindow
)
641 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
645 if (!NT_SUCCESS(Status
))
650 /* Fix up the flags. */
651 if (Window
->Style
& WS_VISIBLE
)
653 flags
&= ~SWP_SHOWWINDOW
;
657 if (!(flags
& SWP_SHOWWINDOW
))
659 flags
|= SWP_NOREDRAW
;
661 flags
&= ~SWP_HIDEWINDOW
;
667 if ((Window
->WindowRect
.right
- Window
->WindowRect
.left
) == cx
&&
668 (Window
->WindowRect
.bottom
- Window
->WindowRect
.top
) == cy
)
672 if (Window
->WindowRect
.left
== x
&& Window
->WindowRect
.top
== y
)
676 if (Window
->Flags
& WIN_NCACTIVATED
)
678 flags
|= SWP_NOACTIVATE
;
680 else if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
682 if (!(flags
& SWP_NOACTIVATE
))
684 flags
&= ~SWP_NOZORDER
;
685 WndInsertAfter
= HWND_TOP
;
689 if (WndInsertAfter
== HWND_TOPMOST
|| WndInsertAfter
== HWND_NOTOPMOST
)
691 WndInsertAfter
= HWND_TOP
;
694 if (WndInsertAfter
!= HWND_TOP
&& WndInsertAfter
!= HWND_BOTTOM
)
696 if (NtUserGetAncestor(WndInsertAfter
, GA_PARENT
) != Window
->Parent
)
698 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
704 * Don't need to change the Zorder of hwnd if it's already inserted
705 * after hwndInsertAfter or when inserting hwnd after itself.
707 if (Wnd
== WndInsertAfter
||
708 Wnd
== NtUserGetWindow(WndInsertAfter
, GW_HWNDNEXT
))
710 flags
|= SWP_NOZORDER
;
716 WinPos
.hwndInsertAfter
= WndInsertAfter
;
721 WinPos
.flags
= flags
;
722 if (0 != (Window
->Style
& WS_CHILD
))
724 WinPos
.x
-= Window
->Parent
->ClientRect
.left
;
725 WinPos
.y
-= Window
->Parent
->ClientRect
.top
;
728 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
730 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
732 NtUserGetAncestor(WinPos
.hwnd
, GA_PARENT
) ==
733 PsGetWin32Thread()->Desktop
->DesktopWindow
)
735 WinPos
.hwndInsertAfter
= WinPosDoOwnedPopups(WinPos
.hwnd
, WinPos
.hwndInsertAfter
);
738 /* FIXME: Adjust flags based on WndInsertAfter */
740 /* Compute the visible region before the window position is changed */
741 if ((!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
742 WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
743 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
744 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
746 if (Window
->Style
& WS_CLIPCHILDREN
)
748 VisBefore
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
,
749 Window
, FALSE
, FALSE
, TRUE
);
753 VisBefore
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
,
754 Window
, FALSE
, FALSE
, FALSE
);
756 if (NULLREGION
== UnsafeIntGetRgnBox(VisBefore
, &TempRect
))
758 NtGdiDeleteObject(VisBefore
);
763 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
,
767 * FIXME: Relink windows. (also take into account shell window in hwndShellWindow)
769 if (!(WinPos
.flags
& SWP_NOZORDER
) && WinPos
.hwndInsertAfter
!= WinPos
.hwnd
&&
770 WinPos
.hwnd
!= NtUserGetShellWindow())
772 PWINDOW_OBJECT ParentWindow
;
773 PWINDOW_OBJECT InsertAfterWindow
;
775 ParentWindow
= Window
->Parent
;
778 if (WndInsertAfter
== HWND_TOP
)
779 InsertAfterWindow
= NULL
;
780 else if (WndInsertAfter
== HWND_BOTTOM
)
781 InsertAfterWindow
= ParentWindow
->LastChild
;
783 InsertAfterWindow
= IntGetWindowObject(WinPos
.hwndInsertAfter
);
784 ExAcquireFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
785 IntUnlinkWindow(Window
);
786 IntLinkWindow(Window
, ParentWindow
, InsertAfterWindow
);
787 ExReleaseFastMutexUnsafe(&ParentWindow
->ChildrenListLock
);
788 if (InsertAfterWindow
!= NULL
)
789 IntReleaseWindowObject(InsertAfterWindow
);
793 /* FIXME: Reset active DCEs */
795 OldWindowRect
= Window
->WindowRect
;
796 OldClientRect
= Window
->ClientRect
;
798 /* FIXME: Check for redrawing the whole client rect. */
800 if (! (WinPos
.flags
& SWP_NOMOVE
))
802 WinPosInternalMoveWindow(Window
,
803 NewWindowRect
.left
- OldWindowRect
.left
,
804 NewWindowRect
.top
- OldWindowRect
.top
);
806 Window
->WindowRect
= NewWindowRect
;
807 Window
->ClientRect
= NewClientRect
;
809 if (WinPos
.flags
& SWP_SHOWWINDOW
)
811 Window
->Style
|= WS_VISIBLE
;
812 FlagsEx
|= SWP_EX_PAINTSELF
;
814 else if (WinPos
.flags
& SWP_HIDEWINDOW
)
816 Window
->Style
&= ~WS_VISIBLE
;
819 if (!(WinPos
.flags
& SWP_NOREDRAW
))
821 /* Determine the new visible region */
822 if (Window
->Style
& WS_CLIPCHILDREN
)
824 VisAfter
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
,
825 Window
, FALSE
, FALSE
, TRUE
);
829 VisAfter
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
,
830 Window
, FALSE
, FALSE
, FALSE
);
832 if (NULLREGION
== UnsafeIntGetRgnBox(VisAfter
, &TempRect
))
834 NtGdiDeleteObject(VisAfter
);
838 /* Determine which pixels can be copied from the old window position
839 to the new. Those pixels must be visible in both the old and new
840 position. Also, check the class style to see if the windows of this
841 class need to be completely repainted on (horizontal/vertical) size
843 if (NULL
!= VisBefore
&& NULL
!= VisAfter
&& ! (WinPos
.flags
& SWP_NOCOPYBITS
)
844 && ((WinPos
.flags
& SWP_NOSIZE
)
845 || ! (Window
->Class
->style
& (CS_HREDRAW
| CS_VREDRAW
))))
847 CopyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
848 RgnType
= NtGdiCombineRgn(CopyRgn
, VisAfter
, VisBefore
, RGN_AND
);
850 /* If this is (also) a window resize, the whole nonclient area
851 needs to be repainted. So we limit the copy to the client area,
852 'cause there is no use in copying it (would possibly cause
853 "flashing" too). However, if the copy region is already empty,
854 we don't have to crop (can't take anything away from an empty
856 if (! (WinPos
.flags
& SWP_NOSIZE
)
857 && ERROR
!= RgnType
&& NULLREGION
!= RgnType
)
859 RECT ORect
= OldClientRect
;
860 RECT NRect
= NewClientRect
;
861 NtGdiOffsetRect(&ORect
, - OldWindowRect
.left
, - OldWindowRect
.top
);
862 NtGdiOffsetRect(&NRect
, - NewWindowRect
.left
, - NewWindowRect
.top
);
863 NtGdiIntersectRect(&CopyRect
, &ORect
, &NRect
);
864 REGION_CropRgn(CopyRgn
, CopyRgn
, &CopyRect
, NULL
);
867 /* No use in copying bits which are in the update region. */
868 if ((HRGN
) 1 == Window
->UpdateRegion
)
870 /* The whole window is in the update region. No use
871 copying anything, so set the copy region empty */
872 NtGdiSetRectRgn(CopyRgn
, 0, 0, 0, 0);
874 else if (1 < (DWORD
) Window
->UpdateRegion
)
876 NtGdiCombineRgn(CopyRgn
, CopyRgn
, Window
->UpdateRegion
, RGN_DIFF
);
880 /* Now, get the bounding box of the copy region. If it's empty
881 there's nothing to copy. Also, it's no use copying bits onto
883 UnsafeIntGetRgnBox(CopyRgn
, &CopyRect
);
884 if (NtGdiIsEmptyRect(&CopyRect
))
886 /* Nothing to copy, clean up */
887 NtGdiDeleteObject(CopyRgn
);
890 else if (OldWindowRect
.left
!= NewWindowRect
.left
891 || OldWindowRect
.top
!= NewWindowRect
.top
)
893 /* Small trick here: there is no function to bitblt a region. So
894 we set the region as the clipping region, take the bounding box
895 of the region and bitblt that. Since nothing outside the clipping
896 region is copied, this has the effect of bitblt'ing the region.
898 Since NtUserGetDCEx takes ownership of the clip region, we need
899 to create a copy of CopyRgn and pass that. We need CopyRgn later */
900 HRGN ClipRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
901 NtGdiCombineRgn(ClipRgn
, CopyRgn
, NULL
, RGN_COPY
);
902 Dc
= NtUserGetDCEx(Wnd
, ClipRgn
, DCX_WINDOW
| DCX_CACHE
|
903 DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
904 NtGdiBitBlt(Dc
, CopyRect
.left
, CopyRect
.top
, CopyRect
.right
- CopyRect
.left
,
905 CopyRect
.bottom
- CopyRect
.top
, Dc
,
906 CopyRect
.left
+ (OldWindowRect
.left
- NewWindowRect
.left
),
907 CopyRect
.top
+ (OldWindowRect
.top
- NewWindowRect
.top
), SRCCOPY
);
908 NtUserReleaseDC(Wnd
, Dc
);
916 /* We need to redraw what wasn't visible before */
917 if (NULL
!= VisAfter
)
921 DirtyRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
922 RgnType
= NtGdiCombineRgn(DirtyRgn
, VisAfter
, CopyRgn
, RGN_DIFF
);
923 if (ERROR
!= RgnType
&& NULLREGION
!= RgnType
)
925 IntRedrawWindow(Window
, NULL
, DirtyRgn
,
926 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
|
927 RDW_ALLCHILDREN
| RDW_ERASENOW
);
929 NtGdiDeleteObject(DirtyRgn
);
933 IntRedrawWindow(Window
, NULL
, NULL
,
934 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
|
935 RDW_ALLCHILDREN
| RDW_ERASENOW
);
941 NtGdiDeleteObject(CopyRgn
);
945 /* Expose what was covered before but not covered anymore */
946 if (NULL
!= VisBefore
)
948 ExposedRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
949 NtGdiCombineRgn(ExposedRgn
, VisBefore
, NULL
, RGN_COPY
);
950 NtGdiOffsetRgn(ExposedRgn
, OldWindowRect
.left
- NewWindowRect
.left
,
951 OldWindowRect
.top
- NewWindowRect
.top
);
952 if (NULL
!= VisAfter
)
954 RgnType
= NtGdiCombineRgn(ExposedRgn
, ExposedRgn
, VisAfter
, RGN_DIFF
);
958 RgnType
= SIMPLEREGION
;
960 if (ERROR
!= RgnType
&& NULLREGION
!= RgnType
)
962 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
, ExposedRgn
);
964 NtGdiDeleteObject(ExposedRgn
);
966 NtGdiDeleteObject(VisBefore
);
969 if (NULL
!= VisAfter
)
971 NtGdiDeleteObject(VisAfter
);
974 /* FIXME: Hide or show the claret */
976 if (!(flags
& SWP_NOACTIVATE
))
978 WinPosChangeActiveWindow(WinPos
.hwnd
, FALSE
);
981 /* FIXME: Check some conditions before doing this. */
982 IntSendWINDOWPOSCHANGEDMessage(WinPos
.hwnd
, &WinPos
);
984 IntReleaseWindowObject(Window
);
989 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
991 *ClientRect
= *WindowRect
;
992 return(IntSendNCCALCSIZEMessage(Wnd
, FALSE
, ClientRect
, NULL
));
996 WinPosShowWindow(HWND Wnd
, INT Cmd
)
999 PWINDOW_OBJECT Window
;
1001 RECT NewPos
= {0, 0, 0, 0};
1003 /* HRGN VisibleRgn;*/
1005 Window
= IntGetWindowObject(Wnd
);
1011 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
1019 ObmDereferenceObject(Window
);
1022 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
1027 case SW_SHOWMINNOACTIVE
:
1028 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1030 case SW_SHOWMINIMIZED
:
1031 Swp
|= SWP_SHOWWINDOW
;
1035 Swp
|= SWP_FRAMECHANGED
;
1036 if (!(Window
->Style
& WS_MINIMIZE
))
1038 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
1042 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1047 case SW_SHOWMAXIMIZED
:
1049 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1050 if (!(Window
->Style
& WS_MAXIMIZE
))
1052 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
1056 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1062 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1065 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
1066 /* Don't activate the topmost window. */
1069 case SW_SHOWNOACTIVATE
:
1070 Swp
|= SWP_NOZORDER
;
1073 case SW_SHOWDEFAULT
:
1075 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1076 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1078 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1082 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1087 ShowFlag
= (Cmd
!= SW_HIDE
);
1088 if (ShowFlag
!= WasVisible
)
1090 NtUserSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0);
1092 * FIXME: Need to check the window wasn't destroyed during the
1097 /* We can't activate a child window */
1098 if ((Window
->Style
& WS_CHILD
) &&
1099 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1101 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1104 WinPosSetWindowPos(Wnd
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1105 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1109 /* FIXME: This will cause the window to be activated irrespective
1110 * of whether it is owned by the same thread. Has to be done
1114 if (Wnd
== IntGetActiveWindow())
1116 WinPosActivateOtherWindow(Window
);
1119 /* Revert focus to parent */
1120 if (Wnd
== IntGetFocusWindow() ||
1121 IntIsChildWindow(Wnd
, IntGetFocusWindow()))
1123 IntSetFocusWindow(Window
->Parent
->Self
);
1127 if (!IntIsWindow(Wnd
))
1129 IntReleaseWindowObject(Window
);
1132 else if (Window
->Style
& WS_MINIMIZE
)
1134 WinPosShowIconTitle(Window
, TRUE
);
1137 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1139 /* should happen only in CreateWindowEx() */
1140 int wParam
= SIZE_RESTORED
;
1142 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1143 if (Window
->Style
& WS_MAXIMIZE
)
1145 wParam
= SIZE_MAXIMIZED
;
1147 else if (Window
->Style
& WS_MINIMIZE
)
1149 wParam
= SIZE_MINIMIZED
;
1152 NtUserSendMessage(Wnd
, WM_SIZE
, wParam
,
1153 MAKELONG(Window
->ClientRect
.right
-
1154 Window
->ClientRect
.left
,
1155 Window
->ClientRect
.bottom
-
1156 Window
->ClientRect
.top
));
1157 NtUserSendMessage(Wnd
, WM_MOVE
, 0,
1158 MAKELONG(Window
->ClientRect
.left
,
1159 Window
->ClientRect
.top
));
1162 /* Activate the window if activation is not requested and the window is not minimized */
1163 if (!(Swp
& (SWP_NOACTIVATE
| SWP_HIDEWINDOW
)) && !(Window
->Style
& WS_MINIMIZE
))
1165 WinPosChangeActiveWindow(Wnd
, FALSE
);
1168 IntReleaseWindowObject(Window
);
1172 BOOL STATIC FASTCALL
1173 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1175 return(Point
.x
>= Window
->WindowRect
.left
&&
1176 Point
.x
< Window
->WindowRect
.right
&&
1177 Point
.y
>= Window
->WindowRect
.top
&&
1178 Point
.y
< Window
->WindowRect
.bottom
);
1181 USHORT STATIC STDCALL
1182 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1183 PWINDOW_OBJECT
* Window
)
1185 PWINDOW_OBJECT Current
;
1187 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1188 Current
= ScopeWin
->FirstChild
;
1191 if (Current
->Style
& WS_VISIBLE
&&
1192 ((!(Current
->Style
& WS_DISABLED
)) ||
1193 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1194 WinPosPtInWindow(Current
, Point
))
1197 if (Current
->Style
& WS_DISABLED
)
1199 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1202 if (Current
->Style
& WS_MINIMIZE
)
1204 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1207 if (Point
.x
>= Current
->ClientRect
.left
&&
1208 Point
.x
< Current
->ClientRect
.right
&&
1209 Point
.y
>= Current
->ClientRect
.top
&&
1210 Point
.y
< Current
->ClientRect
.bottom
)
1213 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1214 return(WinPosSearchChildren(Current
, Point
, Window
));
1217 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1220 Current
= Current
->NextSibling
;
1223 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1228 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1229 PWINDOW_OBJECT
* Window
)
1231 HWND DesktopWindowHandle
;
1232 PWINDOW_OBJECT DesktopWindow
;
1233 POINT Point
= WinPoint
;
1238 if (ScopeWin
->Style
& WS_DISABLED
)
1243 /* Translate the point to the space of the scope window. */
1244 DesktopWindowHandle
= IntGetDesktopWindow();
1245 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1246 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1247 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1248 IntReleaseWindowObject(DesktopWindow
);
1250 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1256 if ((*Window
) == NULL
)
1260 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1262 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1263 MAKELONG(Point
.x
, Point
.y
), FALSE
);
1264 /* FIXME: Check for HTTRANSPARENT here. */
1275 WinPosSetActiveWindow(PWINDOW_OBJECT Window
, BOOL Mouse
, BOOL ChangeFocus
)
1277 PUSER_MESSAGE_QUEUE ActiveQueue
;
1280 ActiveQueue
= IntGetFocusMessageQueue();
1281 if (ActiveQueue
!= NULL
)
1283 PrevActive
= ActiveQueue
->ActiveWindow
;
1290 if (Window
->Self
== IntGetActiveDesktop() || Window
->Self
== PrevActive
)
1294 if (PrevActive
!= NULL
)
1296 PWINDOW_OBJECT PrevActiveWindow
= IntGetWindowObject(PrevActive
);
1297 if(PrevActiveWindow
)
1299 WORD Iconised
= HIWORD(PrevActiveWindow
->Style
& WS_MINIMIZE
);
1300 if (!IntSendMessage(PrevActive
, WM_NCACTIVATE
, FALSE
, 0, TRUE
))
1302 /* FIXME: Check if the new window is system modal. */
1305 IntSendMessage(PrevActive
,
1307 MAKEWPARAM(WA_INACTIVE
, Iconised
),
1308 (LPARAM
)Window
->Self
,
1310 /* FIXME: Check if anything changed while processing the message. */
1311 IntReleaseWindowObject(PrevActiveWindow
);
1316 ActiveQueue
->ActiveWindow
= NULL
;
1323 Window
->MessageQueue
->ActiveWindow
= Window
->Self
;
1325 else if (ActiveQueue
!= NULL
)
1327 ActiveQueue
->ActiveWindow
= NULL
;
1329 /* FIXME: Unset this flag for inactive windows */
1330 //if ((Window->Style) & WS_CHILD) Window->Flags |= WIN_NCACTIVATED;
1332 /* FIXME: Send palette messages. */
1334 /* FIXME: Redraw icon title of previously active window. */
1336 /* FIXME: Bring the window to the top. */
1338 /* FIXME: Send WM_ACTIVATEAPP */
1340 IntSetFocusMessageQueue(Window
->MessageQueue
);
1342 /* FIXME: Send activate messages. */
1344 /* FIXME: Change focus. */
1346 /* FIXME: Redraw new window icon title. */
1352 NtUserGetActiveWindow(VOID
)
1354 PUSER_MESSAGE_QUEUE ActiveQueue
;
1356 ActiveQueue
= IntGetFocusMessageQueue();
1357 if (ActiveQueue
== NULL
)
1361 return(ActiveQueue
->ActiveWindow
);
1365 NtUserSetActiveWindow(HWND hWnd
)
1367 PWINDOW_OBJECT Window
;
1368 PUSER_MESSAGE_QUEUE ThreadQueue
;
1371 Window
= IntGetWindowObject(hWnd
);
1372 if (Window
== NULL
|| (Window
->Style
& (WS_DISABLED
| WS_CHILD
)))
1374 IntReleaseWindowObject(Window
);
1377 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
1378 if (Window
->MessageQueue
!= ThreadQueue
)
1380 IntReleaseWindowObject(Window
);
1383 Prev
= Window
->MessageQueue
->ActiveWindow
;
1384 WinPosSetActiveWindow(Window
, FALSE
, FALSE
);
1385 IntReleaseWindowObject(Window
);