diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 8c1617dea..ce691ae90 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -70,6 +70,9 @@ struct _MetaWindowActorPrivate /* A region that matches the shape of the window, including frame bounds */ cairo_region_t *shape_region; + /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with + * the shape region. */ + cairo_region_t *opaque_region; /* The region we should clip to when painting the shadow */ cairo_region_t *shadow_clip; @@ -387,6 +390,7 @@ meta_window_actor_dispose (GObject *object) meta_window_actor_detach (self); g_clear_pointer (&priv->shape_region, cairo_region_destroy); + g_clear_pointer (&priv->opaque_region, cairo_region_destroy); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); g_clear_pointer (&priv->shadow_class, g_free); @@ -1551,8 +1555,8 @@ meta_window_actor_get_obscured_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - if (!priv->argb32 && priv->opacity == 0xff && priv->back_pixmap) - return priv->shape_region; + if (priv->back_pixmap && priv->opacity == 0xff) + return priv->opaque_region; else return NULL; } @@ -2182,6 +2186,27 @@ check_needs_reshape (MetaWindowActor *self) /* The region at this point should be constrained to the * bounds of the client rectangle. */ + if (priv->argb32 && priv->window->opaque_region != NULL) + { + /* 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 + * windows and shadows beneath them. + * + * If the client gives bad coordinates where it does not + * fully paint, the behavior is defined by the specification + * to be undefined, and considered a client bug. In mutter's + * 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); + } + 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+ diff --git a/src/core/window-private.h b/src/core/window-private.h index becfef5d6..f7228ed2b 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -346,6 +346,9 @@ struct _MetaWindow /* if non-NULL, the bounds of the window frame */ cairo_region_t *frame_bounds; + /* if non-NULL, the opaque region _NET_WM_OPAQUE_REGION */ + cairo_region_t *opaque_region; + /* Note: can be NULL */ GSList *struts; @@ -648,6 +651,7 @@ 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); diff --git a/src/core/window-props.c b/src/core/window-props.c index e01934bcf..64bbdb28e 100644 --- a/src/core/window-props.c +++ b/src/core/window-props.c @@ -520,6 +520,14 @@ reload_wm_name (MetaWindow *window, } } +static void +reload_opaque_region (MetaWindow *window, + MetaPropValue *value, + gboolean initial) +{ + meta_window_update_opaque_region (window); +} + static void reload_mutter_hints (MetaWindow *window, MetaPropValue *value, @@ -1706,6 +1714,7 @@ meta_display_init_window_prop_hooks (MetaDisplay *display) { display->atom__NET_WM_PID, META_PROP_VALUE_CARDINAL, reload_net_wm_pid, TRUE, TRUE }, { XA_WM_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_name, TRUE, TRUE }, { display->atom__MUTTER_HINTS, META_PROP_VALUE_TEXT_PROPERTY, reload_mutter_hints, TRUE, TRUE }, + { display->atom__NET_WM_OPAQUE_REGION, META_PROP_VALUE_CARDINAL_LIST, reload_opaque_region, TRUE, TRUE }, { display->atom__NET_WM_ICON_NAME, META_PROP_VALUE_UTF8, reload_net_wm_icon_name, TRUE, FALSE }, { XA_WM_ICON_NAME, META_PROP_VALUE_TEXT_PROPERTY, reload_wm_icon_name, TRUE, FALSE }, { display->atom__NET_WM_DESKTOP, META_PROP_VALUE_CARDINAL, reload_net_wm_desktop, TRUE, FALSE }, diff --git a/src/core/window.c b/src/core/window.c index e5023e4a4..ead4d810f 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -226,6 +226,9 @@ meta_window_finalize (GObject *object) if (window->frame_bounds) cairo_region_destroy (window->frame_bounds); + if (window->opaque_region) + cairo_region_destroy (window->opaque_region); + meta_icon_cache_free (&window->icon_cache); g_free (window->sm_client_id); @@ -7388,6 +7391,64 @@ meta_window_update_net_wm_type (MetaWindow *window) meta_window_recalc_window_type (window); } +void +meta_window_update_opaque_region (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, + ®ion, &nitems)) + { + cairo_rectangle_int_t *rects; + int i, rect_index, nrects; + + if (nitems % 4 != 0) + { + meta_verbose ("_NET_WM_OPAQUE_REGION does not have a list of 4-tuples."); + goto out; + } + + /* empty region */ + if (nitems == 0) + goto out; + + nrects = nitems / 4; + + rects = g_new (cairo_rectangle_int_t, nrects); + + rect_index = 0; + i = 0; + while (i < nitems) + { + cairo_rectangle_int_t *rect = &rects[rect_index]; + + rect->x = region[i++]; + rect->y = region[i++]; + rect->width = region[i++]; + rect->height = region[i++]; + + rect_index++; + } + + opaque_region = cairo_region_create_rectangles (rects, nrects); + + g_free (rects); + } + + out: + window->opaque_region = opaque_region; + meta_XFree (region); + + if (window->display->compositor) + meta_compositor_window_shape_changed (window->display->compositor, window); +} + static void redraw_icon (MetaWindow *window) { diff --git a/src/meta/atomnames.h b/src/meta/atomnames.h index a8598e653..ca0520fd0 100644 --- a/src/meta/atomnames.h +++ b/src/meta/atomnames.h @@ -173,6 +173,7 @@ item(_NET_WM_STATE_STICKY) item(_NET_WM_FULLSCREEN_MONITORS) item(_NET_WM_STATE_FOCUSED) item(_NET_WM_BYPASS_COMPOSITOR) +item(_NET_WM_OPAQUE_REGION) #if 0 /* We apparently never use: */