From bc75f2f6c96915e4ca2c62b326648dc2d80fd296 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 31 Mar 2005 15:36:57 +0000 Subject: [PATCH] Return the coordinates information needed to setup the DC parameters in the get_visible_region request instead of requiring the client to compute it again. --- dlls/x11drv/dce.c | 156 +++++++++------------------------ include/wine/server_protocol.h | 7 +- server/protocol.def | 7 +- server/trace.c | 5 ++ server/window.c | 42 +++++---- 5 files changed, 85 insertions(+), 132 deletions(-) diff --git a/dlls/x11drv/dce.c b/dlls/x11drv/dce.c index 72f8ca77b77..2de1578b1d5 100644 --- a/dlls/x11drv/dce.c +++ b/dlls/x11drv/dce.c @@ -86,21 +86,33 @@ static void dump_cache(void) /*********************************************************************** - * get_server_visible_region + * update_visible_region + * + * Set the visible region and X11 drawable for the DC associated to + * a given window. */ -static HRGN get_server_visible_region( HWND hwnd, UINT flags ) +static void update_visible_region( struct dce *dce ) { - RGNDATA *data; NTSTATUS status; - HRGN ret = 0; + HRGN vis_rgn = 0; + HWND top = 0; + struct x11drv_escape_set_drawable escape; + struct x11drv_win_data *data; + DWORD flags = dce->flags; size_t size = 256; + /* don't clip siblings if using parent clip region */ + if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS; + + /* fetch the visible region from the server */ do { - if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) return 0; + RGNDATA *data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ); + if (!data) return; + SERVER_START_REQ( get_visible_region ) { - req->window = hwnd; + req->window = dce->hwnd; req->flags = flags; wine_server_set_reply( req, data->Buffer, size ); if (!(status = wine_server_call( req ))) @@ -110,7 +122,13 @@ static HRGN get_server_visible_region( HWND hwnd, UINT flags ) data->rdh.iType = RDH_RECTANGLES; data->rdh.nCount = reply_size / sizeof(RECT); data->rdh.nRgnSize = reply_size; - ret = ExtCreateRegion( NULL, size, data ); + vis_rgn = ExtCreateRegion( NULL, size, data ); + + top = reply->top_win; + escape.org.x = reply->win_org_x - reply->top_org_x; + escape.org.y = reply->win_org_y - reply->top_org_y; + escape.drawable_org.x = reply->top_org_x; + escape.drawable_org.y = reply->top_org_y; } else size = reply->total_size; } @@ -118,119 +136,27 @@ static HRGN get_server_visible_region( HWND hwnd, UINT flags ) HeapFree( GetProcessHeap(), 0, data ); } while (status == STATUS_BUFFER_OVERFLOW); - if (status) SetLastError( RtlNtStatusToDosError(status) ); - return ret; -} + if (status || !vis_rgn) return; + if (dce->clip_rgn) CombineRgn( vis_rgn, vis_rgn, dce->clip_rgn, + (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); -/*********************************************************************** - * get_top_clipping_window - * - * Get the top window to clip against (i.e. the top parent that has - * an associated X window). - */ -static HWND get_top_clipping_window( HWND hwnd ) -{ - HWND ret = GetAncestor( hwnd, GA_ROOT ); - if (!ret) ret = GetDesktopWindow(); - return ret; -} - - -/*********************************************************************** - * set_drawable - * - * Set the drawable, origin and dimensions for the DC associated to - * a given window. - */ -static void set_drawable( struct dce *dce, BOOL update_visrgn ) -{ - HWND top = get_top_clipping_window( dce->hwnd ); - struct x11drv_escape_set_drawable escape; - struct x11drv_win_data *data; - DWORD flags = dce->flags; - - escape.mode = IncludeInferiors; - /* don't clip siblings if using parent clip region */ - if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS; - - if (top != dce->hwnd || !(data = X11DRV_get_win_data( dce->hwnd ))) - { - POINT client_offset; - - if (flags & DCX_WINDOW) - { - RECT rect; - GetWindowRect( dce->hwnd, &rect ); - escape.org.x = rect.left; - escape.org.y = rect.top; - MapWindowPoints( 0, top, &escape.org, 1 ); - escape.drawable_org.x = rect.left - escape.org.x; - escape.drawable_org.y = rect.top - escape.org.y; - } - else - { - escape.org.x = escape.org.y = 0; - escape.drawable_org.x = escape.drawable_org.y = 0; - MapWindowPoints( dce->hwnd, top, &escape.org, 1 ); - MapWindowPoints( top, 0, &escape.drawable_org, 1 ); - } - - /* now make origins relative to the X window and not the client area */ - client_offset = X11DRV_get_client_area_offset( top ); - escape.org.x += client_offset.x; - escape.org.y += client_offset.y; - escape.drawable_org.x -= client_offset.x; - escape.drawable_org.y -= client_offset.y; - escape.drawable = X11DRV_get_whole_window( top ); - } + if (top == dce->hwnd && ((data = X11DRV_get_win_data( dce->hwnd )) != NULL) && + IsIconic( dce->hwnd ) && data->icon_window) + escape.drawable = data->icon_window; else - { - if (IsIconic( dce->hwnd )) - { - escape.drawable = data->icon_window ? data->icon_window : data->whole_window; - escape.org.x = 0; - escape.org.y = 0; - escape.drawable_org = escape.org; - MapWindowPoints( dce->hwnd, 0, &escape.drawable_org, 1 ); - } - else - { - escape.drawable = data->whole_window; - escape.drawable_org.x = data->whole_rect.left; - escape.drawable_org.y = data->whole_rect.top; - if (flags & DCX_WINDOW) - { - escape.org.x = data->window_rect.left - data->whole_rect.left; - escape.org.y = data->window_rect.top - data->whole_rect.top; - } - else - { - escape.org.x = data->client_rect.left; - escape.org.y = data->client_rect.top; - } - } - } + escape.drawable = X11DRV_get_whole_window( top ); escape.code = X11DRV_SET_DRAWABLE; + escape.mode = IncludeInferiors; ExtEscape( dce->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); - if (update_visrgn) - { - /* need to recompute the visible region */ - HRGN visRgn = get_server_visible_region( dce->hwnd, flags ); - - if (dce->clip_rgn) - CombineRgn( visRgn, visRgn, dce->clip_rgn, - (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); - - /* map region to DC coordinates */ - OffsetRgn( visRgn, -(escape.org.x + escape.drawable_org.x), - -(escape.org.y + escape.drawable_org.y) ); - - SelectVisRgn16( HDC_16(dce->hdc), HRGN_16(visRgn) ); - DeleteObject( visRgn ); - } + /* map region to DC coordinates */ + OffsetRgn( vis_rgn, + -(escape.drawable_org.x + escape.org.x), + -(escape.drawable_org.y + escape.org.y) ); + SelectVisRgn16( HDC_16(dce->hdc), HRGN_16(vis_rgn) ); + DeleteObject( vis_rgn ); } @@ -619,7 +545,7 @@ HDC X11DRV_GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags ) if (SetHookFlags16( HDC_16(dce->hdc), DCHF_VALIDATEVISRGN )) bUpdateVisRgn = TRUE; /* DC was dirty */ - set_drawable( dce, bUpdateVisRgn ); + if (bUpdateVisRgn) update_visible_region( dce ); if (!(flags & DCX_NORESETATTRS)) { @@ -678,7 +604,7 @@ static BOOL16 CALLBACK dc_hook( HDC16 hDC, WORD code, DWORD data, LPARAM lParam * DC is dirty (usually after SetHookFlags()). This * means that we have to recompute the visible region. */ - if (dce->count) set_drawable( dce, TRUE ); + if (dce->count) update_visible_region( dce ); else /* non-fatal but shouldn't happen */ WARN("DC is not in use!\n"); break; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e5d80ad3219..5ad2dd6fb94 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2675,6 +2675,11 @@ struct get_visible_region_request struct get_visible_region_reply { struct reply_header __header; + user_handle_t top_win; + int top_org_x; + int top_org_y; + int win_org_x; + int win_org_y; size_t total_size; /* VARARG(region,rectangles); */ }; @@ -3872,6 +3877,6 @@ union generic_reply struct set_mailslot_info_reply set_mailslot_info_reply; }; -#define SERVER_PROTOCOL_VERSION 165 +#define SERVER_PROTOCOL_VERSION 166 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index d035abdf79d..472433653a8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1882,8 +1882,13 @@ enum message_type user_handle_t window; /* handle to the window */ unsigned int flags; /* DCX flags */ @REPLY + user_handle_t top_win; /* top window to clip against */ + int top_org_x; /* top window visible rect origin in screen coords */ + int top_org_y; + int win_org_x; /* window rect origin in screen coords */ + int win_org_y; size_t total_size; /* total size of the resulting region */ - VARARG(region,rectangles); /* list of rectangles for the region */ + VARARG(region,rectangles); /* list of rectangles for the region (in screen coords) */ @END diff --git a/server/trace.c b/server/trace.c index cda0973bae6..e025f59fbd9 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2268,6 +2268,11 @@ static void dump_get_visible_region_request( const struct get_visible_region_req static void dump_get_visible_region_reply( const struct get_visible_region_reply *req ) { + fprintf( stderr, " top_win=%p,", req->top_win ); + fprintf( stderr, " top_org_x=%d,", req->top_org_x ); + fprintf( stderr, " top_org_y=%d,", req->top_org_y ); + fprintf( stderr, " win_org_x=%d,", req->win_org_x ); + fprintf( stderr, " win_org_y=%d,", req->win_org_y ); fprintf( stderr, " total_size=%d,", req->total_size ); fprintf( stderr, " region=" ); dump_varargs_rectangles( cur_size ); diff --git a/server/window.c b/server/window.c index 26889faa980..dacd1af676c 100644 --- a/server/window.c +++ b/server/window.c @@ -633,17 +633,22 @@ static struct region *intersect_window_region( struct region *region, struct win } +/* convert coordinates from client to screen coords */ +static inline void client_to_screen( struct window *win, int *x, int *y ) +{ + for ( ; win; win = win->parent) + { + *x += win->client_rect.left; + *y += win->client_rect.top; + } +} + /* map the region from window to screen coordinates */ static inline void map_win_region_to_screen( struct window *win, struct region *region ) { int x = win->window_rect.left; int y = win->window_rect.top; - - for (win = win->parent; win; win = win->parent) - { - x += win->client_rect.left; - y += win->client_rect.top; - } + client_to_screen( win->parent, &x, &y ); offset_region( region, x, y ); } @@ -706,11 +711,10 @@ static inline struct window *get_top_clipping_window( struct window *win ) /* compute the visible region of a window, in window coordinates */ -static struct region *get_visible_region( struct window *win, unsigned int flags ) +static struct region *get_visible_region( struct window *win, struct window *top, unsigned int flags ) { struct region *tmp, *region; int offset_x, offset_y; - struct window *top = get_top_clipping_window( win ); if (!(region = create_empty_region())) return NULL; @@ -1069,11 +1073,10 @@ static unsigned int get_child_update_flags( struct window *win, unsigned int fla /* expose a region of a window, looking for the top most parent that needs to be exposed */ /* the region is in window coordinates */ -static void expose_window( struct window *win, struct region *region ) +static void expose_window( struct window *win, struct window *top, struct region *region ) { struct window *parent, *ptr; int offset_x, offset_y; - struct window *top = get_top_clipping_window( win ); /* find the top most parent that doesn't clip either siblings or children */ for (parent = ptr = win; ptr != top; ptr = ptr->parent) @@ -1107,11 +1110,12 @@ static void set_window_pos( struct window *win, struct window *previous, const rectangle_t old_window_rect = win->window_rect; const rectangle_t old_visible_rect = win->visible_rect; const rectangle_t old_client_rect = win->client_rect; + struct window *top = get_top_clipping_window( win ); int visible = (win->style & WS_VISIBLE) || (swp_flags & SWP_SHOWWINDOW); if (win->parent && !is_visible( win->parent )) visible = 0; - if (visible && !(old_vis_rgn = get_visible_region( win, DCX_WINDOW ))) return; + if (visible && !(old_vis_rgn = get_visible_region( win, top, DCX_WINDOW ))) return; /* set the new window info before invalidating anything */ @@ -1130,7 +1134,7 @@ static void set_window_pos( struct window *win, struct window *previous, /* if the window is not visible, everything is easy */ if (!visible) return; - if (!(new_vis_rgn = get_visible_region( win, DCX_WINDOW ))) + if (!(new_vis_rgn = get_visible_region( win, top, DCX_WINDOW ))) { free_region( old_vis_rgn ); clear_error(); /* ignore error since the window info has been modified already */ @@ -1144,7 +1148,7 @@ static void set_window_pos( struct window *win, struct window *previous, 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, new_vis_rgn ); + expose_window( win, top, new_vis_rgn ); } free_region( old_vis_rgn ); @@ -1580,17 +1584,25 @@ DECL_HANDLER(get_windows_offset) DECL_HANDLER(get_visible_region) { struct region *region; - struct window *win = get_window( req->window ); + struct window *top, *win = get_window( req->window ); if (!win) return; - if ((region = get_visible_region( win, req->flags ))) + top = get_top_clipping_window( win ); + if ((region = get_visible_region( win, top, req->flags ))) { rectangle_t *data; map_win_region_to_screen( win, region ); data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size ); if (data) set_reply_data_ptr( data, reply->total_size ); } + reply->top_win = top->handle; + reply->top_org_x = top->visible_rect.left; + reply->top_org_y = top->visible_rect.top; + reply->win_org_x = (req->flags & DCX_WINDOW) ? win->window_rect.left : win->client_rect.left; + reply->win_org_y = (req->flags & DCX_WINDOW) ? win->window_rect.top : win->client_rect.top; + client_to_screen( top->parent, &reply->top_org_x, &reply->top_org_y ); + client_to_screen( win->parent, &reply->win_org_x, &reply->win_org_y ); }