From 2d35e07faea2ab49d06598cc2c802fc49bdce3bd Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Fri, 23 Aug 2013 22:20:49 -0400 Subject: [PATCH] wayland: Add support for set_opaque_region / set_input_region https://bugzilla.gnome.org/show_bug.cgi?id=707019 --- src/compositor/compositor.c | 4 +- src/compositor/meta-window-actor.c | 258 +++++++++------------------- src/compositor/meta-window-group.c | 10 +- src/core/display.c | 54 +----- src/core/window-private.h | 24 ++- src/core/window-props.c | 2 +- src/core/window.c | 261 ++++++++++++++++++++++------- src/meta/compositor.h | 4 +- src/wayland/meta-wayland.c | 28 +++- 9 files changed, 326 insertions(+), 319 deletions(-) diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index 5565dd0df..215645265 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -930,8 +930,8 @@ is_grabbed_event (MetaDisplay *display, } void -meta_compositor_window_x11_shape_changed (MetaCompositor *compositor, - MetaWindow *window) +meta_compositor_window_shape_changed (MetaCompositor *compositor, + MetaWindow *window) { MetaWindowActor *window_actor; window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index c599ac506..e7ca3f61e 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -71,7 +70,7 @@ struct _MetaWindowActorPrivate /* A region that matches the shape of the window, including frame bounds */ cairo_region_t *shape_region; /* If the window has an input shape, a region that matches the shape */ - cairo_region_t *input_shape_region; + cairo_region_t *input_region; /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with * the shape region. */ cairo_region_t *opaque_region; @@ -416,8 +415,8 @@ meta_window_actor_constructed (GObject *object) /* Start off with empty regions to maintain the invariant that these regions are always set */ - priv->shape_region = cairo_region_create(); - priv->input_shape_region = cairo_region_create(); + priv->shape_region = cairo_region_create (); + priv->input_region = cairo_region_create (); } static void @@ -447,7 +446,7 @@ meta_window_actor_dispose (GObject *object) } g_clear_pointer (&priv->shape_region, cairo_region_destroy); - g_clear_pointer (&priv->input_shape_region, cairo_region_destroy); + g_clear_pointer (&priv->input_region, cairo_region_destroy); g_clear_pointer (&priv->opaque_region, cairo_region_destroy); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); @@ -1269,7 +1268,7 @@ meta_window_actor_should_unredirect (MetaWindowActor *self) if (priv->opacity != 0xff) return FALSE; - if (metaWindow->has_shape) + if (metaWindow->shape_region != NULL) return FALSE; if (priv->argb32 && !meta_window_requested_bypass_compositor (metaWindow)) @@ -2180,85 +2179,21 @@ build_and_scan_frame_mask (MetaWindowActor *self, g_free (mask_data); } -static cairo_region_t * -region_create_from_x_rectangles (const XRectangle *rects, - int n_rects, - int dx, - int dy) -{ - int i; - cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects); - - for (i = 0; i < n_rects; i ++) - { - cairo_rects[i].x = rects[i].x + dx; - cairo_rects[i].y = rects[i].y + dy; - cairo_rects[i].width = rects[i].width; - cairo_rects[i].height = rects[i].height; - } - - return cairo_region_create_rectangles (cairo_rects, n_rects); -} - static void -meta_window_actor_update_x11_shape_region (MetaWindowActor *self, - cairo_rectangle_int_t *client_area) +meta_window_actor_update_shape_region (MetaWindowActor *self, + cairo_rectangle_int_t *client_area) { MetaWindowActorPrivate *priv = self->priv; cairo_region_t *region = NULL; - gboolean needs_mask; - if (priv->shadow_shape != NULL) + if (priv->window->frame != NULL && priv->window->shape_region != NULL) { - meta_window_shape_unref (priv->shadow_shape); - priv->shadow_shape = NULL; + region = cairo_region_copy (priv->window->shape_region); + cairo_region_translate (region, client_area->x, client_area->y); } - - meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL); - g_clear_pointer (&priv->shape_region, cairo_region_destroy); - g_clear_pointer (&priv->opaque_region, cairo_region_destroy); - -#ifdef HAVE_SHAPE - if (priv->window->has_shape) + else if (priv->window->shape_region != NULL) { - /* Translate the set of XShape rectangles that we - * get from the X server to a cairo_region. */ - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - XRectangle *rects; - int n_rects, ordering; - - meta_error_trap_push (display); - rects = XShapeGetRectangles (xdisplay, - priv->window->xwindow, - ShapeBounding, - &n_rects, - &ordering); - meta_error_trap_pop (display); - - if (rects) - { - region = region_create_from_x_rectangles (rects, n_rects, - client_area->x, - client_area->y); - XFree (rects); - } - } -#endif - - needs_mask = (region != NULL) || (priv->window->frame != NULL); - - if (region != NULL) - { - /* The shape we get back from the client may have coordinates - * outside of the frame. The X SHAPE Extension requires that - * the overall shape the client provides never exceeds the - * "bounding rectangle" of the window -- the shape that the - * window would have gotten if it was unshaped. In our case, - * this is simply the client area. - */ - cairo_region_intersect_rectangle (region, client_area); + region = cairo_region_reference (priv->window->shape_region); } else { @@ -2268,11 +2203,71 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self, region = cairo_region_create_rectangle (client_area); } - /* The region at this point should be constrained to the - * bounds of the client rectangle. */ + meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), NULL); + if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL)) + build_and_scan_frame_mask (self, client_area, region); + + g_clear_pointer (&priv->shape_region, cairo_region_destroy); + priv->shape_region = region; + + if (priv->shadow_shape != NULL) + { + meta_window_shape_unref (priv->shadow_shape); + priv->shadow_shape = NULL; + } + + meta_window_actor_invalidate_shadow (self); +} + +static void +meta_window_actor_update_input_region (MetaWindowActor *self, + cairo_rectangle_int_t *client_area) +{ + MetaWindowActorPrivate *priv = self->priv; + MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor); + cairo_region_t *region = NULL; + + if (priv->window->frame != NULL && priv->window->input_region != NULL) + { + region = meta_frame_get_frame_bounds (priv->window->frame); + + cairo_region_subtract_rectangle (region, client_area); + + /* input_region is in client window coordinates, so translate the + * input region into that coordinate system and back */ + cairo_region_translate (region, -client_area->x, -client_area->y); + cairo_region_union (region, priv->window->input_region); + cairo_region_translate (region, client_area->x, client_area->y); + } + else if (priv->window->shape_region != NULL) + { + region = cairo_region_reference (priv->window->input_region); + } + else + { + /* If we don't have a shape on the server, that means that + * we have an implicit shape of one rectangle covering the + * entire window. */ + region = cairo_region_create_rectangle (client_area); + } + + meta_shaped_texture_set_input_shape_region (stex, region); + cairo_region_destroy (region); +} + +static void +meta_window_actor_update_opaque_region (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + + g_clear_pointer (&priv->opaque_region, cairo_region_destroy); if (priv->argb32 && priv->window->opaque_region != NULL) { + MetaFrameBorders borders; + + meta_frame_calc_borders (priv->window->frame, &borders); + /* The opaque region is defined to be a part of the * window which ARGB32 will always paint with opaque * pixels. For these regions, we want to avoid painting @@ -2284,91 +2279,13 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self, * case, graphical glitches will occur. */ priv->opaque_region = cairo_region_copy (priv->window->opaque_region); - cairo_region_translate (priv->opaque_region, client_area->x, client_area->y); - cairo_region_intersect (priv->opaque_region, region); + cairo_region_translate (priv->opaque_region, borders.total.left, borders.total.top); + cairo_region_intersect (priv->opaque_region, priv->shape_region); } else if (priv->argb32) priv->opaque_region = NULL; else - priv->opaque_region = cairo_region_reference (region); - - if (needs_mask) - { - /* This takes the region, generates a mask using GTK+ - * and scans the mask looking for all opaque pixels, - * adding it to region. - */ - build_and_scan_frame_mask (self, client_area, region); - } - - priv->shape_region = region; - - meta_window_actor_invalidate_shadow (self); -} - -static void -meta_window_actor_update_x11_input_shape_region (MetaWindowActor *self, - cairo_rectangle_int_t *client_area) -{ - MetaWindowActorPrivate *priv = self->priv; - cairo_region_t *region = NULL; - - g_clear_pointer (&priv->input_shape_region, cairo_region_destroy); - -#ifdef HAVE_SHAPE - /* Note: we currently assume that mutter never sets an input region - * when there is a frame. */ - if (priv->window->frame == NULL && priv->window->has_input_shape) - { - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - Display *xdisplay = meta_display_get_xdisplay (display); - XRectangle *rects; - int n_rects, ordering; - - /* Note we only actually query the ShapeInput shape of a window - * when we don't have a frame because we assume currently that - * mutter never sets an ShapeInput shape on a frame. */ - meta_error_trap_push (display); - rects = XShapeGetRectangles (xdisplay, - priv->window->xwindow, - ShapeInput, - &n_rects, - &ordering); - meta_error_trap_pop (display); - if (rects) - { - region = region_create_from_x_rectangles (rects, n_rects, - client_area->x, - client_area->y); - XFree (rects); - } - } -#endif /* HAVE_SHAPE */ - - if (region != NULL) - { - /* The X shape extension requires us to intersect the input - * region with the effective bounding shape to determine the - * effective input region. - */ - if (priv->shape_region) - cairo_region_intersect (region, priv->shape_region); - else - cairo_region_intersect_rectangle (region, client_area); - } - else - { - /* If we don't have a shape on the server, that means that we - * have an implicit shape of one rectangle covering the entire - * window. */ - region = cairo_region_create_rectangle (client_area); - } - - priv->input_shape_region = region; - - meta_shaped_texture_set_input_shape_region (META_SHAPED_TEXTURE (priv->actor), - priv->input_shape_region); + priv->opaque_region = cairo_region_reference (priv->shape_region); } static void @@ -2394,24 +2311,9 @@ check_needs_reshape (MetaWindowActor *self) else client_area.height = priv->window->rect.height; - if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11) - { - meta_window_actor_update_x11_shape_region (self, &client_area); - meta_window_actor_update_x11_input_shape_region (self, &client_area); - } - else - { - /* TODO: properly support setting an input region as specified - * via the wayland protocol */ - - g_clear_pointer (&priv->shape_region, cairo_region_destroy); - g_clear_pointer (&priv->opaque_region, cairo_region_destroy); - g_clear_pointer (&priv->input_shape_region, cairo_region_destroy); - - priv->shape_region = cairo_region_create_rectangle (&client_area); - priv->opaque_region = cairo_region_reference (priv->shape_region); - priv->input_shape_region = cairo_region_reference (priv->shape_region); - } + meta_window_actor_update_shape_region (self, &client_area); + meta_window_actor_update_input_region (self, &client_area); + meta_window_actor_update_opaque_region (self); priv->needs_reshape = FALSE; } diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index fe65f3950..65771f73a 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -186,7 +186,6 @@ meta_window_group_paint (ClutterActor *actor) if (META_IS_WINDOW_ACTOR (child)) { - MetaWindow *meta_window; MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); int x, y; @@ -201,14 +200,7 @@ meta_window_group_paint (ClutterActor *actor) meta_window_actor_set_visible_region (window_actor, visible_region); - /* TODO: Track the opaque regions of wayland clients. - * Although wayland clients can report opaque window - * regions, for now we assume that all wayland clients are - * transparent... */ - meta_window = meta_window_actor_get_meta_window (window_actor); - - if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND && - clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff) + if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff) { cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor); if (obscured_region) diff --git a/src/core/display.c b/src/core/display.c index d62e42976..7d67c2e9a 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -2336,59 +2336,9 @@ meta_display_handle_event (MetaDisplay *display, XShapeEvent *sev = (XShapeEvent*) event; if (sev->kind == ShapeBounding) - { - if (sev->shaped && !window->has_shape) - { - window->has_shape = TRUE; - meta_topic (META_DEBUG_SHAPES, - "Window %s now has a shape\n", - window->desc); - } - else if (!sev->shaped && window->has_shape) - { - window->has_shape = FALSE; - meta_topic (META_DEBUG_SHAPES, - "Window %s no longer has a shape\n", - window->desc); - } - else - { - meta_topic (META_DEBUG_SHAPES, - "Window %s shape changed\n", - window->desc); - } - - if (display->compositor) - meta_compositor_window_x11_shape_changed (display->compositor, - window); - } + meta_window_update_shape_region_x11 (window); else if (sev->kind == ShapeInput) - { - if (sev->shaped && !window->has_input_shape) - { - window->has_input_shape = TRUE; - meta_topic (META_DEBUG_SHAPES, - "Window %s now has an input shape\n", - window->desc); - } - else if (!sev->shaped && window->has_input_shape) - { - window->has_input_shape = FALSE; - meta_topic (META_DEBUG_SHAPES, - "Window %s no longer has an input shape\n", - window->desc); - } - else - { - meta_topic (META_DEBUG_SHAPES, - "Window %s input shape changed\n", - window->desc); - } - - if (display->compositor) - meta_compositor_window_x11_shape_changed (display->compositor, - window); - } + meta_window_update_input_region_x11 (window); } else { diff --git a/src/core/window-private.h b/src/core/window-private.h index c068c35af..c54036bed 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -339,11 +339,6 @@ struct _MetaWindow guint using_net_wm_icon_name : 1; /* vs. plain wm_icon_name */ guint using_net_wm_visible_icon_name : 1; /* tracked so we can clear it */ - /* has a bounding shape mask */ - guint has_shape : 1; - /* has an input shape mask */ - guint has_input_shape : 1; - /* icon props have changed */ guint need_reread_icon : 1; @@ -365,9 +360,15 @@ struct _MetaWindow /* if non-NULL, the bounds of the window frame */ cairo_region_t *frame_bounds; + /* if non-NULL, the bounding shape region of the window */ + cairo_region_t *shape_region; + /* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */ cairo_region_t *opaque_region; + /* the input shape region for picking */ + cairo_region_t *input_region; + /* if TRUE, the we have the new form of sync request counter which * also handles application frames */ guint extended_sync_request_counter : 1; @@ -685,7 +686,6 @@ void meta_window_update_icon_now (MetaWindow *window); void meta_window_update_role (MetaWindow *window); void meta_window_update_net_wm_type (MetaWindow *window); -void meta_window_update_opaque_region (MetaWindow *window); void meta_window_update_for_monitors_changed (MetaWindow *window); void meta_window_update_on_all_workspaces (MetaWindow *window); @@ -699,4 +699,16 @@ void meta_window_compute_tile_match (MetaWindow *window); gboolean meta_window_updates_are_frozen (MetaWindow *window); +void meta_window_set_opaque_region (MetaWindow *window, + cairo_region_t *region); +void meta_window_update_opaque_region_x11 (MetaWindow *window); + +void meta_window_set_input_region (MetaWindow *window, + cairo_region_t *region); +void meta_window_update_input_region_x11 (MetaWindow *window); + +void meta_window_set_shape_region (MetaWindow *window, + cairo_region_t *region); +void meta_window_update_shape_region_x11 (MetaWindow *window); + #endif diff --git a/src/core/window-props.c b/src/core/window-props.c index adbfe59dd..13ee3bbdb 100644 --- a/src/core/window-props.c +++ b/src/core/window-props.c @@ -565,7 +565,7 @@ reload_opaque_region (MetaWindow *window, MetaPropValue *value, gboolean initial) { - meta_window_update_opaque_region (window); + meta_window_update_opaque_region_x11 (window); } static void diff --git a/src/core/window.c b/src/core/window.c index faf4bb2d7..5e87e5881 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -822,8 +822,6 @@ meta_window_new_shared (MetaDisplay *display, Window xwindow, gboolean must_be_viewable, gulong existing_wm_state, - gboolean has_shape, - gboolean has_input_shape, MetaCompEffect effect, XWindowAttributes *attrs) { @@ -876,9 +874,6 @@ meta_window_new_shared (MetaDisplay *display, /* avoid tons of stack updates */ meta_stack_freeze (window->screen->stack); - window->has_shape = has_shape; - window->has_input_shape = has_input_shape; - window->rect.x = attrs->x; window->rect.y = attrs->y; window->rect.width = attrs->width; @@ -1059,6 +1054,8 @@ meta_window_new_shared (MetaDisplay *display, } meta_display_register_x_window (display, &window->xwindow, window); + meta_window_update_shape_region_x11 (window); + meta_window_update_input_region_x11 (window); } /* assign the window to its group, or create a new group if needed @@ -1425,8 +1422,6 @@ meta_window_new_for_wayland (MetaDisplay *display, None, TRUE, WithdrawnState, - FALSE, /* has shape */ - FALSE, /* has input shape */ META_COMP_EFFECT_NONE, &attrs); @@ -1455,8 +1450,6 @@ meta_window_new_with_attrs (MetaDisplay *display, gulong existing_wm_state; MetaWindow *window; gulong event_mask; - gboolean has_shape = FALSE; - gboolean has_input_shape = FALSE; meta_verbose ("Attempting to manage 0x%lx\n", xwindow); @@ -1576,53 +1569,6 @@ meta_window_new_with_attrs (MetaDisplay *display, XISelectEvents (display->xdisplay, xwindow, &mask, 1); } -#ifdef HAVE_SHAPE - if (META_DISPLAY_HAS_SHAPE (display)) - { - int x_bounding, y_bounding, x_clip, y_clip; - unsigned w_bounding, h_bounding, w_clip, h_clip; - int bounding_shaped, clip_shaped; - XRectangle *input_rectangles; - int n_rects, ordering; - - XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); - - XShapeQueryExtents (display->xdisplay, xwindow, - &bounding_shaped, &x_bounding, &y_bounding, - &w_bounding, &h_bounding, - &clip_shaped, &x_clip, &y_clip, - &w_clip, &h_clip); - - has_shape = bounding_shaped != FALSE; - - /* XXX: The x shape extension doesn't provide a way to only test if an - * input shape has been specified, so we have to query and throw away the - * rectangles. */ - meta_error_trap_push (display); - input_rectangles = XShapeGetRectangles (display->xdisplay, xwindow, - ShapeInput, &n_rects, &ordering); - meta_error_trap_pop (display); - if (input_rectangles) - { - if (n_rects > 1 || - (n_rects == 1 && - (input_rectangles[0].x != x_bounding || - input_rectangles[1].y != y_bounding || - input_rectangles[2].width != w_bounding || - input_rectangles[3].height != h_bounding))) - { - has_input_shape = TRUE; - } - XFree (input_rectangles); - } - - meta_topic (META_DEBUG_SHAPES, - "Window has_shape = %d extents %d,%d %u x %u\n", - has_shape, x_bounding, y_bounding, - w_bounding, h_bounding); - } -#endif - /* Get rid of any borders */ if (attrs->border_width != 0) XSetWindowBorderWidth (display->xdisplay, xwindow, 0); @@ -1656,8 +1602,6 @@ meta_window_new_with_attrs (MetaDisplay *display, xwindow, must_be_viewable, existing_wm_state, - has_shape, - has_input_shape, effect, attrs); @@ -7810,14 +7754,25 @@ meta_window_update_net_wm_type (MetaWindow *window) } void -meta_window_update_opaque_region (MetaWindow *window) +meta_window_set_opaque_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->opaque_region, cairo_region_destroy); + + if (region != NULL) + window->opaque_region = cairo_region_reference (region); + + if (window->display->compositor) + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_update_opaque_region_x11 (MetaWindow *window) { cairo_region_t *opaque_region = NULL; gulong *region = NULL; int nitems; - g_clear_pointer (&window->opaque_region, cairo_region_destroy); - if (meta_prop_get_cardinal_list (window->display, window->xwindow, window->display->atom__NET_WM_OPAQUE_REGION, @@ -7860,11 +7815,191 @@ meta_window_update_opaque_region (MetaWindow *window) } out: - window->opaque_region = opaque_region; meta_XFree (region); + meta_window_set_opaque_region (window, opaque_region); + cairo_region_destroy (opaque_region); +} + +static cairo_region_t * +region_create_from_x_rectangles (const XRectangle *rects, + int n_rects) +{ + int i; + cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects); + + for (i = 0; i < n_rects; i ++) + { + cairo_rects[i].x = rects[i].x; + cairo_rects[i].y = rects[i].y; + cairo_rects[i].width = rects[i].width; + cairo_rects[i].height = rects[i].height; + } + + return cairo_region_create_rectangles (cairo_rects, n_rects); +} + +void +meta_window_set_input_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->input_region, cairo_region_destroy); + + if (region != NULL) + window->input_region = cairo_region_reference (region); + if (window->display->compositor) - meta_compositor_window_x11_shape_changed (window->display->compositor, window); + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_update_input_region_x11 (MetaWindow *window) +{ + cairo_region_t *region = NULL; + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + { + /* Translate the set of XShape rectangles that we + * get from the X server to a cairo_region. */ + XRectangle *rects = NULL; + int n_rects, ordering; + + int x_bounding, y_bounding, x_clip, y_clip; + unsigned w_bounding, h_bounding, w_clip, h_clip; + int bounding_shaped, clip_shaped; + + meta_error_trap_push (window->display); + XShapeQueryExtents (window->display->xdisplay, window->xwindow, + &bounding_shaped, &x_bounding, &y_bounding, + &w_bounding, &h_bounding, + &clip_shaped, &x_clip, &y_clip, + &w_clip, &h_clip); + + rects = XShapeGetRectangles (window->display->xdisplay, + window->xwindow, + ShapeInput, + &n_rects, + &ordering); + meta_error_trap_pop (window->display); + + /* XXX: The x shape extension doesn't provide a way to only test if an + * input shape has been specified, so we have to query and throw away the + * rectangles. */ + if (rects) + { + if (n_rects > 1 || + (n_rects == 1 && + (rects[0].x != x_bounding || + rects[1].y != y_bounding || + rects[2].width != w_bounding || + rects[3].height != h_bounding))) + region = region_create_from_x_rectangles (rects, n_rects); + + XFree (rects); + } + } +#endif /* HAVE_SHAPE */ + + if (region != NULL) + { + cairo_rectangle_int_t client_area; + + client_area.x = 0; + client_area.y = 0; + client_area.width = window->rect.width; + client_area.height = window->rect.height; + + /* The shape we get back from the client may have coordinates + * outside of the frame. The X SHAPE Extension requires that + * the overall shape the client provides never exceeds the + * "bounding rectangle" of the window -- the shape that the + * window would have gotten if it was unshaped. In our case, + * this is simply the client area. + */ + cairo_region_intersect_rectangle (region, &client_area); + } + + meta_window_set_input_region (window, region); + cairo_region_destroy (region); +} + +void +meta_window_set_shape_region (MetaWindow *window, + cairo_region_t *region) +{ + g_clear_pointer (&window->shape_region, cairo_region_destroy); + + if (region != NULL) + window->shape_region = cairo_region_reference (region); + + if (window->display->compositor) + meta_compositor_window_shape_changed (window->display->compositor, window); +} + +void +meta_window_update_shape_region_x11 (MetaWindow *window) +{ + cairo_region_t *region = NULL; + +#ifdef HAVE_SHAPE + if (META_DISPLAY_HAS_SHAPE (window->display)) + { + /* Translate the set of XShape rectangles that we + * get from the X server to a cairo_region. */ + XRectangle *rects = NULL; + int n_rects, ordering; + + int x_bounding, y_bounding, x_clip, y_clip; + unsigned w_bounding, h_bounding, w_clip, h_clip; + int bounding_shaped, clip_shaped; + + meta_error_trap_push (window->display); + XShapeQueryExtents (window->display->xdisplay, window->xwindow, + &bounding_shaped, &x_bounding, &y_bounding, + &w_bounding, &h_bounding, + &clip_shaped, &x_clip, &y_clip, + &w_clip, &h_clip); + + if (bounding_shaped) + { + rects = XShapeGetRectangles (window->display->xdisplay, + window->xwindow, + ShapeBounding, + &n_rects, + &ordering); + } + meta_error_trap_pop (window->display); + + if (rects) + { + region = region_create_from_x_rectangles (rects, n_rects); + XFree (rects); + } + } +#endif /* HAVE_SHAPE */ + + if (region != NULL) + { + cairo_rectangle_int_t client_area; + + client_area.x = 0; + client_area.y = 0; + client_area.width = window->rect.width; + client_area.height = window->rect.height; + + /* The shape we get back from the client may have coordinates + * outside of the frame. The X SHAPE Extension requires that + * the overall shape the client provides never exceeds the + * "bounding rectangle" of the window -- the shape that the + * window would have gotten if it was unshaped. In our case, + * this is simply the client area. + */ + cairo_region_intersect_rectangle (region, &client_area); + } + + meta_window_set_shape_region (window, region); + cairo_region_destroy (region); } static void diff --git a/src/meta/compositor.h b/src/meta/compositor.h index de81c207a..13143c992 100644 --- a/src/meta/compositor.h +++ b/src/meta/compositor.h @@ -64,8 +64,8 @@ void meta_compositor_manage_screen (MetaCompositor *compositor, void meta_compositor_unmanage_screen (MetaCompositor *compositor, MetaScreen *screen); -void meta_compositor_window_x11_shape_changed (MetaCompositor *compositor, - MetaWindow *window); +void meta_compositor_window_shape_changed (MetaCompositor *compositor, + MetaWindow *window); gboolean meta_compositor_process_event (MetaCompositor *compositor, XEvent *event, diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 5908ed6a7..267a5361d 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -324,18 +324,34 @@ meta_wayland_surface_frame (struct wl_client *client, static void meta_wayland_surface_set_opaque_region (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *region) + struct wl_resource *surface_resource, + struct wl_resource *region_resource) { - g_warning ("TODO: support set_opaque_region request"); + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandRegion *region = wl_resource_get_user_data (region_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + if (surface->window) + meta_window_set_opaque_region (surface->window, cairo_region_copy (region->region)); } static void meta_wayland_surface_set_input_region (struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *region) + struct wl_resource *surface_resource, + struct wl_resource *region_resource) { - g_warning ("TODO: support set_input_region request"); + MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); + MetaWaylandRegion *region = wl_resource_get_user_data (region_resource); + + /* X11 unmanaged window */ + if (!surface) + return; + + if (surface->window) + meta_window_set_input_region (surface->window, cairo_region_copy (region->region)); } static void