diff --git a/dlls/ttydrv/wnd.c b/dlls/ttydrv/wnd.c index 11cca66958..a9f4e5800f 100644 --- a/dlls/ttydrv/wnd.c +++ b/dlls/ttydrv/wnd.c @@ -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 ); diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index fbffc81653..1c3dd8dc24 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -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, diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 71e4e455de..72a0a25016 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -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 ); } diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index 65149ecc7e..73645953aa 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -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); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2cc4897b40..9719654cdb 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -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 */ diff --git a/server/protocol.def b/server/protocol.def index 6873faa392..3307e93428 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -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 diff --git a/server/trace.c b/server/trace.c index d54294dbf8..146d0f2754 100644 --- a/server/trace.c +++ b/server/trace.c @@ -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 ) diff --git a/server/window.c b/server/window.c index c7af5e8c0d..5e1509c485 100644 --- a/server/window.c +++ b/server/window.c @@ -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; }