Return the coordinates information needed to setup the DC parameters
authorAlexandre Julliard <julliard@winehq.org>
Thu, 31 Mar 2005 15:36:57 +0000 (15:36 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Thu, 31 Mar 2005 15:36:57 +0000 (15:36 +0000)
in the get_visible_region request instead of requiring the client to
compute it again.

dlls/x11drv/dce.c
include/wine/server_protocol.h
server/protocol.def
server/trace.c
server/window.c

index 72f8ca77b775ccef8f9c74dfee892a70e1f2401f..2de1578b1d5c2c759cedb0cb91bc4d8580ea16ef 100644 (file)
@@ -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;
index e5d80ad3219b1ad35ba9078af4ec14f93b48d514..5ad2dd6fb946dc4dbca29eeb41bc062be5f80468 100644 (file)
@@ -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 */
index d035abdf79de9378476dd08b65d496ae533e87f7..472433653a8a3b5b77dec621bc155e82f5231763 100644 (file)
@@ -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
 
 
index cda0973bae6fb20ef0bece052d7c6cbd3250ef01..e025f59fbd9c26d6faacfbb893c1625d599e3013 100644 (file)
@@ -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 );
index 26889faa9805806a663456a6a98e2e7b9e72b4bb..dacd1af676c81b6de66bc501c4760092ee849108 100644 (file)
@@ -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 );
 }