diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index db01638f8..4588905b9 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -10,7 +10,6 @@ #include -#include #include #include #include @@ -400,7 +399,7 @@ meta_window_actor_constructed (GObject *object) /* Start off with an empty region to maintain the invariant that the shape region is always set */ - priv->shape_region = cairo_region_create(); + priv->shape_region = cairo_region_create (); } static void @@ -1332,7 +1331,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)) @@ -2220,101 +2219,53 @@ build_and_scan_frame_mask (MetaWindowActor *self, } static void -check_needs_reshape (MetaWindowActor *self) +meta_window_actor_update_shape_region (MetaWindowActor *self, + cairo_rectangle_int_t *client_area) { MetaWindowActorPrivate *priv = self->priv; - MetaScreen *screen = priv->screen; - MetaDisplay *display = meta_screen_get_display (screen); - MetaFrameBorders borders; cairo_region_t *region = NULL; - cairo_rectangle_int_t client_area; - gboolean needs_mask; - if (!priv->mapped) - return; - - if (!priv->needs_reshape) - return; - - g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); - - meta_frame_calc_borders (priv->window->frame, &borders); - - client_area.x = borders.total.left; - client_area.y = borders.total.top; - client_area.width = priv->window->rect.width; - if (priv->window->shaded) - client_area.height = 0; - else - client_area.height = priv->window->rect.height; - - 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) + if (priv->window->frame != NULL && priv->window->shape_region != NULL) { - /* Translate the set of XShape rectangles that we - * get from the X server to a cairo_region. */ - 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) - { - int i; - cairo_rectangle_int_t *cairo_rects = g_new (cairo_rectangle_int_t, n_rects); - - for (i = 0; i < n_rects; i ++) - { - cairo_rects[i].x = rects[i].x + client_area.x; - cairo_rects[i].y = rects[i].y + client_area.y; - cairo_rects[i].width = rects[i].width; - cairo_rects[i].height = rects[i].height; - } - - XFree (rects); - region = cairo_region_create_rectangles (cairo_rects, n_rects); - g_free (cairo_rects); - } + region = cairo_region_copy (priv->window->shape_region); + cairo_region_translate (region, client_area->x, client_area->y); } -#endif - - needs_mask = (region != NULL) || (priv->window->frame != NULL); - - if (region != NULL) + else if (priv->window->shape_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 { /* 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); + 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; + + g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); + meta_window_actor_invalidate_shadow (self); +} + +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 @@ -2326,24 +2277,40 @@ check_needs_reshape (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); + priv->opaque_region = cairo_region_reference (priv->shape_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); - } +static void +check_needs_reshape (MetaWindowActor *self) +{ + MetaWindowActorPrivate *priv = self->priv; + MetaFrameBorders borders; + cairo_rectangle_int_t client_area; - priv->shape_region = region; + if (!priv->mapped) + return; + + if (!priv->needs_reshape) + return; + + meta_frame_calc_borders (priv->window->frame, &borders); + + client_area.x = borders.total.left; + client_area.y = borders.total.top; + client_area.width = priv->window->rect.width; + if (priv->window->shaded) + client_area.height = 0; + else + client_area.height = priv->window->rect.height; + + meta_window_actor_update_shape_region (self, &client_area); + meta_window_actor_update_opaque_region (self); priv->needs_reshape = FALSE; meta_window_actor_invalidate_shadow (self); diff --git a/src/core/display.c b/src/core/display.c index f412c66c9..3f3a45f74 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -2283,32 +2283,7 @@ event_callback (XEvent *event, 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_shape_changed (display->compositor, - window); - } + meta_window_update_shape_region_x11 (window); } else { diff --git a/src/core/window-private.h b/src/core/window-private.h index e7255beab..757263241 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -325,9 +325,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 shape mask */ - guint has_shape : 1; - /* icon props have changed */ guint need_reread_icon : 1; @@ -349,6 +346,9 @@ 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; @@ -665,7 +665,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); @@ -679,4 +678,12 @@ 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_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 b109ec3f1..9b49cfbab 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -825,7 +825,6 @@ meta_window_new_with_attrs (MetaDisplay *display, gulong existing_wm_state; gulong event_mask; MetaMoveResizeFlags flags; - gboolean has_shape; MetaScreen *screen; g_assert (attrs != NULL); @@ -959,29 +958,9 @@ meta_window_new_with_attrs (MetaDisplay *display, XISelectEvents (display->xdisplay, xwindow, &mask, 1); } - has_shape = FALSE; #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; - - 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; - - 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); - } + XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask); #endif /* Get rid of any borders */ @@ -1041,8 +1020,6 @@ meta_window_new_with_attrs (MetaDisplay *display, /* avoid tons of stack updates */ meta_stack_freeze (window->screen->stack); - window->has_shape = has_shape; - window->rect.x = attrs->x; window->rect.y = attrs->y; window->rect.width = attrs->width; @@ -1213,6 +1190,8 @@ meta_window_new_with_attrs (MetaDisplay *display, meta_display_register_x_window (display, &window->xwindow, window); + meta_window_update_shape_region_x11 (window); + /* Assign this #MetaWindow a sequence number which can be used * for sorting. */ @@ -7637,14 +7616,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, @@ -7687,13 +7677,108 @@ 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_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 + + 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 redraw_icon (MetaWindow *window) {