Added support for window regions in the server.
diff --git a/server/protocol.def b/server/protocol.def
index 08eb476..041dc6d 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1849,6 +1849,22 @@
@END
+/* Get the window region */
+@REQ(get_window_region)
+ user_handle_t window; /* handle to the window */
+@REPLY
+ size_t total_size; /* total size of the resulting region */
+ VARARG(region,rectangles); /* list of rectangles for the region */
+@END
+
+
+/* Set the window region */
+@REQ(set_window_region)
+ user_handle_t window; /* handle to the window */
+ 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 */
diff --git a/server/region.c b/server/region.c
index 7ecefe9..ab6645c 100644
--- a/server/region.c
+++ b/server/region.c
@@ -99,6 +99,8 @@
typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r,
const rectangle_t *rEnd, int top, int bottom );
+static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */
+
/* add a rectangle to a region */
static inline rectangle_t *add_rect( struct region *reg )
{
@@ -578,6 +580,16 @@
return region;
}
+/* create a region from request data */
+struct region *create_region_from_req_data( const void *data, size_t size )
+{
+ const rectangle_t *rects = data;
+ int nb_rects = size / sizeof(rectangle_t);
+
+ /* special case: empty region can be specified by a single all-zero rectangle */
+ if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) nb_rects = 0;
+ return create_region( rects, nb_rects );
+}
/* free a region */
void free_region( struct region *region )
@@ -607,7 +619,12 @@
/* retrieve the region data for sending to the client */
rectangle_t *get_region_data( const struct region *region, size_t *total_size )
{
- *total_size = region->num_rects * sizeof(rectangle_t);
+ if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
+ {
+ /* return a single empty rect for empty regions */
+ *total_size = sizeof(empty_rect);
+ return memdup( &empty_rect, sizeof(empty_rect) );
+ }
return memdup( region->rects, *total_size );
}
@@ -615,7 +632,13 @@
rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size )
{
rectangle_t *ret = region->rects;
- *total_size = region->num_rects * sizeof(rectangle_t);
+
+ if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
+ {
+ /* return a single empty rect for empty regions */
+ *total_size = sizeof(empty_rect);
+ ret = memdup( &empty_rect, sizeof(empty_rect) );
+ }
free( region );
return ret;
}
diff --git a/server/request.h b/server/request.h
index 43dc9a9..86c7419 100644
--- a/server/request.h
+++ b/server/request.h
@@ -252,6 +252,8 @@
DECL_HANDLER(inc_window_paint_count);
DECL_HANDLER(get_windows_offset);
DECL_HANDLER(get_visible_region);
+DECL_HANDLER(get_window_region);
+DECL_HANDLER(set_window_region);
DECL_HANDLER(set_window_property);
DECL_HANDLER(remove_window_property);
DECL_HANDLER(get_window_property);
@@ -432,6 +434,8 @@
(req_handler)req_inc_window_paint_count,
(req_handler)req_get_windows_offset,
(req_handler)req_get_visible_region,
+ (req_handler)req_get_window_region,
+ (req_handler)req_set_window_region,
(req_handler)req_set_window_property,
(req_handler)req_remove_window_property,
(req_handler)req_get_window_property,
diff --git a/server/trace.c b/server/trace.c
index 8a85720..0f293e4 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2190,6 +2190,25 @@
dump_varargs_rectangles( cur_size );
}
+static void dump_get_window_region_request( const struct get_window_region_request *req )
+{
+ fprintf( stderr, " window=%p", req->window );
+}
+
+static void dump_get_window_region_reply( const struct get_window_region_reply *req )
+{
+ fprintf( stderr, " total_size=%d,", req->total_size );
+ fprintf( stderr, " region=" );
+ dump_varargs_rectangles( cur_size );
+}
+
+static void dump_set_window_region_request( const struct set_window_region_request *req )
+{
+ fprintf( stderr, " window=%p,", req->window );
+ 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 );
@@ -2660,6 +2679,8 @@
(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_get_window_region_request,
+ (dump_func)dump_set_window_region_request,
(dump_func)dump_set_window_property_request,
(dump_func)dump_remove_window_property_request,
(dump_func)dump_get_window_property_request,
@@ -2837,6 +2858,8 @@
(dump_func)0,
(dump_func)dump_get_windows_offset_reply,
(dump_func)dump_get_visible_region_reply,
+ (dump_func)dump_get_window_region_reply,
+ (dump_func)0,
(dump_func)0,
(dump_func)dump_remove_window_property_reply,
(dump_func)dump_get_window_property_reply,
@@ -3014,6 +3037,8 @@
"inc_window_paint_count",
"get_windows_offset",
"get_visible_region",
+ "get_window_region",
+ "set_window_region",
"set_window_property",
"remove_window_property",
"get_window_property",
diff --git a/server/user.h b/server/user.h
index f6b960d..80ccddf 100644
--- a/server/user.h
+++ b/server/user.h
@@ -68,6 +68,7 @@
/* region functions */
extern struct region *create_region( const rectangle_t *rects, unsigned int nb_rects );
+extern struct region *create_region_from_req_data( const void *data, size_t size );
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 );
diff --git a/server/window.c b/server/window.c
index dbfde58..f93106e 100644
--- a/server/window.c
+++ b/server/window.c
@@ -68,6 +68,7 @@
user_handle_t last_active; /* last active popup */
rectangle_t window_rect; /* window rectangle */
rectangle_t client_rect; /* client rectangle */
+ struct region *win_region; /* window region (for shaped windows) */
unsigned int style; /* window style */
unsigned int ex_style; /* window extended style */
unsigned int id; /* window id */
@@ -261,6 +262,7 @@
free_user_handle( win->handle );
destroy_properties( win );
unlink_window( win );
+ if (win->win_region) free_region( win->win_region );
release_class( win->class );
if (win->text) free( win->text );
memset( win, 0x55, sizeof(*win) );
@@ -299,6 +301,7 @@
win->class = class;
win->atom = atom;
win->last_active = win->handle;
+ win->win_region = NULL;
win->style = 0;
win->ex_style = 0;
win->id = 0;
@@ -463,6 +466,18 @@
}
+/* intersect the window region with the specified region, relative to the window parent */
+static struct region *intersect_window_region( struct region *region, struct window *win )
+{
+ /* make region relative to window rect */
+ offset_region( region, -win->window_rect.left, -win->window_rect.top );
+ if (!intersect_region( region, region, win->win_region )) return NULL;
+ /* make region relative to parent again */
+ offset_region( region, win->window_rect.left, win->window_rect.top );
+ return region;
+}
+
+
/* 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 )
@@ -476,6 +491,11 @@
if (!(ptr->style & WS_VISIBLE)) continue;
if (ptr->ex_style & WS_EX_TRANSPARENT) continue;
set_region_rect( tmp, &ptr->window_rect );
+ if (ptr->win_region && !intersect_window_region( tmp, ptr ))
+ {
+ free_region( tmp );
+ return NULL;
+ }
offset_region( tmp, offset_x, offset_y );
if (!(region = subtract_region( region, region, tmp ))) break;
if (is_region_empty( region )) break;
@@ -491,7 +511,6 @@
{
struct region *tmp, *region;
struct window *ptr;
- rectangle_t rect;
int offset_x, offset_y;
if (!(region = create_empty_region())) return NULL;
@@ -501,32 +520,32 @@
for (ptr = win; ptr != top_window; ptr = ptr->parent)
if (!(ptr->style & WS_VISIBLE)) return region; /* empty region */
- /* retrieve window rectangle in parent coordinates */
+ /* create a region relative to the window itself */
if ((flags & DCX_PARENTCLIP) && win->parent)
{
+ rectangle_t rect;
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;
+ set_region_rect( region, &rect );
offset_x = win->client_rect.left;
offset_y = win->client_rect.top;
}
else if (flags & DCX_WINDOW)
{
- rect = win->window_rect;
+ set_region_rect( region, &win->window_rect );
+ if (win->win_region && !intersect_window_region( region, win )) goto error;
offset_x = win->window_rect.left;
offset_y = win->window_rect.top;
}
else
{
- rect = win->client_rect;
+ set_region_rect( region, &win->client_rect );
+ if (win->win_region && !intersect_window_region( region, win )) goto error;
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 */
@@ -557,7 +576,16 @@
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 (win->win_region && !intersect_window_region( tmp, win ))
+ {
+ free_region( tmp );
+ goto error;
+ }
+ if (!intersect_region( region, region, tmp ))
+ {
+ free_region( tmp );
+ goto error;
+ }
if (is_region_empty( region )) break;
}
offset_region( region, -offset_x, -offset_y ); /* make it relative to target window again */
@@ -951,6 +979,40 @@
}
+/* get the window region */
+DECL_HANDLER(get_window_region)
+{
+ struct window *win = get_window( req->window );
+
+ if (!win) return;
+
+ reply->total_size = 0;
+ if (win->win_region)
+ {
+ rectangle_t *data = get_region_data( win->win_region, &reply->total_size );
+ set_reply_data_ptr( data, min( reply->total_size, get_reply_max_size() ) );
+ }
+}
+
+
+/* set the window region */
+DECL_HANDLER(set_window_region)
+{
+ struct region *region = NULL;
+ struct window *win = get_window( req->window );
+
+ if (!win) return;
+
+ if (get_req_data_size()) /* no data means remove the region completely */
+ {
+ if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() )))
+ return;
+ }
+ if (win->win_region) free_region( win->win_region );
+ win->win_region = region;
+}
+
+
/* set a window property */
DECL_HANDLER(set_window_property)
{