Properly compute the client area valid rects and pass them to the

server in set_window_pos to avoid invalidating areas that remain
valid.
This commit is contained in:
Alexandre Julliard 2005-02-03 13:40:12 +00:00
parent 69d3afc99e
commit ae661da49c
8 changed files with 168 additions and 54 deletions

View File

@ -83,7 +83,7 @@ static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags )
* Set a window position and Z order.
*/
static void set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow,
const RECT *rectClient, UINT swp_flags, UINT wvr_flags )
const RECT *rectClient, UINT swp_flags )
{
WND *win = WIN_GetPtr( hwnd );
BOOL ret;
@ -100,7 +100,6 @@ static void set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
req->top_win = 0;
req->previous = insert_after;
req->flags = swp_flags;
req->redraw_flags = wvr_flags;
req->window.left = rectWindow->left;
req->window.top = rectWindow->top;
req->window.right = rectWindow->right;
@ -139,7 +138,7 @@ BOOL TTYDRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
/* initialize the dimensions before sending WM_GETMINMAXINFO */
SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, 0 );
set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER );
parent = GetAncestor( hwnd, GA_PARENT );
if (!parent) /* desktop window */
@ -415,7 +414,7 @@ BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos )
/* FIXME: actually do something with WVR_VALIDRECTS */
set_window_pos( winpos->hwnd, winpos->hwndInsertAfter,
&newWindowRect, &newClientRect, winpos->flags, wvrFlags );
&newWindowRect, &newClientRect, winpos->flags );
if( winpos->flags & SWP_SHOWWINDOW )
WIN_SetStyle( winpos->hwnd, WS_VISIBLE, 0 );

View File

@ -589,15 +589,15 @@ void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect )
* Synchronize the X window position with the Windows one
*/
void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data,
UINT swp_flags, const RECT *new_client_rect )
UINT swp_flags, const RECT *new_client_rect,
const RECT *new_whole_rect )
{
XWindowChanges changes;
int mask;
RECT old_whole_rect;
old_whole_rect = data->whole_rect;
data->whole_rect = data->window_rect;
X11DRV_window_to_X_rect( data, &data->whole_rect );
data->whole_rect = *new_whole_rect;
data->client_rect = *new_client_rect;
OffsetRect( &data->client_rect, -data->whole_rect.left, -data->whole_rect.top );
@ -706,9 +706,9 @@ static Window create_whole_window( Display *display, struct x11drv_win_data *dat
mask = get_window_attributes( data, &attr );
/* set the attributes that don't change over the lifetime of the window */
attr.bit_gravity = ForgetGravity;
attr.win_gravity = NorthWestGravity;
attr.backing_store = NotUseful/*WhenMapped*/;
attr.bit_gravity = NorthWestGravity;
attr.win_gravity = StaticGravity;
attr.backing_store = NotUseful;
mask |= CWBitGravity | CWWinGravity | CWBackingStore;
wine_tsx11_lock();
@ -910,7 +910,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
/* initialize the dimensions before sending WM_GETMINMAXINFO */
SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, 0 );
X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL );
parent = GetAncestor( hwnd, GA_PARENT );
if (!parent)
@ -946,7 +946,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
if (cs->cy < 0) cs->cy = 0;
SetRect( &rect, cs->x, cs->y, cs->x + cs->cx, cs->y + cs->cy );
if (!X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, 0 )) return FALSE;
if (!X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER, NULL )) return FALSE;
}
/* send WM_NCCREATE */
@ -979,7 +979,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
/* yes, even if the CBT hook was called with HWND_TOP */
insert_after = ((wndPtr->dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
X11DRV_set_window_pos( hwnd, insert_after, &wndPtr->rectWindow, &rect, 0, 0 );
X11DRV_set_window_pos( hwnd, insert_after, &wndPtr->rectWindow, &rect, 0, NULL );
TRACE( "win %p window %ld,%ld,%ld,%ld client %ld,%ld,%ld,%ld whole %ld,%ld,%ld,%ld X client %ld,%ld,%ld,%ld xwin %x\n",
hwnd, wndPtr->rectWindow.left, wndPtr->rectWindow.top,

View File

@ -47,10 +47,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
#define SWP_AGG_NOGEOMETRYCHANGE \
(SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
#define SWP_AGG_NOPOSCHANGE \
(SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
(SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
#define SWP_AGG_STATUSFLAGS \
(SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
@ -328,10 +326,74 @@ static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT
return TRUE;
}
/***********************************************************************
* get_valid_rects
*
* Compute the valid rects from the old and new client rect and WVR_* flags.
* Helper for WM_NCCALCSIZE handling.
*/
static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
RECT *valid )
{
int cx, cy;
if (flags & WVR_REDRAW)
{
SetRectEmpty( &valid[0] );
SetRectEmpty( &valid[1] );
return;
}
if (flags & WVR_VALIDRECTS)
{
if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
!IntersectRect( &valid[1], &valid[1], old_client ))
{
SetRectEmpty( &valid[0] );
SetRectEmpty( &valid[1] );
return;
}
flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
}
else
{
valid[0] = *new_client;
valid[1] = *old_client;
}
/* make sure the rectangles have the same size */
cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );
if (flags & WVR_ALIGNBOTTOM)
{
valid[0].top = valid[0].bottom - cy;
valid[1].top = valid[1].bottom - cy;
}
else
{
valid[0].bottom = valid[0].top + cy;
valid[1].bottom = valid[1].top + cy;
}
if (flags & WVR_ALIGNRIGHT)
{
valid[0].left = valid[0].right - cx;
valid[1].left = valid[1].right - cx;
}
else
{
valid[0].right = valid[0].left + cx;
valid[1].right = valid[1].left + cx;
}
}
/***********************************************************************
* SWP_DoNCCalcSize
*/
static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect )
static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect,
RECT *validRects )
{
UINT wvrFlags = 0;
WND *wndPtr;
@ -374,10 +436,19 @@ static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RE
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) )
wndPtr->rectClient.right - wndPtr->rectClient.left))
pWinpos->flags &= ~SWP_NOCLIENTSIZE;
else
wvrFlags &= ~WVR_HREDRAW;
if (pNewClientRect->bottom - pNewClientRect->top !=
wndPtr->rectClient.bottom - wndPtr->rectClient.top)
pWinpos->flags &= ~SWP_NOCLIENTSIZE;
else
wvrFlags &= ~WVR_VREDRAW;
validRects[0] = params.rgrc[1];
validRects[1] = params.rgrc[2];
}
else
{
@ -386,6 +457,14 @@ static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RE
pNewClientRect->top != wndPtr->rectClient.top))
pWinpos->flags &= ~SWP_NOCLIENTMOVE;
}
if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
{
SetRectEmpty( &validRects[0] );
SetRectEmpty( &validRects[1] );
}
else get_valid_rects( &wndPtr->rectClient, pNewClientRect, wvrFlags, validRects );
WIN_ReleasePtr( wndPtr );
return wvrFlags;
}
@ -607,15 +686,39 @@ void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style )
* Set a window position and Z order.
*/
BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow,
const RECT *rectClient, UINT swp_flags, UINT wvr_flags )
const RECT *rectClient, UINT swp_flags, const RECT *valid_rects )
{
struct x11drv_win_data *data;
HWND top = get_top_clipping_window( hwnd );
RECT new_whole_rect;
WND *win;
DWORD old_style, new_style;
BOOL ret;
if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE;
new_whole_rect = *rectWindow;
X11DRV_window_to_X_rect( data, &new_whole_rect );
if (!IsRectEmpty( &valid_rects[0] ))
{
int x_offset = 0, y_offset = 0;
if (data->whole_window)
{
/* the X server will move the bits for us */
x_offset = data->whole_rect.left - new_whole_rect.left;
y_offset = data->whole_rect.top - new_whole_rect.top;
}
if (x_offset != valid_rects[1].left - valid_rects[0].left ||
y_offset != valid_rects[1].top - valid_rects[0].top)
{
/* FIXME: should copy the window bits here */
valid_rects = NULL;
}
}
if (!(win = WIN_GetPtr( hwnd ))) return FALSE;
if (win == WND_OTHER_PROCESS)
{
@ -629,7 +732,6 @@ BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
req->top_win = top;
req->previous = insert_after;
req->flags = swp_flags & ~SWP_WINE_NOHOSTMOVE;
req->redraw_flags = wvr_flags;
req->window.left = rectWindow->left;
req->window.top = rectWindow->top;
req->window.right = rectWindow->right;
@ -638,6 +740,8 @@ BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
req->client.top = rectClient->top;
req->client.right = rectClient->right;
req->client.bottom = rectClient->bottom;
if (!IsRectEmpty( &valid_rects[0] ))
wine_server_add_data( req, valid_rects, 2 * sizeof(*valid_rects) );
ret = !wine_server_call( req );
new_style = reply->new_style;
}
@ -674,7 +778,7 @@ BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
/* window got hidden, unmap it */
TRACE( "unmapping win %p\n", hwnd );
wine_tsx11_lock();
XUnmapWindow( thread_display(), data->whole_window );
XUnmapWindow( display, data->whole_window );
wine_tsx11_unlock();
}
else if ((new_style & WS_VISIBLE) && !X11DRV_is_window_rect_mapped( rectWindow ))
@ -687,7 +791,7 @@ BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
}
}
X11DRV_sync_window_position( display, data, swp_flags, rectClient );
X11DRV_sync_window_position( display, data, swp_flags, rectClient, &new_whole_rect );
if (data->whole_window)
{
@ -727,8 +831,8 @@ BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
*/
BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
{
RECT newWindowRect, newClientRect;
UINT wvr_flags, orig_flags;
RECT newWindowRect, newClientRect, valid_rects[2];
UINT orig_flags;
TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
@ -769,13 +873,10 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
/* Common operations */
wvr_flags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect );
/* FIXME: actually do something with WVR_VALIDRECTS */
SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect, valid_rects );
if (!X11DRV_set_window_pos( winpos->hwnd, winpos->hwndInsertAfter,
&newWindowRect, &newClientRect,
orig_flags, wvr_flags ))
&newWindowRect, &newClientRect, orig_flags, valid_rects ))
return FALSE;
if( winpos->flags & SWP_HIDEWINDOW )
@ -1316,7 +1417,7 @@ void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height )
screen_height = height;
TRACE("desktop %p change to (%dx%d)\n", hwnd, width, height);
SetRect( &rect, 0, 0, width, height );
X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER|SWP_NOMOVE|SWP_WINE_NOHOSTMOVE, 0 );
X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER|SWP_NOMOVE|SWP_WINE_NOHOSTMOVE, NULL );
SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_depth,
MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
}

View File

@ -565,9 +565,10 @@ extern void X11DRV_create_desktop_thread(void);
extern Window X11DRV_create_desktop( XVisualInfo *desktop_vi, const char *geometry );
extern void X11DRV_sync_window_style( Display *display, struct x11drv_win_data *data );
extern void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data,
UINT swp_flags, const RECT *new_client_rect );
UINT swp_flags, const RECT *new_client_rect,
const RECT *new_whole_rect );
extern BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow,
const RECT *rectClient, UINT swp_flags, UINT wvr_flags );
const RECT *rectClient, UINT swp_flags, const RECT *validRects );
extern void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data );
extern void X11DRV_handle_desktop_resize(unsigned int width, unsigned int height);

View File

@ -2583,9 +2583,9 @@ struct set_window_pos_request
user_handle_t top_win;
user_handle_t previous;
unsigned int flags;
unsigned int redraw_flags;
rectangle_t window;
rectangle_t client;
/* VARARG(valid,rectangles); */
};
struct set_window_pos_reply
{
@ -3712,6 +3712,6 @@ union generic_reply
struct set_global_windows_reply set_global_windows_reply;
};
#define SERVER_PROTOCOL_VERSION 154
#define SERVER_PROTOCOL_VERSION 155
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -1825,9 +1825,9 @@ enum message_type
user_handle_t top_win; /* top window to clip against */
user_handle_t previous; /* previous window in Z order */
unsigned int flags; /* SWP_* flags */
unsigned int redraw_flags; /* WVR_* flags */
rectangle_t window; /* window rectangle */
rectangle_t client; /* client rectangle */
VARARG(valid,rectangles); /* valid rectangles from WM_NCCALCSIZE */
@REPLY
unsigned int new_style; /* new window style */
@END

View File

@ -2174,12 +2174,14 @@ static void dump_set_window_pos_request( const struct set_window_pos_request *re
fprintf( stderr, " top_win=%p,", req->top_win );
fprintf( stderr, " previous=%p,", req->previous );
fprintf( stderr, " flags=%08x,", req->flags );
fprintf( stderr, " redraw_flags=%08x,", req->redraw_flags );
fprintf( stderr, " window=" );
dump_rectangle( &req->window );
fprintf( stderr, "," );
fprintf( stderr, " client=" );
dump_rectangle( &req->client );
fprintf( stderr, "," );
fprintf( stderr, " valid=" );
dump_varargs_rectangles( cur_size );
}
static void dump_set_window_pos_reply( const struct set_window_pos_reply *req )

View File

@ -1075,8 +1075,8 @@ static int validate_window_rectangles( const rectangle_t *window_rect, const rec
/* set the window and client rectangles, updating the update region if necessary */
static void set_window_pos( struct window *win, struct window *top, struct window *previous,
unsigned int swp_flags, unsigned int wvr_flags,
const rectangle_t *window_rect, const rectangle_t *client_rect )
unsigned int swp_flags, const rectangle_t *window_rect,
const rectangle_t *client_rect, const rectangle_t *valid_rects )
{
struct region *old_vis_rgn, *new_vis_rgn;
const rectangle_t old_window_rect = win->window_rect;
@ -1114,9 +1114,13 @@ static void set_window_pos( struct window *win, struct window *top, struct windo
/* expose anything revealed by the change */
offset_region( old_vis_rgn, old_window_rect.left - window_rect->left,
old_window_rect.top - window_rect->top );
if (xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn )) expose_window( win, top, new_vis_rgn );
if (!(swp_flags & SWP_NOREDRAW))
{
offset_region( old_vis_rgn, old_window_rect.left - window_rect->left,
old_window_rect.top - window_rect->top );
if (xor_region( new_vis_rgn, old_vis_rgn, new_vis_rgn ))
expose_window( win, top, new_vis_rgn );
}
free_region( old_vis_rgn );
if (!(win->style & WS_VISIBLE))
@ -1126,32 +1130,36 @@ static void set_window_pos( struct window *win, struct window *top, struct windo
goto done;
}
if (swp_flags & SWP_NOREDRAW) goto done; /* do not repaint anything */
/* expose the whole non-client area if it changed in any way */
if ((swp_flags & SWP_FRAMECHANGED) ||
memcmp( window_rect, &old_window_rect, sizeof(old_window_rect) ) ||
memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) ))
{
struct region *tmp = create_region( client_rect, 1 );
struct region *tmp;
/* subtract the valid portion of client rect from the total region */
if (!memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) ))
tmp = create_region( client_rect, 1 );
else if (valid_rects)
tmp = create_region( &valid_rects[0], 1 );
else
tmp = create_empty_region();
if (tmp)
{
set_region_rect( new_vis_rgn, window_rect );
if (subtract_region( tmp, new_vis_rgn, tmp ))
{
offset_region( tmp, -window_rect->left, -window_rect->top );
add_update_region( win, tmp );
offset_region( tmp, -client_rect->left, -client_rect->top );
redraw_window( win, tmp, 1, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
}
else free_region( tmp );
free_region( tmp );
}
}
/* expose/validate new client areas + children */
/* FIXME: expose everything for now */
if (memcmp( client_rect, &old_client_rect, sizeof(old_client_rect) ))
redraw_window( win, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
done:
free_region( new_vis_rgn );
clear_error(); /* we ignore out of memory errors once the new rects have been set */
@ -1434,6 +1442,7 @@ DECL_HANDLER(get_window_tree)
/* set the position and Z order of a window */
DECL_HANDLER(set_window_pos)
{
const rectangle_t *valid_rects = NULL;
struct window *previous = NULL;
struct window *top = top_window;
struct window *win = get_window( req->handle );
@ -1476,7 +1485,9 @@ DECL_HANDLER(set_window_pos)
return;
}
set_window_pos( win, top, previous, flags, req->redraw_flags, &req->window, &req->client );
if (get_req_data_size() >= 2 * sizeof(rectangle_t)) valid_rects = get_req_data();
set_window_pos( win, top, previous, flags, &req->window, &req->client, valid_rects );
reply->new_style = win->style;
}