/***********************************************************************
- * 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 )))
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;
}
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 );
}
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))
{
* 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;
}
+/* 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 );
}
/* 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;
/* 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)
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 */
/* 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 */
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 );
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 );
}