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.26 2003/08/20 07:45:01 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 <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
;
99 WinPosActivateOtherWindow(PWINDOW_OBJECT Window
)
104 POINT STATIC FASTCALL
105 WinPosFindIconPos(HWND hWnd
, POINT Pos
)
113 WinPosNtGdiIconTitle(PWINDOW_OBJECT WindowObject
)
119 WinPosShowIconTitle(PWINDOW_OBJECT WindowObject
, BOOL Show
)
121 PINTERNALPOS InternalPos
= (PINTERNALPOS
)IntGetProp(WindowObject
, AtomInternalPos
);
122 PWINDOW_OBJECT IconWindow
;
127 HWND hWnd
= InternalPos
->IconTitle
;
131 hWnd
= WinPosNtGdiIconTitle(WindowObject
);
136 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->
140 (PVOID
*)&IconWindow
);
141 if (NT_SUCCESS(Status
))
143 if (!(IconWindow
->Style
& WS_VISIBLE
))
145 NtUserSendMessage(hWnd
, WM_SHOWWINDOW
, TRUE
, 0);
146 WinPosSetWindowPos(hWnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
|
147 SWP_NOMOVE
| SWP_NOACTIVATE
|
148 SWP_NOZORDER
| SWP_SHOWWINDOW
);
150 ObmDereferenceObject(IconWindow
);
155 WinPosShowWindow(hWnd
, SW_HIDE
);
161 PINTERNALPOS STATIC STDCALL
162 WinPosInitInternalPos(PWINDOW_OBJECT WindowObject
, POINT pt
, PRECT RestoreRect
)
164 PINTERNALPOS InternalPos
= (PINTERNALPOS
)IntGetProp(WindowObject
, AtomInternalPos
);
165 if (InternalPos
== NULL
)
168 ExAllocatePool(NonPagedPool
, sizeof(INTERNALPOS
));
169 IntSetProp(WindowObject
, AtomInternalPos
, InternalPos
);
170 InternalPos
->IconTitle
= 0;
171 InternalPos
->NormalRect
= WindowObject
->WindowRect
;
172 InternalPos
->IconPos
.x
= InternalPos
->MaxPos
.x
= 0xFFFFFFFF;
173 InternalPos
->IconPos
.y
= InternalPos
->MaxPos
.y
= 0xFFFFFFFF;
175 if (WindowObject
->Style
& WS_MINIMIZE
)
177 InternalPos
->IconPos
= pt
;
179 else if (WindowObject
->Style
& WS_MAXIMIZE
)
181 InternalPos
->MaxPos
= pt
;
183 else if (RestoreRect
!= NULL
)
185 InternalPos
->NormalRect
= *RestoreRect
;
191 WinPosMinMaximize(PWINDOW_OBJECT WindowObject
, UINT ShowFlag
, RECT
* NewPos
)
194 PINTERNALPOS InternalPos
;
197 Size
.x
= WindowObject
->WindowRect
.left
;
198 Size
.y
= WindowObject
->WindowRect
.top
;
199 InternalPos
= WinPosInitInternalPos(WindowObject
, Size
,
200 &WindowObject
->WindowRect
);
204 if (WindowObject
->Style
& WS_MINIMIZE
)
206 if (!NtUserSendMessage(WindowObject
->Self
, WM_QUERYOPEN
, 0, 0))
208 return(SWP_NOSIZE
| SWP_NOMOVE
);
210 SwpFlags
|= SWP_NOCOPYBITS
;
216 if (WindowObject
->Style
& WS_MAXIMIZE
)
218 WindowObject
->Flags
|= WINDOWOBJECT_RESTOREMAX
;
219 WindowObject
->Style
&= ~WS_MAXIMIZE
;
223 WindowObject
->Style
&= ~WINDOWOBJECT_RESTOREMAX
;
225 WindowObject
->Style
|= WS_MINIMIZE
;
226 InternalPos
->IconPos
= WinPosFindIconPos(WindowObject
,
227 InternalPos
->IconPos
);
228 NtGdiSetRect(NewPos
, InternalPos
->IconPos
.x
, InternalPos
->IconPos
.y
,
229 NtUserGetSystemMetrics(SM_CXICON
),
230 NtUserGetSystemMetrics(SM_CYICON
));
231 SwpFlags
|= SWP_NOCOPYBITS
;
237 WinPosGetMinMaxInfo(WindowObject
, &Size
, &InternalPos
->MaxPos
,
239 if (WindowObject
->Style
& WS_MINIMIZE
)
241 WinPosShowIconTitle(WindowObject
, FALSE
);
242 WindowObject
->Style
&= ~WS_MINIMIZE
;
244 WindowObject
->Style
|= WS_MINIMIZE
;
245 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
, InternalPos
->MaxPos
.y
,
252 if (WindowObject
->Style
& WS_MINIMIZE
)
254 WindowObject
->Style
&= ~WS_MINIMIZE
;
255 WinPosShowIconTitle(WindowObject
, FALSE
);
256 if (WindowObject
->Flags
& WINDOWOBJECT_RESTOREMAX
)
258 WinPosGetMinMaxInfo(WindowObject
, &Size
,
259 &InternalPos
->MaxPos
, NULL
, NULL
);
260 WindowObject
->Style
|= WS_MAXIMIZE
;
261 NtGdiSetRect(NewPos
, InternalPos
->MaxPos
.x
,
262 InternalPos
->MaxPos
.y
, Size
.x
, Size
.y
);
268 if (!(WindowObject
->Style
& WS_MAXIMIZE
))
274 WindowObject
->Style
&= ~WS_MAXIMIZE
;
276 *NewPos
= InternalPos
->NormalRect
;
277 NewPos
->right
-= NewPos
->left
;
278 NewPos
->bottom
-= NewPos
->top
;
286 SwpFlags
|= SWP_NOSIZE
| SWP_NOMOVE
;
292 WinPosGetMinMaxInfo(PWINDOW_OBJECT Window
, POINT
* MaxSize
, POINT
* MaxPos
,
293 POINT
* MinTrack
, POINT
* MaxTrack
)
299 /* Get default values. */
300 MinMax
.ptMaxSize
.x
= NtUserGetSystemMetrics(SM_CXSCREEN
);
301 MinMax
.ptMaxSize
.y
= NtUserGetSystemMetrics(SM_CYSCREEN
);
302 MinMax
.ptMinTrackSize
.x
= NtUserGetSystemMetrics(SM_CXMINTRACK
);
303 MinMax
.ptMinTrackSize
.y
= NtUserGetSystemMetrics(SM_CYMINTRACK
);
304 MinMax
.ptMaxTrackSize
.x
= NtUserGetSystemMetrics(SM_CXSCREEN
);
305 MinMax
.ptMaxTrackSize
.y
= NtUserGetSystemMetrics(SM_CYSCREEN
);
307 if (HAS_DLGFRAME(Window
->Style
, Window
->ExStyle
))
309 XInc
= NtUserGetSystemMetrics(SM_CXDLGFRAME
);
310 YInc
= NtUserGetSystemMetrics(SM_CYDLGFRAME
);
315 if (HAS_THICKFRAME(Window
->Style
, Window
->ExStyle
))
317 XInc
+= NtUserGetSystemMetrics(SM_CXFRAME
);
318 YInc
+= NtUserGetSystemMetrics(SM_CYFRAME
);
320 if (Window
->Style
& WS_BORDER
)
322 XInc
+= NtUserGetSystemMetrics(SM_CXBORDER
);
323 YInc
+= NtUserGetSystemMetrics(SM_CYBORDER
);
326 MinMax
.ptMaxSize
.x
+= 2 * XInc
;
327 MinMax
.ptMaxSize
.y
+= 2 * YInc
;
329 Pos
= (PINTERNALPOS
)IntGetProp(Window
, AtomInternalPos
);
332 MinMax
.ptMaxPosition
= Pos
->MaxPos
;
336 MinMax
.ptMaxPosition
.x
-= XInc
;
337 MinMax
.ptMaxPosition
.y
-= YInc
;
340 IntSendMessage(Window
->Self
, WM_GETMINMAXINFO
, 0, (LPARAM
)&MinMax
, TRUE
);
342 MinMax
.ptMaxTrackSize
.x
= max(MinMax
.ptMaxTrackSize
.x
,
343 MinMax
.ptMinTrackSize
.x
);
344 MinMax
.ptMaxTrackSize
.y
= max(MinMax
.ptMaxTrackSize
.y
,
345 MinMax
.ptMinTrackSize
.y
);
347 if (MaxSize
) *MaxSize
= MinMax
.ptMaxSize
;
348 if (MaxPos
) *MaxPos
= MinMax
.ptMaxPosition
;
349 if (MinTrack
) *MinTrack
= MinMax
.ptMinTrackSize
;
350 if (MaxTrack
) *MaxTrack
= MinMax
.ptMaxTrackSize
;
352 return 0; //FIXME: what does it return?
356 WinPosChangeActiveWindow(HWND hWnd
, BOOL MouseMsg
)
358 PWINDOW_OBJECT WindowObject
;
360 WindowObject
= IntGetWindowObject(hWnd
);
361 if (WindowObject
== NULL
)
366 NtUserSendMessage(hWnd
,
368 MAKELONG(MouseMsg
? WA_CLICKACTIVE
: WA_CLICKACTIVE
,
369 (WindowObject
->Style
& WS_MINIMIZE
) ? 1 : 0),
370 (LPARAM
)IntGetDesktopWindow()); /* FIXME: Previous active window */
372 IntReleaseWindowObject(WindowObject
);
378 WinPosDoNCCALCSize(PWINDOW_OBJECT Window
, PWINDOWPOS WinPos
,
379 RECT
* WindowRect
, RECT
* ClientRect
)
381 return 0; /* FIXME: Calculate non client size */
385 WinPosDoWinPosChanging(PWINDOW_OBJECT WindowObject
,
390 if (!(WinPos
->flags
& SWP_NOSENDCHANGING
))
392 IntSendWINDOWPOSCHANGINGMessage(WindowObject
->Self
, WinPos
);
395 *WindowRect
= WindowObject
->WindowRect
;
397 (WindowObject
->Style
& WS_MINIMIZE
) ? WindowObject
->WindowRect
:
398 WindowObject
->ClientRect
;
400 if (!(WinPos
->flags
& SWP_NOSIZE
))
402 WindowRect
->right
= WindowRect
->left
+ WinPos
->cx
;
403 WindowRect
->bottom
= WindowRect
->top
+ WinPos
->cy
;
406 if (!(WinPos
->flags
& SWP_NOMOVE
))
408 WindowRect
->left
= WinPos
->x
;
409 WindowRect
->top
= WinPos
->y
;
410 WindowRect
->right
+= WinPos
->x
- WindowObject
->WindowRect
.left
;
411 WindowRect
->bottom
+= WinPos
->y
- WindowObject
->WindowRect
.top
;
414 if (!(WinPos
->flags
& SWP_NOSIZE
) || !(WinPos
->flags
& SWP_NOMOVE
))
416 WinPosGetNonClientSize(WindowObject
->Self
, WindowRect
, ClientRect
);
419 WinPos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
423 /***********************************************************************
424 * SWP_DoSimpleFrameChanged
426 * NOTE: old and new client rect origins are identical, only
427 * extents may have changed. Window extents are the same.
430 WinPosDoSimpleFrameChanged( PWINDOW_OBJECT wndPtr
, RECT
* pOldClientRect
, WORD swpFlags
, UINT uFlags
)
436 if( !(swpFlags
& SWP_NOCLIENTSIZE
) )
438 /* Client rect changed its position/size, most likely a scrollar
441 * FIXME: WVR alignment flags
444 if( wndPtr
->ClientRect
.right
> pOldClientRect
->right
) /* right edge */
448 rect
.bottom
= wndPtr
->ClientRect
.bottom
- wndPtr
->ClientRect
.top
;
449 rect
.right
= wndPtr
->ClientRect
.right
- wndPtr
->ClientRect
.left
;
450 if(!(uFlags
& SWP_EX_NOCOPY
))
451 rect
.left
= pOldClientRect
->right
- wndPtr
->ClientRect
.left
;
459 if( wndPtr
->ClientRect
.bottom
> pOldClientRect
->bottom
) /* bottom edge */
462 hrgn
= NtGdiCreateRectRgnIndirect( &rect
);
464 rect
.right
= wndPtr
->ClientRect
.right
- wndPtr
->ClientRect
.left
;
465 rect
.bottom
= wndPtr
->ClientRect
.bottom
- wndPtr
->ClientRect
.top
;
466 if(!(uFlags
& SWP_EX_NOCOPY
))
467 rect
.top
= pOldClientRect
->bottom
- wndPtr
->ClientRect
.top
;
472 HRGN hRectRgn
= NtGdiCreateRectRgnIndirect(&rect
);
473 NtGdiCombineRgn(hrgn
, hrgn
, hRectRgn
, RGN_OR
);
474 NtGdiDeleteObject(hRectRgn
);
478 if( i
== 0 && (uFlags
& SWP_EX_NOCOPY
) ) /* force redraw anyway */
480 rect
= wndPtr
->WindowRect
;
481 NtGdiOffsetRect( &rect
, wndPtr
->WindowRect
.left
- wndPtr
->ClientRect
.left
,
482 wndPtr
->WindowRect
.top
- wndPtr
->ClientRect
.top
);
490 PaintRedrawWindow( wndPtr
, &rect
, hrgn
, RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
|
491 RDW_ERASENOW
| RDW_ALLCHILDREN
, RDW_EX_TOPFRAME
| RDW_EX_USEHRGN
);
495 PaintUpdateNCRegion(wndPtr
, 0, UNC_UPDATE
| UNC_ENTIRE
);
499 NtGdiDeleteObject( hrgn
);
502 /***********************************************************************
505 * Make window look nice without excessive repainting
507 * visible and update regions are in window coordinates
508 * client and window rectangles are in parent client coordinates
510 * Returns: uFlags and a dirty region in *pVisRgn.
512 static UINT
WinPosCopyValidBits( PWINDOW_OBJECT Wnd
, HRGN
* pVisRgn
,
514 LPRECT lpOldClientRect
, UINT uFlags
)
517 HRGN newVisRgn
, dirtyRgn
;
518 INT my
= COMPLEXREGION
;
520 if( Wnd
->UpdateRegion
== (HRGN
)1 )
521 uFlags
|= SWP_EX_NOCOPY
; /* whole window is invalid, nothing to copy */
523 newVisRgn
= DceGetVisRgn( Wnd
->Self
, DCX_WINDOW
| DCX_CLIPSIBLINGS
, 0, 0);
524 NtGdiOffsetRgn(newVisRgn
, -Wnd
->WindowRect
.left
, -Wnd
->WindowRect
.top
);
525 dirtyRgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
527 if( !(uFlags
& SWP_EX_NOCOPY
) ) /* make sure dst region covers only valid bits */
528 my
= NtGdiCombineRgn( dirtyRgn
, newVisRgn
, *pVisRgn
, RGN_AND
);
530 if( (my
== NULLREGION
) || (uFlags
& SWP_EX_NOCOPY
) )
534 /* set dirtyRgn to the sum of old and new visible regions
535 * in parent client coordinates */
537 NtGdiOffsetRgn( newVisRgn
, Wnd
->WindowRect
.left
, Wnd
->WindowRect
.top
);
538 NtGdiOffsetRgn( *pVisRgn
, lpOldWndRect
->left
, lpOldWndRect
->top
);
540 NtGdiCombineRgn(*pVisRgn
, *pVisRgn
, newVisRgn
, RGN_OR
);
542 else /* copy valid bits to a new location */
544 INT dx
, dy
, ow
, oh
, nw
, nh
, ocw
, ncw
, och
, nch
;
545 HRGN hrgnValid
= dirtyRgn
; /* non-empty intersection of old and new visible rgns */
547 /* subtract already invalid region inside Wnd from the dst region */
549 if( Wnd
->UpdateRegion
)
550 if( NtGdiCombineRgn( hrgnValid
, hrgnValid
, Wnd
->UpdateRegion
, RGN_DIFF
) == NULLREGION
)
553 /* check if entire window can be copied */
555 ow
= lpOldWndRect
->right
- lpOldWndRect
->left
;
556 oh
= lpOldWndRect
->bottom
- lpOldWndRect
->top
;
557 nw
= Wnd
->WindowRect
.right
- Wnd
->WindowRect
.left
;
558 nh
= Wnd
->WindowRect
.bottom
- Wnd
->WindowRect
.top
;
560 ocw
= lpOldClientRect
->right
- lpOldClientRect
->left
;
561 och
= lpOldClientRect
->bottom
- lpOldClientRect
->top
;
562 ncw
= Wnd
->ClientRect
.right
- Wnd
->ClientRect
.left
;
563 nch
= Wnd
->ClientRect
.bottom
- Wnd
->ClientRect
.top
;
565 if( (ocw
!= ncw
) || (och
!= nch
) ||
566 ( ow
!= nw
) || ( oh
!= nh
) ||
567 ((lpOldClientRect
->top
- lpOldWndRect
->top
) !=
568 (Wnd
->ClientRect
.top
- Wnd
->WindowRect
.top
)) ||
569 ((lpOldClientRect
->left
- lpOldWndRect
->left
) !=
570 (Wnd
->ClientRect
.left
- Wnd
->WindowRect
.left
)) )
572 if(uFlags
& SWP_EX_PAINTSELF
)
574 /* movement relative to the window itself */
575 dx
= (Wnd
->ClientRect
.left
- Wnd
->WindowRect
.left
) -
576 (lpOldClientRect
->left
- lpOldWndRect
->left
) ;
577 dy
= (Wnd
->ClientRect
.top
- Wnd
->WindowRect
.top
) -
578 (lpOldClientRect
->top
- lpOldWndRect
->top
) ;
582 /* movement relative to the parent's client area */
583 dx
= Wnd
->ClientRect
.left
- lpOldClientRect
->left
;
584 dy
= Wnd
->ClientRect
.top
- lpOldClientRect
->top
;
587 /* restrict valid bits to the common client rect */
589 r
.left
= Wnd
->ClientRect
.left
- Wnd
->WindowRect
.left
;
590 r
.top
= Wnd
->ClientRect
.top
- Wnd
->WindowRect
.top
;
591 r
.right
= r
.left
+ min( ocw
, ncw
);
592 r
.bottom
= r
.top
+ min( och
, nch
);
594 REGION_CropRgn( hrgnValid
, hrgnValid
, &r
,
595 (uFlags
& SWP_EX_PAINTSELF
) ? NULL
: (POINT
*)&(Wnd
->WindowRect
));
596 NtGdiGetRgnBox( hrgnValid
, &r
);
597 if( NtGdiIsEmptyRect( &r
) )
599 r
= *lpOldClientRect
;
603 if(uFlags
& SWP_EX_PAINTSELF
) {
605 * with SWP_EX_PAINTSELF, the window repaints itself. Since a window can't move
606 * relative to itself, only the client area can change.
607 * if the client rect didn't change, there's nothing to do.
614 dx
= Wnd
->WindowRect
.left
- lpOldWndRect
->left
;
615 dy
= Wnd
->WindowRect
.top
- lpOldWndRect
->top
;
616 NtGdiOffsetRgn( hrgnValid
, Wnd
->WindowRect
.left
, Wnd
->WindowRect
.top
);
621 if( !(uFlags
& SWP_EX_PAINTSELF
) )
623 /* Move remaining regions to parent coordinates */
624 NtGdiOffsetRgn( newVisRgn
, Wnd
->WindowRect
.left
, Wnd
->WindowRect
.top
);
625 NtGdiOffsetRgn( *pVisRgn
, lpOldWndRect
->left
, lpOldWndRect
->top
);
628 NtGdiOffsetRect( &r
, -lpOldWndRect
->left
, -lpOldWndRect
->top
);
630 /* Compute combined dirty region (old + new - valid) */
631 NtGdiCombineRgn( *pVisRgn
, *pVisRgn
, newVisRgn
, RGN_OR
);
632 NtGdiCombineRgn( *pVisRgn
, *pVisRgn
, hrgnValid
, RGN_DIFF
);
634 /* Blt valid bits, r is the rect to copy */
641 /* get DC and clip rect with drawable rect to avoid superfluous expose events
642 from copying clipped areas */
644 if( uFlags
& SWP_EX_PAINTSELF
)
646 hDC
= NtUserGetDCEx( Wnd
->Self
, hrgnValid
, DCX_WINDOW
| DCX_CACHE
|
647 DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
648 rClip
.right
= nw
; rClip
.bottom
= nh
;
652 hDC
= NtUserGetDCEx( Wnd
->Parent
->Self
, hrgnValid
, DCX_CACHE
|
653 DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_CLIPSIBLINGS
);
654 rClip
.right
= Wnd
->Parent
->ClientRect
.right
- Wnd
->Parent
->ClientRect
.left
;
655 rClip
.bottom
= Wnd
->Parent
->ClientRect
.bottom
- Wnd
->Parent
->ClientRect
.top
;
657 rClip
.left
= rClip
.top
= 0;
659 if( oh
> nh
) r
.bottom
= r
.top
+ nh
;
660 if( ow
< nw
) r
.right
= r
.left
+ nw
;
662 if( NtGdiIntersectRect( &r
, &r
, &rClip
) )
664 NtGdiBitBlt(hDC
, dx
+ r
.left
, dy
+ r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
, hDC
, r
.left
, r
.top
, SRCCOPY
);
666 /* When you copy the bits without repainting, parent doesn't
667 get validated appropriately. Therefore, we have to validate
668 the parent with the windows' updated region when the
669 parent's update region is not empty. */
671 if (Wnd
->Parent
->UpdateRegion
!= 0 && !(Wnd
->Parent
->Style
& WS_CLIPCHILDREN
))
673 NtGdiOffsetRect(&r
, dx
, dy
);
674 NtUserValidateRect(Wnd
->Parent
->Self
, &r
);
677 NtUserReleaseDC( (uFlags
& SWP_EX_PAINTSELF
) ?
678 Wnd
->Self
: Wnd
->Parent
->Self
, hDC
);
682 /* *pVisRgn now points to the invalidated region */
684 NtGdiDeleteObject(newVisRgn
);
685 NtGdiDeleteObject(dirtyRgn
);
691 WinPosSetWindowPos(HWND Wnd
, HWND WndInsertAfter
, INT x
, INT y
, INT cx
,
694 PWINDOW_OBJECT Window
;
700 HRGN VisibleRgn
= NULL
;
702 RECT OldWindowRect
, OldClientRect
;
705 /* FIXME: Get current active window from active queue. */
707 /* Check if the window is for a desktop. */
708 if (Wnd
== PsGetWin32Thread()->Desktop
->DesktopWindow
)
714 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
718 if (!NT_SUCCESS(Status
))
723 /* Fix up the flags. */
724 if (Window
->Style
& WS_VISIBLE
)
726 flags
&= ~SWP_SHOWWINDOW
;
730 if (!(flags
& SWP_SHOWWINDOW
))
732 flags
|= SWP_NOREDRAW
;
734 flags
&= ~SWP_HIDEWINDOW
;
740 if ((Window
->WindowRect
.right
- Window
->WindowRect
.left
) == cx
&&
741 (Window
->WindowRect
.bottom
- Window
->WindowRect
.top
) == cy
)
745 if (Window
->WindowRect
.left
== x
&& Window
->WindowRect
.top
== y
)
749 if (Window
->Style
& WIN_NCACTIVATED
)
751 flags
|= SWP_NOACTIVATE
;
753 else if ((Window
->Style
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
755 if (!(flags
& SWP_NOACTIVATE
))
757 flags
&= ~SWP_NOZORDER
;
758 WndInsertAfter
= HWND_TOP
;
762 if (WndInsertAfter
== HWND_TOPMOST
|| WndInsertAfter
== HWND_NOTOPMOST
)
764 WndInsertAfter
= HWND_TOP
;
767 if (WndInsertAfter
!= HWND_TOP
&& WndInsertAfter
!= HWND_BOTTOM
)
769 /* FIXME: Find the window to insert after. */
773 WinPos
.hwndInsertAfter
= WndInsertAfter
;
778 WinPos
.flags
= flags
;
780 WinPosDoWinPosChanging(Window
, &WinPos
, &NewWindowRect
, &NewClientRect
);
782 if ((WinPos
.flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) !=
785 /* FIXME: SWP_DoOwnedPopups. */
788 /* FIXME: Adjust flags based on WndInsertAfter */
790 if ((!(WinPos
.flags
& (SWP_NOREDRAW
| SWP_SHOWWINDOW
)) &&
791 WinPos
.flags
& (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
|
792 SWP_HIDEWINDOW
| SWP_FRAMECHANGED
)) !=
793 (SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
))
795 if (Window
->Style
& WS_CLIPCHILDREN
)
797 VisRgn
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
,
798 Window
, FALSE
, FALSE
, TRUE
);
802 VisRgn
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
,
803 Window
, FALSE
, FALSE
, FALSE
);
805 NtGdiOffsetRgn(VisRgn
, -Window
->WindowRect
.left
, -Window
->WindowRect
.top
);
808 WvrFlags
= WinPosDoNCCALCSize(Window
, &WinPos
, &NewWindowRect
,
811 /* FIXME: Relink windows. */
813 /* FIXME: Reset active DCEs */
815 OldWindowRect
= Window
->WindowRect
;
816 OldClientRect
= Window
->ClientRect
;
818 /* FIXME: Check for redrawing the whole client rect. */
820 Window
->WindowRect
= NewWindowRect
;
821 Window
->ClientRect
= NewClientRect
;
823 if (WinPos
.flags
& SWP_SHOWWINDOW
)
825 Window
->Style
|= WS_VISIBLE
;
826 FlagsEx
|= SWP_EX_PAINTSELF
;
827 /* Redraw entire window. */
830 else if (!(WinPos
.flags
& SWP_NOREDRAW
))
832 if (WinPos
.flags
& SWP_HIDEWINDOW
)
834 if (VisRgn
> (HRGN
)1)
836 NtGdiOffsetRgn(VisRgn
, OldWindowRect
.left
, OldWindowRect
.top
);
845 if ((WinPos
.flags
& SWP_AGG_NOPOSCHANGE
) != SWP_AGG_NOPOSCHANGE
)
847 if ((WinPos
.flags
& SWP_AGG_NOGEOMETRYCHANGE
) == SWP_AGG_NOGEOMETRYCHANGE
)
849 FlagsEx
|= SWP_EX_PAINTSELF
;
851 FlagsEx
= WinPosCopyValidBits(Window
, &VisRgn
, &OldWindowRect
, &OldClientRect
, FlagsEx
);
855 if (WinPos
.flags
& SWP_FRAMECHANGED
)
857 WinPosDoSimpleFrameChanged(Window
, &OldClientRect
, WinPos
.flags
, FlagsEx
);
861 NtGdiDeleteObject(VisRgn
);
868 if (WinPos
.flags
& SWP_HIDEWINDOW
)
870 VisibleRgn
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
, Window
,
871 FALSE
, FALSE
, FALSE
);
872 Window
->Style
&= ~WS_VISIBLE
;
873 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
, VisibleRgn
);
874 NtGdiDeleteObject(VisibleRgn
);
877 /* FIXME: Hide or show the claret */
881 if (!(WinPos
.flags
& SWP_NOREDRAW
))
883 if (FlagsEx
& SWP_EX_PAINTSELF
)
885 PaintRedrawWindow(Window
, NULL
,
886 (VisRgn
== (HRGN
) 1) ? 0 : VisRgn
,
887 RDW_ERASE
| RDW_FRAME
| RDW_INVALIDATE
|
888 RDW_ALLCHILDREN
| RDW_ERASENOW
,
889 RDW_EX_XYWINDOW
| RDW_EX_USEHRGN
);
893 PaintRedrawWindow(Window
->Parent
, NULL
,
894 (VisRgn
== (HRGN
) 1) ? 0 : VisRgn
,
895 RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
|
899 /* FIXME: Redraw the window parent. */
901 NtGdiDeleteObject(VisRgn
);
904 if (!(flags
& SWP_NOACTIVATE
))
906 WinPosChangeActiveWindow(WinPos
.hwnd
, FALSE
);
909 /* FIXME: Check some conditions before doing this. */
910 IntSendWINDOWPOSCHANGEDMessage(Window
->Self
, &WinPos
);
912 ObmDereferenceObject(Window
);
917 WinPosGetNonClientSize(HWND Wnd
, RECT
* WindowRect
, RECT
* ClientRect
)
919 *ClientRect
= *WindowRect
;
920 return(IntSendNCCALCSIZEMessage(Wnd
, FALSE
, ClientRect
, NULL
));
924 WinPosShowWindow(HWND Wnd
, INT Cmd
)
927 PWINDOW_OBJECT Window
;
935 ObmReferenceObjectByHandle(PsGetWin32Process()->WindowStation
->HandleTable
,
939 if (!NT_SUCCESS(Status
))
944 WasVisible
= (Window
->Style
& WS_VISIBLE
) != 0;
952 ObmDereferenceObject(Window
);
955 Swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
|
960 case SW_SHOWMINNOACTIVE
:
961 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
963 case SW_SHOWMINIMIZED
:
964 Swp
|= SWP_SHOWWINDOW
;
968 Swp
|= SWP_FRAMECHANGED
;
969 if (!(Window
->Style
& WS_MINIMIZE
))
971 Swp
|= WinPosMinMaximize(Window
, SW_MINIMIZE
, &NewPos
);
975 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
980 case SW_SHOWMAXIMIZED
:
982 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
983 if (!(Window
->Style
& WS_MAXIMIZE
))
985 Swp
|= WinPosMinMaximize(Window
, SW_MAXIMIZE
, &NewPos
);
989 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
995 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
998 Swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
999 /* Don't activate the topmost window. */
1002 case SW_SHOWNOACTIVATE
:
1003 Swp
|= SWP_NOZORDER
;
1006 case SW_SHOWDEFAULT
:
1008 Swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
1009 if (Window
->Style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
1011 Swp
|= WinPosMinMaximize(Window
, SW_RESTORE
, &NewPos
);
1015 Swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
1020 ShowFlag
= (Cmd
!= SW_HIDE
);
1021 if (ShowFlag
!= WasVisible
)
1023 NtUserSendMessage(Wnd
, WM_SHOWWINDOW
, ShowFlag
, 0);
1025 * FIXME: Need to check the window wasn't destroyed during the
1030 if (Window
->Style
& WS_CHILD
&&
1031 !IntIsWindowVisible(Window
->Parent
->Self
) &&
1032 (Swp
& (SWP_NOSIZE
| SWP_NOMOVE
)) == (SWP_NOSIZE
| SWP_NOMOVE
))
1036 VisibleRgn
= VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop
, Window
,
1037 FALSE
, FALSE
, FALSE
);
1038 Window
->Style
&= ~WS_VISIBLE
;
1039 VIS_WindowLayoutChanged(PsGetWin32Thread()->Desktop
, Window
, VisibleRgn
);
1040 NtGdiDeleteObject(VisibleRgn
);
1044 Window
->Style
|= WS_VISIBLE
;
1049 if (Window
->Style
& WS_CHILD
&&
1050 !(Window
->ExStyle
& WS_EX_MDICHILD
))
1052 Swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
1054 if (!(Swp
& MINMAX_NOSWP
))
1056 WinPosSetWindowPos(Wnd
, HWND_TOP
, NewPos
.left
, NewPos
.top
,
1057 NewPos
.right
, NewPos
.bottom
, LOWORD(Swp
));
1060 /* Hide the window. */
1061 if (Wnd
== IntGetActiveWindow())
1063 WinPosActivateOtherWindow(Window
);
1065 /* Revert focus to parent. */
1066 if (Wnd
== IntGetFocusWindow() ||
1067 IntIsChildWindow(Wnd
, IntGetFocusWindow()))
1069 IntSetFocusWindow(Window
->Parent
->Self
);
1073 /* FIXME: Check for window destruction. */
1074 /* Show title for minimized windows. */
1075 if (Window
->Style
& WS_MINIMIZE
)
1077 WinPosShowIconTitle(Window
, TRUE
);
1081 if (Window
->Flags
& WINDOWOBJECT_NEED_SIZE
)
1083 WPARAM wParam
= SIZE_RESTORED
;
1085 Window
->Flags
&= ~WINDOWOBJECT_NEED_SIZE
;
1086 if (Window
->Style
& WS_MAXIMIZE
)
1088 wParam
= SIZE_MAXIMIZED
;
1090 else if (Window
->Style
& WS_MINIMIZE
)
1092 wParam
= SIZE_MINIMIZED
;
1095 NtUserSendMessage(Wnd
, WM_SIZE
, wParam
,
1096 MAKELONG(Window
->ClientRect
.right
-
1097 Window
->ClientRect
.left
,
1098 Window
->ClientRect
.bottom
-
1099 Window
->ClientRect
.top
));
1100 NtUserSendMessage(Wnd
, WM_MOVE
, 0,
1101 MAKELONG(Window
->ClientRect
.left
,
1102 Window
->ClientRect
.top
));
1105 /* Activate the window if activation is not requested and the window is not minimized */
1106 if (!(Swp
& (SWP_NOACTIVATE
| SWP_HIDEWINDOW
)) && !(Window
->Style
& WS_MINIMIZE
))
1108 WinPosChangeActiveWindow(Wnd
, FALSE
);
1111 ObmDereferenceObject(Window
);
1115 BOOL STATIC FASTCALL
1116 WinPosPtInWindow(PWINDOW_OBJECT Window
, POINT Point
)
1118 return(Point
.x
>= Window
->WindowRect
.left
&&
1119 Point
.x
< Window
->WindowRect
.right
&&
1120 Point
.y
>= Window
->WindowRect
.top
&&
1121 Point
.y
< Window
->WindowRect
.bottom
);
1124 USHORT STATIC STDCALL
1125 WinPosSearchChildren(PWINDOW_OBJECT ScopeWin
, POINT Point
,
1126 PWINDOW_OBJECT
* Window
)
1128 PWINDOW_OBJECT Current
;
1130 ExAcquireFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1131 Current
= ScopeWin
->FirstChild
;
1134 if (Current
->Style
& WS_VISIBLE
&&
1135 ((!(Current
->Style
& WS_DISABLED
)) ||
1136 (Current
->Style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) &&
1137 WinPosPtInWindow(Current
, Point
))
1140 if (Current
->Style
& WS_DISABLED
)
1142 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1145 if (Current
->Style
& WS_MINIMIZE
)
1147 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1150 if (Point
.x
>= Current
->ClientRect
.left
&&
1151 Point
.x
< Current
->ClientRect
.right
&&
1152 Point
.y
>= Current
->ClientRect
.top
&&
1153 Point
.y
< Current
->ClientRect
.bottom
)
1156 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1157 return(WinPosSearchChildren(Current
, Point
, Window
));
1160 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1163 Current
= Current
->NextSibling
;
1166 ExReleaseFastMutexUnsafe(&ScopeWin
->ChildrenListLock
);
1171 WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin
, POINT WinPoint
,
1172 PWINDOW_OBJECT
* Window
)
1174 HWND DesktopWindowHandle
;
1175 PWINDOW_OBJECT DesktopWindow
;
1176 POINT Point
= WinPoint
;
1181 if (ScopeWin
->Style
& WS_DISABLED
)
1186 /* Translate the point to the space of the scope window. */
1187 DesktopWindowHandle
= IntGetDesktopWindow();
1188 DesktopWindow
= IntGetWindowObject(DesktopWindowHandle
);
1189 Point
.x
+= ScopeWin
->ClientRect
.left
- DesktopWindow
->ClientRect
.left
;
1190 Point
.y
+= ScopeWin
->ClientRect
.top
- DesktopWindow
->ClientRect
.top
;
1191 IntReleaseWindowObject(DesktopWindow
);
1193 HitTest
= WinPosSearchChildren(ScopeWin
, Point
, Window
);
1199 if ((*Window
) == NULL
)
1203 if ((*Window
)->MessageQueue
== PsGetWin32Thread()->MessageQueue
)
1205 HitTest
= IntSendMessage((*Window
)->Self
, WM_NCHITTEST
, 0,
1206 MAKELONG(Point
.x
, Point
.y
), FALSE
);
1207 /* FIXME: Check for HTTRANSPARENT here. */
1218 WinPosSetActiveWindow(PWINDOW_OBJECT Window
, BOOL Mouse
, BOOL ChangeFocus
)
1220 PUSER_MESSAGE_QUEUE ActiveQueue
;
1223 ActiveQueue
= IntGetFocusMessageQueue();
1224 if (ActiveQueue
!= NULL
)
1226 PrevActive
= ActiveQueue
->ActiveWindow
;
1233 if (Window
->Self
== IntGetActiveDesktop() || Window
->Self
== PrevActive
)
1237 if (PrevActive
!= NULL
)
1239 PWINDOW_OBJECT PrevActiveWindow
= IntGetWindowObject(PrevActive
);
1240 WORD Iconised
= HIWORD(PrevActiveWindow
->Style
& WS_MINIMIZE
);
1241 if (!IntSendMessage(PrevActive
, WM_NCACTIVATE
, FALSE
, 0, TRUE
))
1243 /* FIXME: Check if the new window is system modal. */
1246 IntSendMessage(PrevActive
,
1248 MAKEWPARAM(WA_INACTIVE
, Iconised
),
1249 (LPARAM
)Window
->Self
,
1251 /* FIXME: Check if anything changed while processing the message. */
1252 IntReleaseWindowObject(PrevActiveWindow
);
1257 Window
->MessageQueue
->ActiveWindow
= Window
->Self
;
1259 else if (ActiveQueue
!= NULL
)
1261 ActiveQueue
->ActiveWindow
= NULL
;
1263 /* FIXME: Unset this flag for inactive windows */
1264 //if ((Window->Style) & WS_CHILD) Window->Flags |= WIN_NCACTIVATED;
1266 /* FIXME: Send palette messages. */
1268 /* FIXME: Redraw icon title of previously active window. */
1270 /* FIXME: Bring the window to the top. */
1272 /* FIXME: Send WM_ACTIVATEAPP */
1274 IntSetFocusMessageQueue(Window
->MessageQueue
);
1276 /* FIXME: Send activate messages. */
1278 /* FIXME: Change focus. */
1280 /* FIXME: Redraw new window icon title. */
1286 NtUserGetActiveWindow(VOID
)
1288 PUSER_MESSAGE_QUEUE ActiveQueue
;
1290 ActiveQueue
= IntGetFocusMessageQueue();
1291 if (ActiveQueue
== NULL
)
1295 return(ActiveQueue
->ActiveWindow
);
1299 NtUserSetActiveWindow(HWND hWnd
)
1301 PWINDOW_OBJECT Window
;
1302 PUSER_MESSAGE_QUEUE ThreadQueue
;
1305 Window
= IntGetWindowObject(hWnd
);
1306 if (Window
== NULL
|| (Window
->Style
& (WS_DISABLED
| WS_CHILD
)))
1308 IntReleaseWindowObject(Window
);
1311 ThreadQueue
= (PUSER_MESSAGE_QUEUE
)PsGetWin32Thread()->MessageQueue
;
1312 if (Window
->MessageQueue
!= ThreadQueue
)
1314 IntReleaseWindowObject(Window
);
1317 Prev
= Window
->MessageQueue
->ActiveWindow
;
1318 WinPosSetActiveWindow(Window
, FALSE
, FALSE
);
1319 IntReleaseWindowObject(Window
);