1325 lines
46 KiB
C
1325 lines
46 KiB
C
/*
|
|
* Window position related functions.
|
|
*
|
|
* Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
|
|
* Copyright 1995, 1996, 1999 Alex Korobka
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "ts_xlib.h"
|
|
#include "ts_shape.h"
|
|
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
|
|
#include "x11drv.h"
|
|
#include "win.h"
|
|
#include "winpos.h"
|
|
#include "region.h"
|
|
#include "dce.h"
|
|
|
|
#include "debugtools.h"
|
|
|
|
DEFAULT_DEBUG_CHANNEL(win);
|
|
|
|
|
|
#define SWP_AGG_NOGEOMETRYCHANGE \
|
|
(SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
|
|
#define SWP_AGG_NOPOSCHANGE \
|
|
(SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
|
|
#define SWP_AGG_STATUSFLAGS \
|
|
(SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
|
|
|
|
#define SWP_EX_NOCOPY 0x0001
|
|
#define SWP_EX_PAINTSELF 0x0002
|
|
#define SWP_EX_NONCLIENT 0x0004
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_OffsetVisRgn
|
|
*
|
|
* Change region from DC-origin relative coordinates to screen coords.
|
|
*/
|
|
|
|
static void DCE_OffsetVisRgn( HDC hDC, HRGN hVisRgn )
|
|
{
|
|
DC *dc;
|
|
if (!(dc = DC_GetDCPtr( hDC ))) return;
|
|
|
|
OffsetRgn( hVisRgn, dc->DCOrgX, dc->DCOrgY );
|
|
|
|
GDI_ReleaseObj( hDC );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_GetVisRect
|
|
*
|
|
* Calculate the visible rectangle of a window (i.e. the client or
|
|
* window area clipped by the client area of all ancestors) in the
|
|
* corresponding coordinates. Return FALSE if the visible region is empty.
|
|
*/
|
|
static BOOL DCE_GetVisRect( WND *wndPtr, BOOL clientArea, RECT *lprect )
|
|
{
|
|
*lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow;
|
|
|
|
if (wndPtr->dwStyle & WS_VISIBLE)
|
|
{
|
|
INT xoffset = lprect->left;
|
|
INT yoffset = lprect->top;
|
|
|
|
while( !(wndPtr->flags & WIN_NATIVE) &&
|
|
( wndPtr = WIN_LockWndPtr(wndPtr->parent)) )
|
|
{
|
|
if ( (wndPtr->dwStyle & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE )
|
|
{
|
|
WIN_ReleaseWndPtr(wndPtr);
|
|
goto fail;
|
|
}
|
|
|
|
xoffset += wndPtr->rectClient.left;
|
|
yoffset += wndPtr->rectClient.top;
|
|
OffsetRect( lprect, wndPtr->rectClient.left,
|
|
wndPtr->rectClient.top );
|
|
|
|
if( (wndPtr->rectClient.left >= wndPtr->rectClient.right) ||
|
|
(wndPtr->rectClient.top >= wndPtr->rectClient.bottom) ||
|
|
(lprect->left >= wndPtr->rectClient.right) ||
|
|
(lprect->right <= wndPtr->rectClient.left) ||
|
|
(lprect->top >= wndPtr->rectClient.bottom) ||
|
|
(lprect->bottom <= wndPtr->rectClient.top) )
|
|
{
|
|
WIN_ReleaseWndPtr(wndPtr);
|
|
goto fail;
|
|
}
|
|
|
|
lprect->left = max( lprect->left, wndPtr->rectClient.left );
|
|
lprect->right = min( lprect->right, wndPtr->rectClient.right );
|
|
lprect->top = max( lprect->top, wndPtr->rectClient.top );
|
|
lprect->bottom = min( lprect->bottom, wndPtr->rectClient.bottom );
|
|
|
|
WIN_ReleaseWndPtr(wndPtr);
|
|
}
|
|
OffsetRect( lprect, -xoffset, -yoffset );
|
|
return TRUE;
|
|
}
|
|
|
|
fail:
|
|
SetRectEmpty( lprect );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_AddClipRects
|
|
*
|
|
* Go through the linked list of windows from pWndStart to pWndEnd,
|
|
* adding to the clip region the intersection of the target rectangle
|
|
* with an offset window rectangle.
|
|
*/
|
|
static BOOL DCE_AddClipRects( WND *pWndStart, WND *pWndEnd,
|
|
HRGN hrgnClip, LPRECT lpRect, int x, int y )
|
|
{
|
|
RECT rect;
|
|
|
|
if (X11DRV_WND_GetXWindow(pWndStart)) return TRUE; /* X will do the clipping */
|
|
|
|
for (WIN_LockWndPtr(pWndStart); (pWndStart && (pWndStart != pWndEnd)); WIN_UpdateWndPtr(&pWndStart,pWndStart->next))
|
|
{
|
|
if( !(pWndStart->dwStyle & WS_VISIBLE) ) continue;
|
|
|
|
rect.left = pWndStart->rectWindow.left + x;
|
|
rect.top = pWndStart->rectWindow.top + y;
|
|
rect.right = pWndStart->rectWindow.right + x;
|
|
rect.bottom = pWndStart->rectWindow.bottom + y;
|
|
|
|
if( IntersectRect( &rect, &rect, lpRect ))
|
|
{
|
|
if(!REGION_UnionRectWithRgn( hrgnClip, &rect )) break;
|
|
}
|
|
}
|
|
WIN_ReleaseWndPtr(pWndStart);
|
|
return (pWndStart == pWndEnd);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* DCE_GetVisRgn
|
|
*
|
|
* Return the visible region of a window, i.e. the client or window area
|
|
* clipped by the client area of all ancestors, and then optionally
|
|
* by siblings and children.
|
|
*/
|
|
static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
|
|
{
|
|
HRGN hrgnVis = 0;
|
|
RECT rect;
|
|
WND *wndPtr = WIN_FindWndPtr( hwnd );
|
|
WND *childWnd = WIN_FindWndPtr( hwndChild );
|
|
|
|
/* Get visible rectangle and create a region with it. */
|
|
|
|
if (wndPtr && DCE_GetVisRect(wndPtr, !(flags & DCX_WINDOW), &rect))
|
|
{
|
|
if((hrgnVis = CreateRectRgnIndirect( &rect )))
|
|
{
|
|
HRGN hrgnClip = CreateRectRgn( 0, 0, 0, 0 );
|
|
INT xoffset, yoffset;
|
|
|
|
if( hrgnClip )
|
|
{
|
|
/* Compute obscured region for the visible rectangle by
|
|
* clipping children, siblings, and ancestors. Note that
|
|
* DCE_GetVisRect() returns a rectangle either in client
|
|
* or in window coordinates (for DCX_WINDOW request). */
|
|
|
|
if( (flags & DCX_CLIPCHILDREN) && wndPtr->child )
|
|
{
|
|
if( flags & DCX_WINDOW )
|
|
{
|
|
/* adjust offsets since child window rectangles are
|
|
* in client coordinates */
|
|
|
|
xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
|
|
yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
|
|
}
|
|
else
|
|
xoffset = yoffset = 0;
|
|
|
|
DCE_AddClipRects( wndPtr->child, NULL, hrgnClip, &rect, xoffset, yoffset );
|
|
}
|
|
|
|
/* We may need to clip children of child window, if a window with PARENTDC
|
|
* class style and CLIPCHILDREN window style (like in Free Agent 16
|
|
* preference dialogs) gets here, we take the region for the parent window
|
|
* but apparently still need to clip the children of the child window... */
|
|
|
|
if( (cflags & DCX_CLIPCHILDREN) && childWnd && childWnd->child )
|
|
{
|
|
if( flags & DCX_WINDOW )
|
|
{
|
|
/* adjust offsets since child window rectangles are
|
|
* in client coordinates */
|
|
|
|
xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
|
|
yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
|
|
}
|
|
else
|
|
xoffset = yoffset = 0;
|
|
|
|
/* client coordinates of child window */
|
|
xoffset += childWnd->rectClient.left;
|
|
yoffset += childWnd->rectClient.top;
|
|
|
|
DCE_AddClipRects( childWnd->child, NULL, hrgnClip,
|
|
&rect, xoffset, yoffset );
|
|
}
|
|
|
|
/* sibling window rectangles are in client
|
|
* coordinates of the parent window */
|
|
|
|
if (flags & DCX_WINDOW)
|
|
{
|
|
xoffset = -wndPtr->rectWindow.left;
|
|
yoffset = -wndPtr->rectWindow.top;
|
|
}
|
|
else
|
|
{
|
|
xoffset = -wndPtr->rectClient.left;
|
|
yoffset = -wndPtr->rectClient.top;
|
|
}
|
|
|
|
if (flags & DCX_CLIPSIBLINGS && wndPtr->parent )
|
|
DCE_AddClipRects( wndPtr->parent->child,
|
|
wndPtr, hrgnClip, &rect, xoffset, yoffset );
|
|
|
|
/* Clip siblings of all ancestors that have the
|
|
* WS_CLIPSIBLINGS style
|
|
*/
|
|
|
|
while (wndPtr->parent)
|
|
{
|
|
WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
|
|
xoffset -= wndPtr->rectClient.left;
|
|
yoffset -= wndPtr->rectClient.top;
|
|
if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent)
|
|
{
|
|
DCE_AddClipRects( wndPtr->parent->child, wndPtr,
|
|
hrgnClip, &rect, xoffset, yoffset );
|
|
}
|
|
}
|
|
|
|
/* Now once we've got a jumbo clip region we have
|
|
* to substract it from the visible rectangle.
|
|
*/
|
|
CombineRgn( hrgnVis, hrgnVis, hrgnClip, RGN_DIFF );
|
|
DeleteObject( hrgnClip );
|
|
}
|
|
else
|
|
{
|
|
DeleteObject( hrgnVis );
|
|
hrgnVis = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
hrgnVis = CreateRectRgn(0, 0, 0, 0); /* empty */
|
|
WIN_ReleaseWndPtr(wndPtr);
|
|
WIN_ReleaseWndPtr(childWnd);
|
|
return hrgnVis;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetDC (X11DRV.@)
|
|
*
|
|
* Set the drawable, origin and dimensions for the DC associated to
|
|
* a given window.
|
|
*/
|
|
BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
|
|
{
|
|
WND *w, *wndPtr = WIN_FindWndPtr(hwnd);
|
|
DC *dc;
|
|
X11DRV_PDEVICE *physDev;
|
|
INT dcOrgXCopy = 0, dcOrgYCopy = 0;
|
|
BOOL offsetClipRgn = FALSE;
|
|
BOOL updateVisRgn;
|
|
HRGN hrgnVisible = 0;
|
|
|
|
if (!wndPtr) return FALSE;
|
|
|
|
if (!(dc = DC_GetDCPtr( hdc )))
|
|
{
|
|
WIN_ReleaseWndPtr( wndPtr );
|
|
return FALSE;
|
|
}
|
|
|
|
physDev = (X11DRV_PDEVICE *)dc->physDev;
|
|
|
|
/*
|
|
* This function change the coordinate system (DCOrgX,DCOrgY)
|
|
* values. When it moves the origin, other data like the current clipping
|
|
* region will not be moved to that new origin. In the case of DCs that are class
|
|
* or window DCs that clipping region might be a valid value from a previous use
|
|
* of the DC and changing the origin of the DC without moving the clip region
|
|
* results in a clip region that is not placed properly in the DC.
|
|
* This code will save the dc origin, let the SetDrawable
|
|
* modify the origin and reset the clipping. When the clipping is set,
|
|
* it is moved according to the new DC origin.
|
|
*/
|
|
if ( (wndPtr->clsStyle & (CS_OWNDC | CS_CLASSDC)) && (dc->hClipRgn > 0))
|
|
{
|
|
dcOrgXCopy = dc->DCOrgX;
|
|
dcOrgYCopy = dc->DCOrgY;
|
|
offsetClipRgn = TRUE;
|
|
}
|
|
|
|
if (flags & DCX_WINDOW)
|
|
{
|
|
dc->DCOrgX = wndPtr->rectWindow.left;
|
|
dc->DCOrgY = wndPtr->rectWindow.top;
|
|
}
|
|
else
|
|
{
|
|
dc->DCOrgX = wndPtr->rectClient.left;
|
|
dc->DCOrgY = wndPtr->rectClient.top;
|
|
}
|
|
|
|
w = wndPtr;
|
|
while (!X11DRV_WND_GetXWindow(w))
|
|
{
|
|
w = w->parent;
|
|
dc->DCOrgX += w->rectClient.left;
|
|
dc->DCOrgY += w->rectClient.top;
|
|
}
|
|
dc->DCOrgX -= w->rectWindow.left;
|
|
dc->DCOrgY -= w->rectWindow.top;
|
|
|
|
/* reset the clip region, according to the new origin */
|
|
if ( offsetClipRgn )
|
|
{
|
|
OffsetRgn(dc->hClipRgn, dc->DCOrgX - dcOrgXCopy,dc->DCOrgY - dcOrgYCopy);
|
|
}
|
|
|
|
physDev->drawable = X11DRV_WND_GetXWindow(w);
|
|
|
|
#if 0
|
|
/* This is needed when we reuse a cached DC because
|
|
* SetDCState() called by ReleaseDC() screws up DC
|
|
* origins for child windows.
|
|
*/
|
|
|
|
if( bSetClipOrigin )
|
|
TSXSetClipOrigin( display, physDev->gc, dc->DCOrgX, dc->DCOrgY );
|
|
#endif
|
|
|
|
updateVisRgn = (dc->flags & DC_DIRTY) != 0;
|
|
GDI_ReleaseObj( hdc );
|
|
|
|
if (updateVisRgn)
|
|
{
|
|
if (flags & DCX_PARENTCLIP)
|
|
{
|
|
WND *parentPtr = WIN_LockWndPtr(wndPtr->parent);
|
|
|
|
if( wndPtr->dwStyle & WS_VISIBLE && !(parentPtr->dwStyle & WS_MINIMIZE) )
|
|
{
|
|
DWORD dcxFlags;
|
|
|
|
if( parentPtr->dwStyle & WS_CLIPSIBLINGS )
|
|
dcxFlags = DCX_CLIPSIBLINGS | (flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
|
|
else
|
|
dcxFlags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
|
|
|
|
hrgnVisible = DCE_GetVisRgn( parentPtr->hwndSelf, dcxFlags,
|
|
wndPtr->hwndSelf, flags );
|
|
if( flags & DCX_WINDOW )
|
|
OffsetRgn( hrgnVisible, -wndPtr->rectWindow.left,
|
|
-wndPtr->rectWindow.top );
|
|
else
|
|
OffsetRgn( hrgnVisible, -wndPtr->rectClient.left,
|
|
-wndPtr->rectClient.top );
|
|
DCE_OffsetVisRgn( hdc, hrgnVisible );
|
|
}
|
|
else
|
|
hrgnVisible = CreateRectRgn( 0, 0, 0, 0 );
|
|
WIN_ReleaseWndPtr(parentPtr);
|
|
}
|
|
else
|
|
{
|
|
if ((hwnd == GetDesktopWindow()) && (root_window != DefaultRootWindow(display)))
|
|
hrgnVisible = CreateRectRgn( 0, 0, GetSystemMetrics(SM_CXSCREEN),
|
|
GetSystemMetrics(SM_CYSCREEN) );
|
|
else
|
|
{
|
|
hrgnVisible = DCE_GetVisRgn( hwnd, flags, 0, 0 );
|
|
DCE_OffsetVisRgn( hdc, hrgnVisible );
|
|
}
|
|
}
|
|
SelectVisRgn16( hdc, hrgnVisible );
|
|
}
|
|
|
|
/* apply additional region operation (if any) */
|
|
|
|
if( flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) )
|
|
{
|
|
if( !hrgnVisible ) hrgnVisible = CreateRectRgn( 0, 0, 0, 0 );
|
|
|
|
TRACE("\tsaved VisRgn, clipRgn = %04x\n", hrgn);
|
|
|
|
SaveVisRgn16( hdc );
|
|
CombineRgn( hrgnVisible, hrgn, 0, RGN_COPY );
|
|
DCE_OffsetVisRgn( hdc, hrgnVisible );
|
|
CombineRgn( hrgnVisible, InquireVisRgn16( hdc ), hrgnVisible,
|
|
(flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
|
|
SelectVisRgn16( hdc, hrgnVisible );
|
|
}
|
|
|
|
if (hrgnVisible) DeleteObject( hrgnVisible );
|
|
|
|
WIN_ReleaseWndPtr( wndPtr );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SWP_DoSimpleFrameChanged
|
|
*
|
|
* NOTE: old and new client rect origins are identical, only
|
|
* extents may have changed. Window extents are the same.
|
|
*/
|
|
static void SWP_DoSimpleFrameChanged( WND* wndPtr, RECT* pOldClientRect,
|
|
WORD swpFlags, UINT uFlags )
|
|
{
|
|
INT i = 0;
|
|
RECT rect;
|
|
HRGN hrgn = 0;
|
|
|
|
if( !(swpFlags & SWP_NOCLIENTSIZE) )
|
|
{
|
|
/* Client rect changed its position/size, most likely a scrollar
|
|
* was added/removed.
|
|
*
|
|
* FIXME: WVR alignment flags
|
|
*/
|
|
|
|
if( wndPtr->rectClient.right > pOldClientRect->right ) /* right edge */
|
|
{
|
|
i++;
|
|
rect.top = 0;
|
|
rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
|
|
rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left;
|
|
if(!(uFlags & SWP_EX_NOCOPY))
|
|
rect.left = pOldClientRect->right - wndPtr->rectClient.left;
|
|
else
|
|
{
|
|
rect.left = 0;
|
|
goto redraw;
|
|
}
|
|
}
|
|
|
|
if( wndPtr->rectClient.bottom > pOldClientRect->bottom ) /* bottom edge */
|
|
{
|
|
if( i )
|
|
hrgn = CreateRectRgnIndirect( &rect );
|
|
rect.left = 0;
|
|
rect.right = wndPtr->rectClient.right - wndPtr->rectClient.left;
|
|
rect.bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
|
|
if(!(uFlags & SWP_EX_NOCOPY))
|
|
rect.top = pOldClientRect->bottom - wndPtr->rectClient.top;
|
|
else
|
|
rect.top = 0;
|
|
if( i++ )
|
|
REGION_UnionRectWithRgn( hrgn, &rect );
|
|
}
|
|
|
|
if( i == 0 && (uFlags & SWP_EX_NOCOPY) ) /* force redraw anyway */
|
|
{
|
|
rect = wndPtr->rectWindow;
|
|
OffsetRect( &rect, wndPtr->rectWindow.left - wndPtr->rectClient.left,
|
|
wndPtr->rectWindow.top - wndPtr->rectClient.top );
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if( i )
|
|
{
|
|
redraw:
|
|
PAINT_RedrawWindow( wndPtr->hwndSelf, &rect, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE |
|
|
RDW_ERASENOW | RDW_ALLCHILDREN, RDW_EX_TOPFRAME | RDW_EX_USEHRGN );
|
|
}
|
|
else
|
|
{
|
|
WIN_UpdateNCRgn(wndPtr, 0, UNC_UPDATE | UNC_ENTIRE);
|
|
}
|
|
|
|
if( hrgn > 1 )
|
|
DeleteObject( hrgn );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SWP_DoWinPosChanging
|
|
*/
|
|
static BOOL SWP_DoWinPosChanging( WND* wndPtr, WINDOWPOS* pWinpos,
|
|
RECT* pNewWindowRect, RECT* pNewClientRect )
|
|
{
|
|
/* Send WM_WINDOWPOSCHANGING message */
|
|
|
|
if (!(pWinpos->flags & SWP_NOSENDCHANGING))
|
|
SendMessageA( wndPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
|
|
|
|
/* Calculate new position and size */
|
|
|
|
*pNewWindowRect = wndPtr->rectWindow;
|
|
*pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
|
|
: wndPtr->rectClient;
|
|
|
|
if (!(pWinpos->flags & SWP_NOSIZE))
|
|
{
|
|
pNewWindowRect->right = pNewWindowRect->left + pWinpos->cx;
|
|
pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
|
|
}
|
|
if (!(pWinpos->flags & SWP_NOMOVE))
|
|
{
|
|
pNewWindowRect->left = pWinpos->x;
|
|
pNewWindowRect->top = pWinpos->y;
|
|
pNewWindowRect->right += pWinpos->x - wndPtr->rectWindow.left;
|
|
pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
|
|
|
|
OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
|
|
pWinpos->y - wndPtr->rectWindow.top );
|
|
}
|
|
|
|
pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SWP_DoNCCalcSize
|
|
*/
|
|
static UINT SWP_DoNCCalcSize( WND* wndPtr, WINDOWPOS* pWinpos,
|
|
RECT* pNewWindowRect, RECT* pNewClientRect, WORD f)
|
|
{
|
|
UINT wvrFlags = 0;
|
|
|
|
/* Send WM_NCCALCSIZE message to get new client area */
|
|
if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
|
|
{
|
|
wvrFlags = WINPOS_SendNCCalcSize( pWinpos->hwnd, TRUE, pNewWindowRect,
|
|
&wndPtr->rectWindow, &wndPtr->rectClient,
|
|
pWinpos, pNewClientRect );
|
|
|
|
/* FIXME: WVR_ALIGNxxx */
|
|
|
|
if( pNewClientRect->left != wndPtr->rectClient.left ||
|
|
pNewClientRect->top != wndPtr->rectClient.top )
|
|
pWinpos->flags &= ~SWP_NOCLIENTMOVE;
|
|
|
|
if( (pNewClientRect->right - pNewClientRect->left !=
|
|
wndPtr->rectClient.right - wndPtr->rectClient.left) ||
|
|
(pNewClientRect->bottom - pNewClientRect->top !=
|
|
wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
|
|
pWinpos->flags &= ~SWP_NOCLIENTSIZE;
|
|
}
|
|
else
|
|
if( !(f & SWP_NOMOVE) && (pNewClientRect->left != wndPtr->rectClient.left ||
|
|
pNewClientRect->top != wndPtr->rectClient.top) )
|
|
pWinpos->flags &= ~SWP_NOCLIENTMOVE;
|
|
return wvrFlags;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SWP_DoOwnedPopups
|
|
*
|
|
* fix Z order taking into account owned popups -
|
|
* basically we need to maintain them above the window that owns them
|
|
*
|
|
* FIXME: hide/show owned popups when owner visibility changes.
|
|
*/
|
|
static HWND SWP_DoOwnedPopups(WND* pDesktop, WND* wndPtr, HWND hwndInsertAfter, WORD flags)
|
|
{
|
|
WND *w = WIN_LockWndPtr(pDesktop->child);
|
|
|
|
WARN("(%04x) hInsertAfter = %04x\n", wndPtr->hwndSelf, hwndInsertAfter );
|
|
|
|
if( (wndPtr->dwStyle & WS_POPUP) && wndPtr->owner )
|
|
{
|
|
/* make sure this popup stays above the owner */
|
|
|
|
HWND hwndLocalPrev = HWND_TOP;
|
|
|
|
if( hwndInsertAfter != HWND_TOP )
|
|
{
|
|
while( w && w != wndPtr->owner )
|
|
{
|
|
if (w != wndPtr) hwndLocalPrev = w->hwndSelf;
|
|
if( hwndLocalPrev == hwndInsertAfter ) break;
|
|
WIN_UpdateWndPtr(&w,w->next);
|
|
}
|
|
hwndInsertAfter = hwndLocalPrev;
|
|
}
|
|
}
|
|
else if( wndPtr->dwStyle & WS_CHILD )
|
|
goto END;
|
|
|
|
WIN_UpdateWndPtr(&w, pDesktop->child);
|
|
|
|
while( w )
|
|
{
|
|
if( w == wndPtr ) break;
|
|
|
|
if( (w->dwStyle & WS_POPUP) && w->owner == wndPtr )
|
|
{
|
|
SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
|
|
hwndInsertAfter = w->hwndSelf;
|
|
}
|
|
WIN_UpdateWndPtr(&w, w->next);
|
|
}
|
|
|
|
END:
|
|
WIN_ReleaseWndPtr(w);
|
|
return hwndInsertAfter;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SWP_CopyValidBits
|
|
*
|
|
* Make window look nice without excessive repainting
|
|
*
|
|
* visible and update regions are in window coordinates
|
|
* client and window rectangles are in parent client coordinates
|
|
*
|
|
* Returns: uFlags and a dirty region in *pVisRgn.
|
|
*/
|
|
static UINT SWP_CopyValidBits( WND* Wnd, HRGN* pVisRgn,
|
|
LPRECT lpOldWndRect,
|
|
LPRECT lpOldClientRect, UINT uFlags )
|
|
{
|
|
RECT r;
|
|
HRGN newVisRgn, dirtyRgn;
|
|
INT my = COMPLEXREGION;
|
|
DWORD dflags;
|
|
|
|
TRACE("\tnew wnd=(%i %i-%i %i) old wnd=(%i %i-%i %i), %04x\n",
|
|
Wnd->rectWindow.left, Wnd->rectWindow.top,
|
|
Wnd->rectWindow.right, Wnd->rectWindow.bottom,
|
|
lpOldWndRect->left, lpOldWndRect->top,
|
|
lpOldWndRect->right, lpOldWndRect->bottom, *pVisRgn);
|
|
TRACE("\tnew client=(%i %i-%i %i) old client=(%i %i-%i %i)\n",
|
|
Wnd->rectClient.left, Wnd->rectClient.top,
|
|
Wnd->rectClient.right, Wnd->rectClient.bottom,
|
|
lpOldClientRect->left, lpOldClientRect->top,
|
|
lpOldClientRect->right,lpOldClientRect->bottom );
|
|
|
|
if( Wnd->hrgnUpdate == 1 )
|
|
uFlags |= SWP_EX_NOCOPY; /* whole window is invalid, nothing to copy */
|
|
|
|
dflags = DCX_WINDOW;
|
|
if(Wnd->dwStyle & WS_CLIPSIBLINGS)
|
|
dflags |= DCX_CLIPSIBLINGS;
|
|
newVisRgn = DCE_GetVisRgn( Wnd->hwndSelf, dflags, 0, 0);
|
|
|
|
dirtyRgn = CreateRectRgn( 0, 0, 0, 0 );
|
|
|
|
if( !(uFlags & SWP_EX_NOCOPY) ) /* make sure dst region covers only valid bits */
|
|
my = CombineRgn( dirtyRgn, newVisRgn, *pVisRgn, RGN_AND );
|
|
|
|
if( (my == NULLREGION) || (uFlags & SWP_EX_NOCOPY) )
|
|
{
|
|
nocopy:
|
|
|
|
TRACE("\twon't copy anything!\n");
|
|
|
|
/* set dirtyRgn to the sum of old and new visible regions
|
|
* in parent client coordinates */
|
|
|
|
OffsetRgn( newVisRgn, Wnd->rectWindow.left, Wnd->rectWindow.top );
|
|
OffsetRgn( *pVisRgn, lpOldWndRect->left, lpOldWndRect->top );
|
|
|
|
CombineRgn(*pVisRgn, *pVisRgn, newVisRgn, RGN_OR );
|
|
}
|
|
else /* copy valid bits to a new location */
|
|
{
|
|
INT dx, dy, ow, oh, nw, nh, ocw, ncw, och, nch;
|
|
HRGN hrgnValid = dirtyRgn; /* non-empty intersection of old and new visible rgns */
|
|
|
|
/* subtract already invalid region inside Wnd from the dst region */
|
|
|
|
if( Wnd->hrgnUpdate )
|
|
if( CombineRgn( hrgnValid, hrgnValid, Wnd->hrgnUpdate, RGN_DIFF) == NULLREGION )
|
|
goto nocopy;
|
|
|
|
/* check if entire window can be copied */
|
|
|
|
ow = lpOldWndRect->right - lpOldWndRect->left;
|
|
oh = lpOldWndRect->bottom - lpOldWndRect->top;
|
|
nw = Wnd->rectWindow.right - Wnd->rectWindow.left;
|
|
nh = Wnd->rectWindow.bottom - Wnd->rectWindow.top;
|
|
|
|
ocw = lpOldClientRect->right - lpOldClientRect->left;
|
|
och = lpOldClientRect->bottom - lpOldClientRect->top;
|
|
ncw = Wnd->rectClient.right - Wnd->rectClient.left;
|
|
nch = Wnd->rectClient.bottom - Wnd->rectClient.top;
|
|
|
|
if( (ocw != ncw) || (och != nch) ||
|
|
( ow != nw) || ( oh != nh) ||
|
|
((lpOldClientRect->top - lpOldWndRect->top) !=
|
|
(Wnd->rectClient.top - Wnd->rectWindow.top)) ||
|
|
((lpOldClientRect->left - lpOldWndRect->left) !=
|
|
(Wnd->rectClient.left - Wnd->rectWindow.left)) )
|
|
{
|
|
if(uFlags & SWP_EX_PAINTSELF)
|
|
{
|
|
/* movement relative to the window itself */
|
|
dx = (Wnd->rectClient.left - Wnd->rectWindow.left) -
|
|
(lpOldClientRect->left - lpOldWndRect->left) ;
|
|
dy = (Wnd->rectClient.top - Wnd->rectWindow.top) -
|
|
(lpOldClientRect->top - lpOldWndRect->top) ;
|
|
}
|
|
else
|
|
{
|
|
/* movement relative to the parent's client area */
|
|
dx = Wnd->rectClient.left - lpOldClientRect->left;
|
|
dy = Wnd->rectClient.top - lpOldClientRect->top;
|
|
}
|
|
|
|
/* restrict valid bits to the common client rect */
|
|
|
|
r.left = Wnd->rectClient.left - Wnd->rectWindow.left;
|
|
r.top = Wnd->rectClient.top - Wnd->rectWindow.top;
|
|
r.right = r.left + min( ocw, ncw );
|
|
r.bottom = r.top + min( och, nch );
|
|
|
|
REGION_CropRgn( hrgnValid, hrgnValid, &r,
|
|
(uFlags & SWP_EX_PAINTSELF) ? NULL : (POINT*)&(Wnd->rectWindow));
|
|
GetRgnBox( hrgnValid, &r );
|
|
if( IsRectEmpty( &r ) )
|
|
goto nocopy;
|
|
r = *lpOldClientRect;
|
|
}
|
|
else
|
|
{
|
|
if(uFlags & SWP_EX_PAINTSELF) {
|
|
/*
|
|
* with SWP_EX_PAINTSELF, the window repaints itself. Since a window can't move
|
|
* relative to itself, only the client area can change.
|
|
* if the client rect didn't change, there's nothing to do.
|
|
*/
|
|
dx = 0;
|
|
dy = 0;
|
|
}
|
|
else
|
|
{
|
|
dx = Wnd->rectWindow.left - lpOldWndRect->left;
|
|
dy = Wnd->rectWindow.top - lpOldWndRect->top;
|
|
OffsetRgn( hrgnValid, Wnd->rectWindow.left, Wnd->rectWindow.top );
|
|
}
|
|
r = *lpOldWndRect;
|
|
}
|
|
|
|
if( !(uFlags & SWP_EX_PAINTSELF) )
|
|
{
|
|
/* Move remaining regions to parent coordinates */
|
|
OffsetRgn( newVisRgn, Wnd->rectWindow.left, Wnd->rectWindow.top );
|
|
OffsetRgn( *pVisRgn, lpOldWndRect->left, lpOldWndRect->top );
|
|
}
|
|
else
|
|
OffsetRect( &r, -lpOldWndRect->left, -lpOldWndRect->top );
|
|
|
|
TRACE("\tcomputing dirty region!\n");
|
|
|
|
/* Compute combined dirty region (old + new - valid) */
|
|
CombineRgn( *pVisRgn, *pVisRgn, newVisRgn, RGN_OR);
|
|
CombineRgn( *pVisRgn, *pVisRgn, hrgnValid, RGN_DIFF);
|
|
|
|
/* Blt valid bits, r is the rect to copy */
|
|
|
|
if( dx || dy )
|
|
{
|
|
RECT rClip;
|
|
HDC hDC;
|
|
|
|
/* get DC and clip rect with drawable rect to avoid superfluous expose events
|
|
from copying clipped areas */
|
|
|
|
if( uFlags & SWP_EX_PAINTSELF )
|
|
{
|
|
hDC = GetDCEx( Wnd->hwndSelf, hrgnValid, DCX_WINDOW | DCX_CACHE |
|
|
DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
|
|
rClip.right = nw; rClip.bottom = nh;
|
|
}
|
|
else
|
|
{
|
|
hDC = GetDCEx( Wnd->parent->hwndSelf, hrgnValid, DCX_CACHE |
|
|
DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_CLIPSIBLINGS );
|
|
rClip.right = Wnd->parent->rectClient.right - Wnd->parent->rectClient.left;
|
|
rClip.bottom = Wnd->parent->rectClient.bottom - Wnd->parent->rectClient.top;
|
|
}
|
|
rClip.left = rClip.top = 0;
|
|
|
|
if( oh > nh ) r.bottom = r.top + nh;
|
|
if( ow < nw ) r.right = r.left + nw;
|
|
|
|
if( IntersectRect( &r, &r, &rClip ) )
|
|
{
|
|
X11DRV_WND_SurfaceCopy( Wnd->parent, hDC, dx, dy, &r, TRUE );
|
|
|
|
/* When you copy the bits without repainting, parent doesn't
|
|
get validated appropriately. Therefore, we have to validate
|
|
the parent with the windows' updated region when the
|
|
parent's update region is not empty. */
|
|
|
|
if (Wnd->parent->hrgnUpdate != 0 && !(Wnd->parent->dwStyle & WS_CLIPCHILDREN))
|
|
{
|
|
OffsetRect(&r, dx, dy);
|
|
ValidateRect(Wnd->parent->hwndSelf, &r);
|
|
}
|
|
}
|
|
ReleaseDC( (uFlags & SWP_EX_PAINTSELF) ?
|
|
Wnd->hwndSelf : Wnd->parent->hwndSelf, hDC);
|
|
}
|
|
}
|
|
|
|
/* *pVisRgn now points to the invalidated region */
|
|
|
|
DeleteObject(newVisRgn);
|
|
DeleteObject(dirtyRgn);
|
|
return uFlags;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetWindowPos (X11DRV.@)
|
|
*/
|
|
BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
|
|
{
|
|
WND *wndPtr,*wndTemp;
|
|
RECT newWindowRect, newClientRect;
|
|
RECT oldWindowRect, oldClientRect;
|
|
HRGN visRgn = 0;
|
|
UINT wvrFlags = 0, uFlags = 0;
|
|
BOOL retvalue, resync = FALSE, bChangePos;
|
|
HWND hwndActive = GetForegroundWindow();
|
|
|
|
TRACE( "hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
|
|
winpos->hwnd, winpos->x, winpos->y,
|
|
winpos->x + winpos->cx, winpos->y + winpos->cy, winpos->flags);
|
|
|
|
bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
|
|
winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
|
|
|
|
/* ------------------------------------------------------------------------ CHECKS */
|
|
|
|
/* Check window handle */
|
|
|
|
if (winpos->hwnd == GetDesktopWindow()) return FALSE;
|
|
if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
|
|
|
|
TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n",
|
|
wndPtr->rectWindow.left, wndPtr->rectWindow.top,
|
|
wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
|
|
|
|
/* Fix redundant flags */
|
|
|
|
if(wndPtr->dwStyle & WS_VISIBLE)
|
|
winpos->flags &= ~SWP_SHOWWINDOW;
|
|
else
|
|
{
|
|
if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
|
|
winpos->flags &= ~SWP_HIDEWINDOW;
|
|
}
|
|
|
|
if ( winpos->cx < 0 ) winpos->cx = 0;
|
|
if ( winpos->cy < 0 ) winpos->cy = 0;
|
|
|
|
if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
|
|
(wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
|
|
winpos->flags |= SWP_NOSIZE; /* Already the right size */
|
|
|
|
if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
|
|
winpos->flags |= SWP_NOMOVE; /* Already the right position */
|
|
|
|
if (winpos->hwnd == hwndActive)
|
|
winpos->flags |= SWP_NOACTIVATE; /* Already active */
|
|
else if ( (wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD )
|
|
{
|
|
if(!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
|
|
{
|
|
winpos->flags &= ~SWP_NOZORDER;
|
|
winpos->hwndInsertAfter = HWND_TOP;
|
|
goto Pos;
|
|
}
|
|
}
|
|
|
|
/* Check hwndInsertAfter */
|
|
|
|
/* FIXME: TOPMOST not supported yet */
|
|
if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
|
|
(winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
|
|
|
|
/* hwndInsertAfter must be a sibling of the window */
|
|
if ((winpos->hwndInsertAfter != HWND_TOP) && (winpos->hwndInsertAfter != HWND_BOTTOM))
|
|
{
|
|
WND* wnd = WIN_FindWndPtr(winpos->hwndInsertAfter);
|
|
|
|
if( wnd ) {
|
|
if( wnd->parent != wndPtr->parent )
|
|
{
|
|
retvalue = FALSE;
|
|
WIN_ReleaseWndPtr(wnd);
|
|
goto END;
|
|
}
|
|
/* don't need to change the Zorder of hwnd if it's already inserted
|
|
* after hwndInsertAfter or when inserting hwnd after itself.
|
|
*/
|
|
if(( wnd->next == wndPtr ) || (winpos->hwnd == winpos->hwndInsertAfter))
|
|
winpos->flags |= SWP_NOZORDER;
|
|
}
|
|
WIN_ReleaseWndPtr(wnd);
|
|
}
|
|
|
|
Pos: /* ------------------------------------------------------------------------ MAIN part */
|
|
|
|
SWP_DoWinPosChanging( wndPtr, winpos, &newWindowRect, &newClientRect );
|
|
|
|
if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
|
|
{
|
|
if( wndPtr->parent == WIN_GetDesktop() )
|
|
winpos->hwndInsertAfter = SWP_DoOwnedPopups( wndPtr->parent, wndPtr,
|
|
winpos->hwndInsertAfter, winpos->flags );
|
|
WIN_ReleaseDesktop();
|
|
}
|
|
|
|
if(!(wndPtr->flags & WIN_NATIVE) )
|
|
{
|
|
if( winpos->hwndInsertAfter == HWND_TOP )
|
|
winpos->flags |= ( wndPtr->parent->child == wndPtr)? SWP_NOZORDER: 0;
|
|
else
|
|
if( winpos->hwndInsertAfter == HWND_BOTTOM )
|
|
winpos->flags |= ( wndPtr->next )? 0: SWP_NOZORDER;
|
|
else
|
|
if( !(winpos->flags & SWP_NOZORDER) )
|
|
if( GetWindow(winpos->hwndInsertAfter, GW_HWNDNEXT) == wndPtr->hwndSelf )
|
|
winpos->flags |= SWP_NOZORDER;
|
|
|
|
if( !(winpos->flags & (SWP_NOREDRAW | SWP_SHOWWINDOW)) &&
|
|
((winpos->flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW | SWP_FRAMECHANGED))
|
|
!= (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)) )
|
|
{
|
|
/* get a previous visible region for SWP_CopyValidBits() */
|
|
DWORD dflags = DCX_WINDOW;
|
|
|
|
if (wndPtr->dwStyle & WS_CLIPSIBLINGS)
|
|
dflags |= DCX_CLIPSIBLINGS;
|
|
|
|
visRgn = DCE_GetVisRgn(winpos->hwnd, dflags, 0, 0);
|
|
}
|
|
}
|
|
|
|
/* Common operations */
|
|
|
|
wvrFlags = SWP_DoNCCalcSize( wndPtr, winpos, &newWindowRect, &newClientRect, winpos->flags );
|
|
|
|
if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
|
|
{
|
|
if ( WIN_UnlinkWindow( winpos->hwnd ) )
|
|
WIN_LinkWindow( winpos->hwnd, winpos->hwndInsertAfter );
|
|
}
|
|
|
|
/* Reset active DCEs */
|
|
|
|
if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
|
|
wndPtr->dwStyle & WS_VISIBLE) ||
|
|
(winpos->flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
|
|
{
|
|
RECT rect;
|
|
|
|
UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
|
|
DCE_InvalidateDCE(wndPtr, &rect);
|
|
}
|
|
|
|
oldWindowRect = wndPtr->rectWindow;
|
|
oldClientRect = wndPtr->rectClient;
|
|
|
|
/* Find out if we have to redraw the whole client rect */
|
|
|
|
if( oldClientRect.bottom - oldClientRect.top ==
|
|
newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
|
|
|
|
if( oldClientRect.right - oldClientRect.left ==
|
|
newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
|
|
|
|
if( (winpos->flags & SWP_NOCOPYBITS) ||
|
|
(!(winpos->flags & SWP_NOCLIENTSIZE) &&
|
|
(wvrFlags >= WVR_HREDRAW) && (wvrFlags < WVR_VALIDRECTS)) )
|
|
{
|
|
uFlags |= SWP_EX_NOCOPY;
|
|
}
|
|
/*
|
|
* Use this later in CopyValidBits()
|
|
*
|
|
else if( 0 )
|
|
uFlags |= SWP_EX_NONCLIENT;
|
|
*/
|
|
|
|
/* FIXME: actually do something with WVR_VALIDRECTS */
|
|
|
|
wndPtr->rectWindow = newWindowRect;
|
|
wndPtr->rectClient = newClientRect;
|
|
|
|
if (wndPtr->flags & WIN_NATIVE) /* -------------------------------------------- hosted window */
|
|
{
|
|
BOOL bCallDriver = TRUE;
|
|
HWND tempInsertAfter = winpos->hwndInsertAfter;
|
|
|
|
winpos->hwndInsertAfter = winpos->hwndInsertAfter;
|
|
|
|
if( !(winpos->flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOREDRAW)) )
|
|
{
|
|
/* This is the only place where we need to force repainting of the contents
|
|
of windows created by the host window system, all other cases go through the
|
|
expose event handling */
|
|
|
|
if( (winpos->flags & (SWP_NOSIZE | SWP_FRAMECHANGED)) == (SWP_NOSIZE | SWP_FRAMECHANGED) )
|
|
{
|
|
winpos->cx = newWindowRect.right - newWindowRect.left;
|
|
winpos->cy = newWindowRect.bottom - newWindowRect.top;
|
|
|
|
X11DRV_WND_SetWindowPos(wndPtr, winpos, bChangePos);
|
|
winpos->hwndInsertAfter = tempInsertAfter;
|
|
bCallDriver = FALSE;
|
|
|
|
if( winpos->flags & SWP_NOCLIENTMOVE )
|
|
SWP_DoSimpleFrameChanged(wndPtr, &oldClientRect, winpos->flags, uFlags );
|
|
else
|
|
{
|
|
/* client area moved but window extents remained the same, copy valid bits */
|
|
|
|
visRgn = CreateRectRgn( 0, 0, winpos->cx, winpos->cy );
|
|
uFlags = SWP_CopyValidBits( wndPtr, &visRgn, &oldWindowRect, &oldClientRect,
|
|
uFlags | SWP_EX_PAINTSELF );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bCallDriver )
|
|
{
|
|
if( !(winpos->flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | SWP_NOREDRAW)) )
|
|
{
|
|
if( (oldClientRect.left - oldWindowRect.left == newClientRect.left - newWindowRect.left) &&
|
|
(oldClientRect.top - oldWindowRect.top == newClientRect.top - newWindowRect.top) &&
|
|
!(uFlags & SWP_EX_NOCOPY) )
|
|
{
|
|
/* The origin of the client rect didn't move so we can try to repaint
|
|
* only the nonclient area by setting bit gravity hint for the host window system.
|
|
*/
|
|
|
|
if( !(wndPtr->dwExStyle & WS_EX_MANAGED) )
|
|
{
|
|
HRGN hrgn = CreateRectRgn( 0, 0, newWindowRect.right - newWindowRect.left,
|
|
newWindowRect.bottom - newWindowRect.top);
|
|
RECT rcn = newClientRect;
|
|
RECT rco = oldClientRect;
|
|
|
|
OffsetRect( &rcn, -newWindowRect.left, -newWindowRect.top );
|
|
OffsetRect( &rco, -oldWindowRect.left, -oldWindowRect.top );
|
|
IntersectRect( &rcn, &rcn, &rco );
|
|
visRgn = CreateRectRgnIndirect( &rcn );
|
|
CombineRgn( visRgn, hrgn, visRgn, RGN_DIFF );
|
|
DeleteObject( hrgn );
|
|
uFlags = SWP_EX_PAINTSELF;
|
|
}
|
|
X11DRV_WND_SetGravity(wndPtr, NorthWestGravity );
|
|
}
|
|
}
|
|
|
|
X11DRV_WND_SetWindowPos(wndPtr, winpos, bChangePos);
|
|
X11DRV_WND_SetGravity(wndPtr, ForgetGravity );
|
|
winpos->hwndInsertAfter = tempInsertAfter;
|
|
}
|
|
|
|
if( winpos->flags & SWP_SHOWWINDOW )
|
|
{
|
|
HWND focus, curr;
|
|
|
|
wndPtr->dwStyle |= WS_VISIBLE;
|
|
|
|
if (wndPtr->dwExStyle & WS_EX_MANAGED) resync = TRUE;
|
|
|
|
/* focus was set to unmapped window, reset host focus
|
|
* since the window is now visible */
|
|
|
|
focus = curr = GetFocus();
|
|
while (curr)
|
|
{
|
|
if (curr == winpos->hwnd)
|
|
{
|
|
X11DRV_SetFocus(focus);
|
|
break;
|
|
}
|
|
curr = GetParent(curr);
|
|
}
|
|
}
|
|
}
|
|
else /* -------------------------------------------- emulated window */
|
|
{
|
|
if( winpos->flags & SWP_SHOWWINDOW )
|
|
{
|
|
wndPtr->dwStyle |= WS_VISIBLE;
|
|
uFlags |= SWP_EX_PAINTSELF;
|
|
visRgn = 1; /* redraw the whole window */
|
|
}
|
|
else if( !(winpos->flags & SWP_NOREDRAW) )
|
|
{
|
|
if( winpos->flags & SWP_HIDEWINDOW )
|
|
{
|
|
if( visRgn > 1 ) /* map to parent */
|
|
OffsetRgn( visRgn, oldWindowRect.left, oldWindowRect.top );
|
|
else
|
|
visRgn = 0;
|
|
}
|
|
else
|
|
{
|
|
if( (winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE )
|
|
uFlags = SWP_CopyValidBits(wndPtr, &visRgn, &oldWindowRect,
|
|
&oldClientRect, uFlags);
|
|
else
|
|
{
|
|
/* nothing moved, redraw frame if needed */
|
|
|
|
if( winpos->flags & SWP_FRAMECHANGED )
|
|
SWP_DoSimpleFrameChanged( wndPtr, &oldClientRect, winpos->flags, uFlags );
|
|
if( visRgn )
|
|
{
|
|
DeleteObject( visRgn );
|
|
visRgn = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( winpos->flags & SWP_HIDEWINDOW )
|
|
{
|
|
wndPtr->dwStyle &= ~WS_VISIBLE;
|
|
}
|
|
|
|
if (winpos->hwnd == CARET_GetHwnd())
|
|
{
|
|
if( winpos->flags & SWP_HIDEWINDOW )
|
|
HideCaret(winpos->hwnd);
|
|
else if (winpos->flags & SWP_SHOWWINDOW)
|
|
ShowCaret(winpos->hwnd);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ FINAL */
|
|
|
|
if (wndPtr->flags & WIN_NATIVE)
|
|
X11DRV_Synchronize(); /* Synchronize with the host window system */
|
|
|
|
wndTemp = WIN_GetDesktop();
|
|
|
|
/* repaint invalidated region (if any)
|
|
*
|
|
* FIXME: if SWP_NOACTIVATE is not set then set invalid regions here without any painting
|
|
* and force update after ChangeActiveWindow() to avoid painting frames twice.
|
|
*/
|
|
|
|
if( visRgn )
|
|
{
|
|
if( !(winpos->flags & SWP_NOREDRAW) )
|
|
{
|
|
|
|
/* Use PAINT_RedrawWindow to explicitly force an invalidation of the window,
|
|
its parent and sibling and so on, and then erase the parent window
|
|
background if the parent is either a top-level window or its parent's parent
|
|
is top-level window. Rely on the system to repaint other affected
|
|
windows later on. */
|
|
if( uFlags & SWP_EX_PAINTSELF )
|
|
{
|
|
PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, (visRgn == 1) ? 0 : visRgn,
|
|
RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN,
|
|
RDW_EX_XYWINDOW | RDW_EX_USEHRGN );
|
|
}
|
|
else
|
|
{
|
|
PAINT_RedrawWindow( wndPtr->parent->hwndSelf, NULL, (visRgn == 1) ? 0 : visRgn,
|
|
RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN,
|
|
RDW_EX_USEHRGN );
|
|
}
|
|
|
|
if(wndPtr -> parent == wndTemp || wndPtr->parent->parent == wndTemp )
|
|
{
|
|
RedrawWindow( wndPtr->parent->hwndSelf, NULL, 0,
|
|
RDW_ERASENOW | RDW_NOCHILDREN );
|
|
}
|
|
}
|
|
if( visRgn != 1 )
|
|
DeleteObject( visRgn );
|
|
}
|
|
|
|
WIN_ReleaseDesktop();
|
|
|
|
if (!(winpos->flags & SWP_NOACTIVATE))
|
|
WINPOS_ChangeActiveWindow( winpos->hwnd, FALSE );
|
|
|
|
/* And last, send the WM_WINDOWPOSCHANGED message */
|
|
|
|
TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
|
|
|
|
if ( resync ||
|
|
(((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
|
|
!(winpos->flags & SWP_NOSENDCHANGING)) )
|
|
{
|
|
SendMessageA( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
|
|
if (resync) X11DRV_Synchronize();
|
|
}
|
|
|
|
retvalue = TRUE;
|
|
END:
|
|
WIN_ReleaseWndPtr(wndPtr);
|
|
return retvalue;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* SetWindowRgn (X11DRV.@)
|
|
*
|
|
* Assign specified region to window (for non-rectangular windows)
|
|
*/
|
|
BOOL X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
|
|
{
|
|
RECT rect;
|
|
WND *wndPtr = WIN_FindWndPtr(hwnd);
|
|
int ret = FALSE;
|
|
|
|
if (!wndPtr) return FALSE;
|
|
|
|
if (wndPtr->hrgnWnd == hrgn)
|
|
{
|
|
ret = TRUE;
|
|
goto done;
|
|
}
|
|
|
|
if (hrgn) /* verify that region really exists */
|
|
{
|
|
if (GetRgnBox( hrgn, &rect ) == ERROR) goto done;
|
|
}
|
|
|
|
if (wndPtr->hrgnWnd)
|
|
{
|
|
/* delete previous region */
|
|
DeleteObject(wndPtr->hrgnWnd);
|
|
wndPtr->hrgnWnd = 0;
|
|
}
|
|
wndPtr->hrgnWnd = hrgn;
|
|
|
|
/* Size the window to the rectangle of the new region (if it isn't NULL) */
|
|
if (hrgn) SetWindowPos( hwnd, 0, rect.left, rect.top,
|
|
rect.right - rect.left, rect.bottom - rect.top,
|
|
SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE |
|
|
SWP_NOZORDER | (redraw ? 0 : SWP_NOREDRAW) );
|
|
#ifdef HAVE_LIBXSHAPE
|
|
{
|
|
Window win = X11DRV_WND_GetXWindow(wndPtr);
|
|
|
|
if (win)
|
|
{
|
|
if (!hrgn)
|
|
{
|
|
TSXShapeCombineMask( display, win, ShapeBounding, 0, 0, None, ShapeSet );
|
|
}
|
|
else
|
|
{
|
|
XRectangle *aXRect;
|
|
DWORD size;
|
|
DWORD dwBufferSize = GetRegionData(hrgn, 0, NULL);
|
|
PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
|
|
if (!pRegionData) goto done;
|
|
|
|
GetRegionData(hrgn, dwBufferSize, pRegionData);
|
|
size = pRegionData->rdh.nCount;
|
|
/* convert region's "Windows rectangles" to XRectangles */
|
|
aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
|
|
if (aXRect)
|
|
{
|
|
XRectangle* pCurrRect = aXRect;
|
|
RECT *pRect = (RECT*) pRegionData->Buffer;
|
|
for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
|
|
{
|
|
pCurrRect->x = pRect->left;
|
|
pCurrRect->y = pRect->top;
|
|
pCurrRect->height = pRect->bottom - pRect->top;
|
|
pCurrRect->width = pRect->right - pRect->left;
|
|
|
|
TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
|
|
pRect - (RECT*) pRegionData->Buffer,
|
|
size,
|
|
pCurrRect->x,
|
|
pCurrRect->y,
|
|
pCurrRect->height,
|
|
pCurrRect->width);
|
|
}
|
|
|
|
/* shape = non-rectangular windows (X11/extensions) */
|
|
TSXShapeCombineRectangles( display, win, ShapeBounding,
|
|
0, 0, aXRect,
|
|
pCurrRect - aXRect, ShapeSet, YXBanded );
|
|
HeapFree(GetProcessHeap(), 0, aXRect );
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, pRegionData);
|
|
}
|
|
}
|
|
}
|
|
#endif /* HAVE_LIBXSHAPE */
|
|
|
|
ret = TRUE;
|
|
|
|
done:
|
|
WIN_ReleaseWndPtr(wndPtr);
|
|
return ret;
|
|
}
|