[metacity] window: get bounding shape region



commit 619bb121fb511847c01769941dd6c94b606e3695
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sun Mar 12 12:06:04 2017 +0200

    window: get bounding shape region

 src/core/display.c        |    2 +
 src/core/window-private.h |    5 ++
 src/core/window.c         |  135 +++++++++++++++++++++++++++++++++++++--------
 3 files changed, 119 insertions(+), 23 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index 421afb4..848e3e2 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1850,6 +1850,8 @@ event_callback (XEvent   *event,
                               window->desc);
                 }
 
+              meta_window_update_shape_region (window);
+
               if (window->frame)
                 {
                   window->frame->need_reapply_frame_shape = TRUE;
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 4eba584..b7949d9 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -343,6 +343,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;
 
@@ -728,4 +731,6 @@ MetaFrameType meta_window_get_frame_type (MetaWindow *window);
 
 gboolean meta_window_updates_are_frozen (MetaWindow *window);
 
+void meta_window_update_shape_region (MetaWindow *window);
+
 #endif
diff --git a/src/core/window.c b/src/core/window.c
index 9b4f5ac..de34e64 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -273,7 +273,6 @@ meta_window_new (MetaDisplay    *display,
   gulong existing_wm_state;
   gulong event_mask;
   MetaMoveResizeFlags flags;
-  gboolean has_shape;
 
   meta_display_grab (display);
   meta_error_trap_push (display); /* Push a trap over all of window
@@ -352,28 +351,8 @@ meta_window_new (MetaDisplay    *display,
    */
   XSelectInput (display->xdisplay, xwindow, attrs.your_event_mask | event_mask);
 
-  has_shape = FALSE;
   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);
 
   /* Get rid of any borders */
   if (attrs.border_width != 0)
@@ -430,7 +409,7 @@ meta_window_new (MetaDisplay    *display,
   /* avoid tons of stack updates */
   meta_stack_freeze (window->screen->stack);
 
-  window->has_shape = has_shape;
+  window->has_shape = FALSE;
 
   window->rect.x = attrs.x;
   window->rect.y = attrs.y;
@@ -523,6 +502,7 @@ meta_window_new (MetaDisplay    *display,
   window->disable_sync = FALSE;
   window->attached = FALSE;
   window->frame_bounds = NULL;
+  window->shape_region = NULL;
   window->opaque_region = NULL;
   window->opacity = 0xffffffff;
 
@@ -599,6 +579,8 @@ meta_window_new (MetaDisplay    *display,
 
   meta_display_register_x_window (display, &window->xwindow, window);
 
+  meta_window_update_shape_region (window);
+
   /* assign the window to its group, or create a new group if needed
    */
   window->group = NULL;
@@ -1271,6 +1253,9 @@ meta_window_free (MetaWindow  *window,
   if (window->frame_bounds)
     cairo_region_destroy (window->frame_bounds);
 
+  if (window->shape_region)
+    cairo_region_destroy (window->shape_region);
+
   if (window->opaque_region)
     cairo_region_destroy (window->opaque_region);
 
@@ -9106,3 +9091,107 @@ meta_window_is_attached_dialog (MetaWindow *window)
 {
   return window->attached;
 }
+
+void
+meta_window_update_shape_region (MetaWindow *window)
+{
+  cairo_region_t *shape_region;
+  int bshaped;
+  int xbs;
+  int ybs;
+  unsigned int wbs;
+  unsigned int hbs;
+  int cshaped;
+  int xcs;
+  int ycs;
+  unsigned int wcs;
+  unsigned int hcs;
+
+  if (!window->display->have_shape)
+    return;
+
+  meta_error_trap_push (window->display);
+
+  XShapeQueryExtents (window->display->xdisplay, window->xwindow,
+                      &bshaped, &xbs, &ybs, &wbs, &hbs,
+                      &cshaped, &xcs, &ycs, &wcs, &hcs);
+
+  if (bshaped)
+    {
+      XRectangle *rects;
+      int n_rects;
+      int ordering;
+
+      window->has_shape = TRUE;
+
+      rects = XShapeGetRectangles (window->display->xdisplay, window->xwindow,
+                                   ShapeBounding, &n_rects, &ordering);
+
+      if (rects)
+        {
+          cairo_rectangle_int_t cairo_rects[n_rects];
+          int i;
+
+          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;
+            }
+
+          shape_region = cairo_region_create_rectangles (cairo_rects, n_rects);
+          XFree (rects);
+        }
+      else
+        {
+          shape_region = NULL;
+        }
+    }
+  else
+    {
+      window->has_shape = FALSE;
+      shape_region = NULL;
+    }
+
+  meta_error_trap_pop (window->display);
+
+  if (shape_region != NULL)
+    {
+      cairo_rectangle_int_t client_area;
+      cairo_region_overlap_t overlap;
+
+      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 (shape_region, &client_area);
+
+      /* Some applications might explicitly set their bounding region
+       * to the client area. Detect these cases, and throw out the
+       * bounding region in this case.
+       */
+      overlap = cairo_region_contains_rectangle (shape_region, &client_area);
+      if (overlap == CAIRO_REGION_OVERLAP_IN)
+        g_clear_pointer (&shape_region, cairo_region_destroy);
+    }
+
+  if (cairo_region_equal (window->shape_region, shape_region))
+    {
+      cairo_region_destroy (shape_region);
+      return;
+    }
+
+  g_clear_pointer (&window->shape_region, cairo_region_destroy);
+  window->shape_region = shape_region;
+
+  meta_compositor_window_shape_changed (window->display->compositor, window);
+}


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