[mutter/wip/shape: 1/6] Refactor how shapes are done



commit b42cd305923ab0ccc7fc7f0fa72db8d011cbebf7
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Fri Aug 23 23:30:47 2013 -0400

    Refactor how shapes are done

 src/compositor/meta-window-actor.c |  158 ++++++++++++++---------------------
 src/core/display.c                 |   27 +------
 src/core/window-private.h          |   15 +++-
 src/core/window-props.c            |    2 +-
 src/core/window.c                  |  141 +++++++++++++++++++++++++-------
 5 files changed, 189 insertions(+), 154 deletions(-)
---
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 1d90114..a32afed 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -10,7 +10,6 @@
 
 #include <math.h>
 
-#include <X11/extensions/shape.h>
 #include <X11/extensions/Xcomposite.h>
 #include <X11/extensions/Xdamage.h>
 #include <X11/extensions/Xrender.h>
@@ -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,105 +2219,58 @@ 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;
 
-  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);
+    }
+  else if (priv->window->shape_region != NULL)
+    {
+      region = cairo_region_reference (priv->window->shape_region);
     }
-
-  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;
+    {
+      /* 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_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);
-  g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
+  priv->shape_region = region;
 
-#ifdef HAVE_SHAPE
-  if (priv->window->has_shape)
+  if (priv->shadow_shape != 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);
-        }
+      meta_window_shape_unref (priv->shadow_shape);
+      priv->shadow_shape = NULL;
     }
-#endif
 
-  needs_mask = (region != NULL) || (priv->window->frame != NULL);
+  meta_window_actor_invalidate_shadow (self);
+}
 
-  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);
-    }
-  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);
-    }
+static void
+meta_window_actor_update_opaque_region (MetaWindowActor *self)
+{
+  MetaWindowActorPrivate *priv = self->priv;
 
-  /* The region at this point should be constrained to the
-   * bounds of the client rectangle. */
+  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
@@ -2330,24 +2282,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 f412c66..3f3a45f 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 e7255be..7572632 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 adbfe59..13ee3bb 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 b109ec3..9b49cfb 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)
 {


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