[mutter/wayland] wayland: Add support for set_opaque_region / set_input_region



commit 2d35e07faea2ab49d06598cc2c802fc49bdce3bd
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Fri Aug 23 22:20:49 2013 -0400

    wayland: Add support for set_opaque_region / set_input_region
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707019

 src/compositor/compositor.c        |    4 +-
 src/compositor/meta-window-actor.c |  236 ++++++++++-----------------------
 src/compositor/meta-window-group.c |   10 +--
 src/core/display.c                 |   54 +-------
 src/core/window-private.h          |   24 +++-
 src/core/window-props.c            |    2 +-
 src/core/window.c                  |  261 +++++++++++++++++++++++++++---------
 src/meta/compositor.h              |    4 +-
 src/wayland/meta-wayland.c         |   28 +++-
 9 files changed, 315 insertions(+), 308 deletions(-)
---
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 5565dd0..2156452 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -930,8 +930,8 @@ is_grabbed_event (MetaDisplay *display,
 }
 
 void
-meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
-                                          MetaWindow     *window)
+meta_compositor_window_shape_changed (MetaCompositor *compositor,
+                                      MetaWindow     *window)
 {
   MetaWindowActor *window_actor;
   window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index c599ac5..e7ca3f6 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>
@@ -71,7 +70,7 @@ struct _MetaWindowActorPrivate
   /* A region that matches the shape of the window, including frame bounds */
   cairo_region_t   *shape_region;
   /* If the window has an input shape, a region that matches the shape */
-  cairo_region_t   *input_shape_region;
+  cairo_region_t   *input_region;
   /* The opaque region, from _NET_WM_OPAQUE_REGION, intersected with
    * the shape region. */
   cairo_region_t   *opaque_region;
@@ -416,8 +415,8 @@ meta_window_actor_constructed (GObject *object)
 
   /* Start off with empty regions to maintain the invariant that
      these regions are always set */
-  priv->shape_region = cairo_region_create();
-  priv->input_shape_region = cairo_region_create();
+  priv->shape_region = cairo_region_create ();
+  priv->input_region = cairo_region_create ();
 }
 
 static void
@@ -447,7 +446,7 @@ meta_window_actor_dispose (GObject *object)
     }
 
   g_clear_pointer (&priv->shape_region, cairo_region_destroy);
-  g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
+  g_clear_pointer (&priv->input_region, cairo_region_destroy);
   g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
   g_clear_pointer (&priv->shadow_clip, cairo_region_destroy);
 
@@ -1269,7 +1268,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))
@@ -2180,33 +2179,36 @@ build_and_scan_frame_mask (MetaWindowActor       *self,
   g_free (mask_data);
 }
 
-static cairo_region_t *
-region_create_from_x_rectangles (const XRectangle *rects,
-                                 int n_rects,
-                                 int dx,
-                                 int dy)
+static void
+meta_window_actor_update_shape_region (MetaWindowActor       *self,
+                                       cairo_rectangle_int_t *client_area)
 {
-  int i;
-  cairo_rectangle_int_t *cairo_rects = g_newa (cairo_rectangle_int_t, n_rects);
+  MetaWindowActorPrivate *priv = self->priv;
+  cairo_region_t *region = NULL;
 
-  for (i = 0; i < n_rects; i ++)
+  if (priv->window->frame != NULL && priv->window->shape_region != 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);
+    }
+  else
     {
-      cairo_rects[i].x = rects[i].x + dx;
-      cairo_rects[i].y = rects[i].y + dy;
-      cairo_rects[i].width = rects[i].width;
-      cairo_rects[i].height = rects[i].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);
     }
 
-  return cairo_region_create_rectangles (cairo_rects, n_rects);
-}
+  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);
 
-static void
-meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
-                                           cairo_rectangle_int_t *client_area)
-{
-  MetaWindowActorPrivate *priv = self->priv;
-  cairo_region_t *region = NULL;
-  gboolean needs_mask;
+  g_clear_pointer (&priv->shape_region, cairo_region_destroy);
+  priv->shape_region = region;
 
   if (priv->shadow_shape != NULL)
     {
@@ -2214,51 +2216,32 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
       priv->shadow_shape = NULL;
     }
 
-  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);
+  meta_window_actor_invalidate_shadow (self);
+}
+
+static void
+meta_window_actor_update_input_region (MetaWindowActor       *self,
+                                       cairo_rectangle_int_t *client_area)
+{
+  MetaWindowActorPrivate *priv = self->priv;
+  MetaShapedTexture *stex = META_SHAPED_TEXTURE (priv->actor);
+  cairo_region_t *region = NULL;
 
-#ifdef HAVE_SHAPE
-  if (priv->window->has_shape)
+  if (priv->window->frame != NULL && priv->window->input_region != NULL)
     {
-      /* Translate the set of XShape rectangles that we
-       * get from the X server to a cairo_region. */
-      MetaScreen *screen = priv->screen;
-      MetaDisplay *display = meta_screen_get_display (screen);
-      Display *xdisplay = meta_display_get_xdisplay (display);
-      XRectangle *rects;
-      int n_rects, ordering;
+      region = meta_frame_get_frame_bounds (priv->window->frame);
 
-      meta_error_trap_push (display);
-      rects = XShapeGetRectangles (xdisplay,
-                                   priv->window->xwindow,
-                                   ShapeBounding,
-                                   &n_rects,
-                                   &ordering);
-      meta_error_trap_pop (display);
+      cairo_region_subtract_rectangle (region, client_area);
 
-      if (rects)
-        {
-          region = region_create_from_x_rectangles (rects, n_rects,
-                                                    client_area->x,
-                                                    client_area->y);
-          XFree (rects);
-        }
+      /* input_region is in client window coordinates, so translate the
+       * input region into that coordinate system and back */
+      cairo_region_translate (region, -client_area->x, -client_area->y);
+      cairo_region_union (region, priv->window->input_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->input_region);
     }
   else
     {
@@ -2268,11 +2251,23 @@ meta_window_actor_update_x11_shape_region (MetaWindowActor *self,
       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_input_shape_region (stex, region);
+  cairo_region_destroy (region);
+}
+
+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
@@ -2284,91 +2279,13 @@ meta_window_actor_update_x11_shape_region (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);
-
-  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);
-    }
-
-  priv->shape_region = region;
-
-  meta_window_actor_invalidate_shadow (self);
-}
-
-static void
-meta_window_actor_update_x11_input_shape_region (MetaWindowActor *self,
-                                                 cairo_rectangle_int_t *client_area)
-{
-  MetaWindowActorPrivate *priv = self->priv;
-  cairo_region_t *region = NULL;
-
-  g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
-
-#ifdef HAVE_SHAPE
-  /* Note: we currently assume that mutter never sets an input region
-   * when there is a frame. */
-  if (priv->window->frame == NULL && priv->window->has_input_shape)
-    {
-      MetaScreen *screen = priv->screen;
-      MetaDisplay *display = meta_screen_get_display (screen);
-      Display *xdisplay = meta_display_get_xdisplay (display);
-      XRectangle *rects;
-      int n_rects, ordering;
-
-      /* Note we only actually query the ShapeInput shape of a window
-       * when we don't have a frame because we assume currently that
-       * mutter never sets an ShapeInput shape on a frame. */
-      meta_error_trap_push (display);
-      rects = XShapeGetRectangles (xdisplay,
-                                   priv->window->xwindow,
-                                   ShapeInput,
-                                   &n_rects,
-                                   &ordering);
-      meta_error_trap_pop (display);
-      if (rects)
-        {
-          region = region_create_from_x_rectangles (rects, n_rects,
-                                                    client_area->x,
-                                                    client_area->y);
-          XFree (rects);
-        }
-    }
-#endif /* HAVE_SHAPE */
-
-  if (region != NULL)
-    {
-      /* The X shape extension requires us to intersect the input
-       * region with the effective bounding shape to determine the
-       * effective input region.
-       */
-      if (priv->shape_region)
-        cairo_region_intersect (region, priv->shape_region);
-      else
-        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);
-    }
-
-  priv->input_shape_region = region;
-
-  meta_shaped_texture_set_input_shape_region (META_SHAPED_TEXTURE (priv->actor),
-                                              priv->input_shape_region);
+    priv->opaque_region = cairo_region_reference (priv->shape_region);
 }
 
 static void
@@ -2394,24 +2311,9 @@ check_needs_reshape (MetaWindowActor *self)
   else
     client_area.height = priv->window->rect.height;
 
-  if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11)
-    {
-      meta_window_actor_update_x11_shape_region (self, &client_area);
-      meta_window_actor_update_x11_input_shape_region (self, &client_area);
-    }
-  else
-    {
-      /* TODO: properly support setting an input region as specified
-       * via the wayland protocol */
-
-      g_clear_pointer (&priv->shape_region, cairo_region_destroy);
-      g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
-      g_clear_pointer (&priv->input_shape_region, cairo_region_destroy);
-
-      priv->shape_region = cairo_region_create_rectangle (&client_area);
-      priv->opaque_region = cairo_region_reference (priv->shape_region);
-      priv->input_shape_region = cairo_region_reference (priv->shape_region);
-    }
+  meta_window_actor_update_shape_region (self, &client_area);
+  meta_window_actor_update_input_region (self, &client_area);
+  meta_window_actor_update_opaque_region (self);
 
   priv->needs_reshape = FALSE;
 }
diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c
index fe65f39..65771f7 100644
--- a/src/compositor/meta-window-group.c
+++ b/src/compositor/meta-window-group.c
@@ -186,7 +186,6 @@ meta_window_group_paint (ClutterActor *actor)
 
       if (META_IS_WINDOW_ACTOR (child))
         {
-          MetaWindow *meta_window;
           MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
           int x, y;
 
@@ -201,14 +200,7 @@ meta_window_group_paint (ClutterActor *actor)
 
           meta_window_actor_set_visible_region (window_actor, visible_region);
 
-          /* TODO: Track the opaque regions of wayland clients.
-           * Although wayland clients can report opaque window
-           * regions, for now we assume that all wayland clients are
-           * transparent... */
-          meta_window = meta_window_actor_get_meta_window (window_actor);
-
-          if (meta_window->client_type != META_WINDOW_CLIENT_TYPE_WAYLAND &&
-              clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
+          if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
             {
               cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
               if (obscured_region)
diff --git a/src/core/display.c b/src/core/display.c
index d62e429..7d67c2e 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2336,59 +2336,9 @@ meta_display_handle_event (MetaDisplay *display,
           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_x11_shape_changed (display->compositor,
-                                                          window);
-            }
+            meta_window_update_shape_region_x11 (window);
           else if (sev->kind == ShapeInput)
-            {
-              if (sev->shaped && !window->has_input_shape)
-                {
-                  window->has_input_shape = TRUE;                  
-                  meta_topic (META_DEBUG_SHAPES,
-                              "Window %s now has an input shape\n",
-                              window->desc);
-                }
-              else if (!sev->shaped && window->has_input_shape)
-                {
-                  window->has_input_shape = FALSE;
-                  meta_topic (META_DEBUG_SHAPES,
-                              "Window %s no longer has an input shape\n",
-                              window->desc);
-                }
-              else
-                {
-                  meta_topic (META_DEBUG_SHAPES,
-                              "Window %s input shape changed\n",
-                              window->desc);
-                }
-
-              if (display->compositor)
-                meta_compositor_window_x11_shape_changed (display->compositor,
-                                                          window);
-            }
+            meta_window_update_input_region_x11 (window);
         }
       else
         {
diff --git a/src/core/window-private.h b/src/core/window-private.h
index c068c35..c54036b 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -339,11 +339,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 bounding shape mask */
-  guint has_shape : 1;
-  /* has an input shape mask */
-  guint has_input_shape : 1;
-
   /* icon props have changed */
   guint need_reread_icon : 1;
   
@@ -365,9 +360,15 @@ 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;
 
+  /* the input shape region for picking */
+  cairo_region_t *input_region;
+
   /* if TRUE, the we have the new form of sync request counter which
    * also handles application frames */
   guint extended_sync_request_counter : 1;
@@ -685,7 +686,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);
 
@@ -699,4 +699,16 @@ 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_input_region         (MetaWindow     *window,
+                                           cairo_region_t *region);
+void meta_window_update_input_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 faf4bb2..5e87e58 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -822,8 +822,6 @@ meta_window_new_shared (MetaDisplay         *display,
                         Window               xwindow,
                         gboolean             must_be_viewable,
                         gulong               existing_wm_state,
-                        gboolean             has_shape,
-                        gboolean             has_input_shape,
                         MetaCompEffect       effect,
                         XWindowAttributes   *attrs)
 {
@@ -876,9 +874,6 @@ meta_window_new_shared (MetaDisplay         *display,
   /* avoid tons of stack updates */
   meta_stack_freeze (window->screen->stack);
 
-  window->has_shape = has_shape;
-  window->has_input_shape = has_input_shape;
-
   window->rect.x = attrs->x;
   window->rect.y = attrs->y;
   window->rect.width = attrs->width;
@@ -1059,6 +1054,8 @@ meta_window_new_shared (MetaDisplay         *display,
         }
 
       meta_display_register_x_window (display, &window->xwindow, window);
+      meta_window_update_shape_region_x11 (window);
+      meta_window_update_input_region_x11 (window);
     }
 
   /* assign the window to its group, or create a new group if needed
@@ -1425,8 +1422,6 @@ meta_window_new_for_wayland (MetaDisplay        *display,
                                    None,
                                    TRUE,
                                    WithdrawnState,
-                                   FALSE, /* has shape */
-                                   FALSE, /* has input shape */
                                    META_COMP_EFFECT_NONE,
                                    &attrs);
 
@@ -1455,8 +1450,6 @@ meta_window_new_with_attrs (MetaDisplay       *display,
   gulong existing_wm_state;
   MetaWindow *window;
   gulong event_mask;
-  gboolean has_shape = FALSE;
-  gboolean has_input_shape = FALSE;
 
   meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
 
@@ -1576,53 +1569,6 @@ meta_window_new_with_attrs (MetaDisplay       *display,
       XISelectEvents (display->xdisplay, xwindow, &mask, 1);
     }
 
-#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;
-      XRectangle *input_rectangles;
-      int n_rects, ordering;
-
-      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;
-
-      /* XXX: The x shape extension doesn't provide a way to only test if an
-       * input shape has been specified, so we have to query and throw away the
-       * rectangles. */
-      meta_error_trap_push (display);
-      input_rectangles = XShapeGetRectangles (display->xdisplay, xwindow,
-                                              ShapeInput, &n_rects, &ordering);
-      meta_error_trap_pop (display);
-      if (input_rectangles)
-        {
-          if (n_rects > 1 ||
-              (n_rects == 1 &&
-               (input_rectangles[0].x != x_bounding ||
-                input_rectangles[1].y != y_bounding ||
-                input_rectangles[2].width != w_bounding ||
-                input_rectangles[3].height != h_bounding)))
-            {
-              has_input_shape = TRUE;
-            }
-          XFree (input_rectangles);
-        }
-
-      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);
-    }
-#endif
-
   /* Get rid of any borders */
   if (attrs->border_width != 0)
     XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
@@ -1656,8 +1602,6 @@ meta_window_new_with_attrs (MetaDisplay       *display,
                                    xwindow,
                                    must_be_viewable,
                                    existing_wm_state,
-                                   has_shape,
-                                   has_input_shape,
                                    effect,
                                    attrs);
 
@@ -7810,14 +7754,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,
@@ -7860,11 +7815,191 @@ 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_input_region (MetaWindow     *window,
+                              cairo_region_t *region)
+{
+  g_clear_pointer (&window->input_region, cairo_region_destroy);
+
+  if (region != NULL)
+    window->input_region = cairo_region_reference (region);
+
   if (window->display->compositor)
-    meta_compositor_window_x11_shape_changed (window->display->compositor, window);
+    meta_compositor_window_shape_changed (window->display->compositor, window);
+}
+
+void
+meta_window_update_input_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);
+
+      rects = XShapeGetRectangles (window->display->xdisplay,
+                                   window->xwindow,
+                                   ShapeInput,
+                                   &n_rects,
+                                   &ordering);
+      meta_error_trap_pop (window->display);
+
+      /* XXX: The x shape extension doesn't provide a way to only test if an
+       * input shape has been specified, so we have to query and throw away the
+       * rectangles. */
+      if (rects)
+        {
+          if (n_rects > 1 ||
+              (n_rects == 1 &&
+               (rects[0].x != x_bounding ||
+                rects[1].y != y_bounding ||
+                rects[2].width != w_bounding ||
+                rects[3].height != h_bounding)))
+            region = region_create_from_x_rectangles (rects, n_rects);
+
+          XFree (rects);
+        }
+    }
+#endif /* HAVE_SHAPE */
+
+  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_input_region (window, region);
+  cairo_region_destroy (region);
+}
+
+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 /* HAVE_SHAPE */
+
+  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
diff --git a/src/meta/compositor.h b/src/meta/compositor.h
index de81c20..13143c9 100644
--- a/src/meta/compositor.h
+++ b/src/meta/compositor.h
@@ -64,8 +64,8 @@ void meta_compositor_manage_screen   (MetaCompositor *compositor,
 void meta_compositor_unmanage_screen (MetaCompositor *compositor,
                                       MetaScreen     *screen);
 
-void meta_compositor_window_x11_shape_changed (MetaCompositor *compositor,
-                                               MetaWindow     *window);
+void meta_compositor_window_shape_changed (MetaCompositor *compositor,
+                                           MetaWindow     *window);
 
 gboolean meta_compositor_process_event (MetaCompositor *compositor,
                                         XEvent         *event,
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 5908ed6..267a536 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -324,18 +324,34 @@ meta_wayland_surface_frame (struct wl_client *client,
 
 static void
 meta_wayland_surface_set_opaque_region (struct wl_client *client,
-                                        struct wl_resource *resource,
-                                        struct wl_resource *region)
+                                        struct wl_resource *surface_resource,
+                                        struct wl_resource *region_resource)
 {
-  g_warning ("TODO: support set_opaque_region request");
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  if (surface->window)
+    meta_window_set_opaque_region (surface->window, cairo_region_copy (region->region));
 }
 
 static void
 meta_wayland_surface_set_input_region (struct wl_client *client,
-                                       struct wl_resource *resource,
-                                       struct wl_resource *region)
+                                       struct wl_resource *surface_resource,
+                                       struct wl_resource *region_resource)
 {
-  g_warning ("TODO: support set_input_region request");
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaWaylandRegion *region = wl_resource_get_user_data (region_resource);
+
+  /* X11 unmanaged window */
+  if (!surface)
+    return;
+
+  if (surface->window)
+    meta_window_set_input_region (surface->window, cairo_region_copy (region->region));
 }
 
 static void


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