Commit e8d86b7c authored by Alexandre Julliard's avatar Alexandre Julliard

Moved visible region calculation to the server.

parent 00844ee0
......@@ -121,79 +121,46 @@ static int clip_children( HWND parent, HWND last, HRGN hrgn, int whole_window )
/***********************************************************************
* get_visible_region
*
* Compute the visible region of a window
* get_server_visible_region
*/
static HRGN get_visible_region( WND *win, HWND top, UINT flags, int mode )
static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags )
{
HRGN rgn;
RECT rect;
int xoffset, yoffset;
X11DRV_WND_DATA *data = win->pDriverData;
if (flags & DCX_WINDOW)
{
xoffset = win->rectWindow.left;
yoffset = win->rectWindow.top;
}
else
{
xoffset = win->rectClient.left;
yoffset = win->rectClient.top;
}
if (flags & DCX_PARENTCLIP)
GetClientRect( win->parent, &rect );
else if (flags & DCX_WINDOW)
rect = data->whole_rect;
else
rect = win->rectClient;
RGNDATA *data;
HRGN ret = 0;
size_t size = 256;
BOOL retry = FALSE;
/* vis region is relative to the start of the client/window area */
OffsetRect( &rect, -xoffset, -yoffset );
if (!(rgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom ))) return 0;
if ((flags & DCX_CLIPCHILDREN) && (mode != ClipByChildren))
{
/* we need to clip children by hand */
if (clip_children( win->hwndSelf, 0, rgn, (flags & DCX_WINDOW) ) == NULLREGION) return rgn;
}
if (top && top != win->hwndSelf) /* need to clip siblings of ancestors */
do
{
WND *parent, *ptr = WIN_FindWndPtr( win->hwndSelf );
HRGN tmp = 0;
OffsetRgn( rgn, xoffset, yoffset );
for (;;)
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) return 0;
SERVER_START_REQ( get_visible_region )
{
if (ptr->dwStyle & WS_CLIPSIBLINGS)
req->window = hwnd;
req->top_win = top;
req->flags = flags;
wine_server_set_reply( req, data->Buffer, size );
if (!wine_server_call_err( req ))
{
if (clip_children( ptr->parent, ptr->hwndSelf, rgn, FALSE ) == NULLREGION) break;
if (reply->total_size <= size)
{
size_t reply_size = wine_server_reply_size( reply );
data->rdh.dwSize = sizeof(data->rdh);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = reply_size / sizeof(RECT);
data->rdh.nRgnSize = reply_size;
ret = ExtCreateRegion( NULL, size, data );
}
else
{
size = reply->total_size;
retry = TRUE;
}
}
if (ptr->hwndSelf == top) break;
if (!(parent = WIN_FindWndPtr( ptr->parent ))) break;
WIN_ReleaseWndPtr( ptr );
ptr = parent;
/* clip to parent client area */
if (tmp) SetRectRgn( tmp, 0, 0, ptr->rectClient.right - ptr->rectClient.left,
ptr->rectClient.bottom - ptr->rectClient.top );
else tmp = CreateRectRgn( 0, 0, ptr->rectClient.right - ptr->rectClient.left,
ptr->rectClient.bottom - ptr->rectClient.top );
CombineRgn( rgn, rgn, tmp, RGN_AND );
OffsetRgn( rgn, ptr->rectClient.left, ptr->rectClient.top );
xoffset += ptr->rectClient.left;
yoffset += ptr->rectClient.top;
}
WIN_ReleaseWndPtr( ptr );
/* make it relative to the target window again */
OffsetRgn( rgn, -xoffset, -yoffset );
if (tmp) DeleteObject( tmp );
}
return rgn;
SERVER_END_REQ;
HeapFree( GetProcessHeap(), 0, data );
} while (retry);
return ret;
}
......@@ -426,52 +393,24 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
HWND top = 0;
X11DRV_WND_DATA *data = win->pDriverData;
struct x11drv_escape_set_drawable escape;
BOOL visible;
escape.mode = IncludeInferiors;
/* don't clip siblings if using parent clip region */
if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
/* find the top parent in the hierarchy that isn't clipping siblings */
visible = (win->dwStyle & WS_VISIBLE) != 0;
if (visible)
{
HWND *list = WIN_ListParents( hwnd );
if (list)
{
int i;
for (i = 0; list[i] != GetDesktopWindow(); i++)
{
LONG style = GetWindowLongW( list[i], GWL_STYLE );
if (!(style & WS_VISIBLE))
{
visible = FALSE;
top = 0;
break;
}
if (!(style & WS_CLIPSIBLINGS)) top = list[i];
}
HeapFree( GetProcessHeap(), 0, list );
}
if (!top && visible && !(flags & DCX_CLIPSIBLINGS)) top = hwnd;
}
if (top)
top = GetAncestor( hwnd, GA_ROOT );
if (top != hwnd)
{
HWND parent = GetAncestor( top, GA_PARENT );
escape.org.x = escape.org.y = 0;
if (flags & DCX_WINDOW)
{
escape.org.x = win->rectWindow.left - win->rectClient.left;
escape.org.y = win->rectWindow.top - win->rectClient.top;
}
MapWindowPoints( hwnd, parent, &escape.org, 1 );
MapWindowPoints( hwnd, top, &escape.org, 1 );
escape.drawable_org.x = escape.drawable_org.y = 0;
MapWindowPoints( parent, 0, &escape.drawable_org, 1 );
/* have to use the parent so that we include siblings */
if (parent) escape.drawable = X11DRV_get_client_window( parent );
else escape.drawable = root_window;
MapWindowPoints( top, 0, &escape.drawable_org, 1 );
escape.drawable = X11DRV_get_client_window( top );
}
else
{
......@@ -482,23 +421,22 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
escape.org.y = 0;
escape.drawable_org = escape.org;
}
else if (flags & DCX_WINDOW)
{
escape.drawable = data->whole_window;
escape.org.x = win->rectWindow.left - data->whole_rect.left;
escape.org.y = win->rectWindow.top - data->whole_rect.top;
escape.drawable_org.x = data->whole_rect.left - win->rectClient.left;
escape.drawable_org.y = data->whole_rect.top - win->rectClient.top;
}
else
{
escape.drawable = data->client_window;
escape.org.x = 0;
escape.org.y = 0;
escape.drawable_org = escape.org;
if (flags & DCX_CLIPCHILDREN) escape.mode = ClipByChildren; /* can use X11 clipping */
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 = win->rectWindow.left - data->whole_rect.left;
escape.org.y = win->rectWindow.top - data->whole_rect.top;
}
else
{
escape.org.x = win->rectClient.left - data->whole_rect.left;
escape.org.y = win->rectClient.top - data->whole_rect.top;
}
}
MapWindowPoints( hwnd, 0, &escape.drawable_org, 1 );
}
escape.code = X11DRV_SET_DRAWABLE;
......@@ -508,17 +446,10 @@ BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
SetHookFlags16( HDC_16(hdc), DCHF_VALIDATEVISRGN )) /* DC was dirty */
{
/* need to recompute the visible region */
HRGN visRgn;
HRGN visRgn = get_server_visible_region( hwnd, top, flags );
if (visible)
{
visRgn = get_visible_region( win, top, flags, escape.mode );
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
CombineRgn( visRgn, visRgn, hrgn,
(flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
}
else visRgn = CreateRectRgn( 0, 0, 0, 0 );
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
SelectVisRgn16( HDC_16(hdc), HRGN_16(visRgn) );
DeleteObject( visRgn );
......
......@@ -2614,6 +2614,22 @@ struct get_windows_offset_reply
struct get_visible_region_request
{
struct request_header __header;
user_handle_t window;
user_handle_t top_win;
unsigned int flags;
};
struct get_visible_region_reply
{
struct reply_header __header;
size_t total_size;
/* VARARG(region,rectangles); */
};
struct set_window_property_request
{
struct request_header __header;
......@@ -3189,6 +3205,7 @@ enum request
REQ_set_window_text,
REQ_inc_window_paint_count,
REQ_get_windows_offset,
REQ_get_visible_region,
REQ_set_window_property,
REQ_remove_window_property,
REQ_get_window_property,
......@@ -3369,6 +3386,7 @@ union generic_request
struct set_window_text_request set_window_text_request;
struct inc_window_paint_count_request inc_window_paint_count_request;
struct get_windows_offset_request get_windows_offset_request;
struct get_visible_region_request get_visible_region_request;
struct set_window_property_request set_window_property_request;
struct remove_window_property_request remove_window_property_request;
struct get_window_property_request get_window_property_request;
......@@ -3547,6 +3565,7 @@ union generic_reply
struct set_window_text_reply set_window_text_reply;
struct inc_window_paint_count_reply inc_window_paint_count_reply;
struct get_windows_offset_reply get_windows_offset_reply;
struct get_visible_region_reply get_visible_region_reply;
struct set_window_property_reply set_window_property_reply;
struct remove_window_property_reply remove_window_property_reply;
struct get_window_property_reply get_window_property_reply;
......@@ -3574,6 +3593,6 @@ union generic_reply
struct set_global_windows_reply set_global_windows_reply;
};
#define SERVER_PROTOCOL_VERSION 143
#define SERVER_PROTOCOL_VERSION 144
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -29,6 +29,7 @@ C_SRCS = \
process.c \
ptrace.c \
queue.c \
region.c \
registry.c \
request.c \
semaphore.c \
......
......@@ -1838,6 +1838,17 @@ enum message_type
@END
/* Get the visible region of a window */
@REQ(get_visible_region)
user_handle_t window; /* handle to the window */
user_handle_t top_win; /* top window to clip against */
unsigned int flags; /* DCX flags */
@REPLY
size_t total_size; /* total size of the resulting region */
VARARG(region,rectangles); /* list of rectangles for the region */
@END
/* Set a window property */
@REQ(set_window_property)
user_handle_t window; /* handle to the window */
......
This diff is collapsed. Click to expand it.
......@@ -251,6 +251,7 @@ DECL_HANDLER(get_window_text);
DECL_HANDLER(set_window_text);
DECL_HANDLER(inc_window_paint_count);
DECL_HANDLER(get_windows_offset);
DECL_HANDLER(get_visible_region);
DECL_HANDLER(set_window_property);
DECL_HANDLER(remove_window_property);
DECL_HANDLER(get_window_property);
......@@ -430,6 +431,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_set_window_text,
(req_handler)req_inc_window_paint_count,
(req_handler)req_get_windows_offset,
(req_handler)req_get_visible_region,
(req_handler)req_set_window_property,
(req_handler)req_remove_window_property,
(req_handler)req_get_window_property,
......
......@@ -375,6 +375,21 @@ static void dump_varargs_input_records( size_t size )
remove_data( size );
}
static void dump_varargs_rectangles( size_t size )
{
const rectangle_t *rect = cur_data;
size_t len = size / sizeof(*rect);
fputc( '{', stderr );
while (len > 0)
{
dump_rectangle( rect++ );
if (--len) fputc( ',', stderr );
}
fputc( '}', stderr );
remove_data( size );
}
static void dump_varargs_properties( size_t size )
{
const property_data_t *prop = cur_data;
......@@ -2161,6 +2176,20 @@ static void dump_get_windows_offset_reply( const struct get_windows_offset_reply
fprintf( stderr, " y=%d", req->y );
}
static void dump_get_visible_region_request( const struct get_visible_region_request *req )
{
fprintf( stderr, " window=%p,", req->window );
fprintf( stderr, " top_win=%p,", req->top_win );
fprintf( stderr, " flags=%08x", req->flags );
}
static void dump_get_visible_region_reply( const struct get_visible_region_reply *req )
{
fprintf( stderr, " total_size=%d,", req->total_size );
fprintf( stderr, " region=" );
dump_varargs_rectangles( cur_size );
}
static void dump_set_window_property_request( const struct set_window_property_request *req )
{
fprintf( stderr, " window=%p,", req->window );
......@@ -2630,6 +2659,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_window_text_request,
(dump_func)dump_inc_window_paint_count_request,
(dump_func)dump_get_windows_offset_request,
(dump_func)dump_get_visible_region_request,
(dump_func)dump_set_window_property_request,
(dump_func)dump_remove_window_property_request,
(dump_func)dump_get_window_property_request,
......@@ -2806,6 +2836,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0,
(dump_func)0,
(dump_func)dump_get_windows_offset_reply,
(dump_func)dump_get_visible_region_reply,
(dump_func)0,
(dump_func)dump_remove_window_property_reply,
(dump_func)dump_get_window_property_reply,
......@@ -2982,6 +3013,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"set_window_text",
"inc_window_paint_count",
"get_windows_offset",
"get_visible_region",
"set_window_property",
"remove_window_property",
"get_window_property",
......
......@@ -24,6 +24,7 @@
#include "wine/server_protocol.h"
struct thread;
struct region;
struct window;
struct msg_queue;
struct hook_table;
......@@ -64,6 +65,25 @@ extern int attach_thread_input( struct thread *thread_from, struct thread *threa
extern void post_message( user_handle_t win, unsigned int message,
unsigned int wparam, unsigned int lparam );
/* region functions */
extern struct region *create_region( const rectangle_t *rects, unsigned int nb_rects );
extern void free_region( struct region *region );
extern void set_region_rect( struct region *region, const rectangle_t *rect );
extern rectangle_t *get_region_data( const struct region *region, size_t *total_size );
extern rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size );
extern int is_region_empty( const struct region *region );
extern void get_region_extents( const struct region *region, rectangle_t *rect );
extern void offset_region( struct region *region, int x, int y );
extern struct region *copy_region( struct region *dst, const struct region *src );
extern struct region *intersect_region( struct region *dst, const struct region *src1,
const struct region *src2 );
extern struct region *subtract_region( struct region *dst, const struct region *src1,
const struct region *src2 );
extern struct region *union_region( struct region *dst, const struct region *src1,
const struct region *src2 );
static inline struct region *create_empty_region(void) { return create_region( NULL, 0 ); }
/* window functions */
extern void destroy_thread_windows( struct thread *thread );
......
......@@ -463,6 +463,114 @@ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *threa
}
/* clip all children of a given window out of the visible region */
static struct region *clip_children( struct window *parent, struct window *last,
struct region *region, int offset_x, int offset_y )
{
struct window *ptr;
struct region *tmp = create_empty_region();
if (!tmp) return NULL;
for (ptr = parent->first_child; ptr && ptr != last; ptr = ptr->next)
{
if (!(ptr->style & WS_VISIBLE)) continue;
if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
set_region_rect( tmp, &ptr->window_rect );
offset_region( tmp, offset_x, offset_y );
if (!(region = subtract_region( region, region, tmp ))) break;
if (is_region_empty( region )) break;
}
free_region( tmp );
return region;
}
/* compute the visible region of a window */
static struct region *get_visible_region( struct window *win, struct window *top,
unsigned int flags )
{
struct region *tmp, *region;
struct window *ptr;
rectangle_t rect;
int offset_x, offset_y;
if (!(region = create_empty_region())) return NULL;
/* first check if all ancestors are visible */
for (ptr = win; ptr != top_window; ptr = ptr->parent)
if (!(ptr->style & WS_VISIBLE)) return region; /* empty region */
/* retrieve window rectangle in parent coordinates */
if ((flags & DCX_PARENTCLIP) && win->parent)
{
rect.left = rect.top = 0;
rect.right = win->parent->client_rect.right - win->parent->client_rect.left;
rect.bottom = win->parent->client_rect.bottom - win->parent->client_rect.top;
offset_x = win->client_rect.left;
offset_y = win->client_rect.top;
}
else if (flags & DCX_WINDOW)
{
rect = win->window_rect;
offset_x = win->window_rect.left;
offset_y = win->window_rect.top;
}
else
{
rect = win->client_rect;
offset_x = win->client_rect.left;
offset_y = win->client_rect.top;
}
/* create a region relative to the window itself */
set_region_rect( region, &rect );
offset_region( region, -offset_x, -offset_y );
/* clip children */
if (flags & DCX_CLIPCHILDREN)
{
if (!clip_children( win, NULL, region,
offset_x - win->client_rect.left,
offset_y - win->client_rect.top )) goto error;
}
/* clip siblings of ancestors */
if (top && top != win && (tmp = create_empty_region()) != NULL)
{
offset_region( region, offset_x, offset_y ); /* make it relative to parent */
while (win->parent)
{
if (win->style & WS_CLIPSIBLINGS)
{
if (!clip_children( win->parent, win, region, 0, 0 )) goto error;
if (is_region_empty( region )) break;
}
if (win == top) break;
/* clip to parent client area */
win = win->parent;
offset_x += win->client_rect.left;
offset_y += win->client_rect.top;
offset_region( region, win->client_rect.left, win->client_rect.top );
set_region_rect( tmp, &win->client_rect );
if (!intersect_region( region, region, tmp )) goto error;
if (is_region_empty( region )) break;
}
offset_region( region, -offset_x, -offset_y ); /* make it relative to target window again */
free_region( tmp );
}
return region;
error:
free_region( region );
return NULL;
}
/* get the window class of a window */
struct window_class* get_window_class( user_handle_t window )
{
......@@ -825,6 +933,24 @@ DECL_HANDLER(get_windows_offset)
}
/* get the visible region of a window */
DECL_HANDLER(get_visible_region)
{
struct region *region;
struct window *win = get_window( req->window );
struct window *top = NULL;
if (!win) return;
if (req->top_win && !(top = get_window( req->top_win ))) return;
if ((region = get_visible_region( win, top, req->flags )))
{
rectangle_t *data = get_region_data_and_free( region, &reply->total_size );
set_reply_data_ptr( data, min(reply->total_size,get_reply_max_size()) );
}
}
/* set a window property */
DECL_HANDLER(set_window_property)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment