Added support for window regions in the server.
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)
{