[mutter] Support _NET_WM_OPAQUE_REGION



commit a613a55658c5717481e1f2d34987715d5f0a5ca4
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Jan 14 20:45:31 2013 -0500

    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

 src/compositor/meta-window-actor.c |   29 ++++++++++++++++-
 src/core/window-private.h          |    4 ++
 src/core/window-props.c            |    9 +++++
 src/core/window.c                  |   61 ++++++++++++++++++++++++++++++++++++
 src/meta/atomnames.h               |    1 +
 5 files changed, 102 insertions(+), 2 deletions(-)
---
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 8c1617d..ce691ae 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 becfef5..f7228ed 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 e01934b..64bbdb2 100644
--- a/src/core/window-props.c
+++ b/src/core/window-props.c
@@ -521,6 +521,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,
                      gboolean       initial)
@@ -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 e5023e4..ead4d81 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,
+                                   &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)
 {
diff --git a/src/meta/atomnames.h b/src/meta/atomnames.h
index a8598e6..ca0520f 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: */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]