Support _NET_WM_OPAQUE_REGION

This new hint allows compositors to know what portions of a window
will be obscured, as a region above them is opaque. For an RGB window,
possible to glean this information from the bounding shape region of
a client window, but not for an ARGB32 window. This new hint allows
clients that use ARGB32 windows to say which part of the window is
opaque, allowing this sort of optimization.

https://bugzilla.gnome.org/show_bug.cgi?id=679901
This commit is contained in:
Jasper St. Pierre 2013-01-14 20:45:31 -05:00
parent 3fe5a676c2
commit a613a55658
5 changed files with 102 additions and 2 deletions

View File

@ -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+

View File

@ -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);

View File

@ -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 },

View File

@ -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,
&region, &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)
{

View File

@ -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: */