[mutter] window-actor: Add back antialiased window corners



commit 60c05a0dac2bbc7fa1aa5abde3d60c4a5749c1e4
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Fri Apr 27 00:15:30 2012 -0400

    window-actor: Add back antialiased window corners
    
    This simply adds fancy arcs to the mask texture. It's still not painted
    with GTK+ yet.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=676052

 src/compositor/meta-window-actor.c |  189 +++++++++++++++++++++++++++++-------
 1 files changed, 155 insertions(+), 34 deletions(-)
---
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 87eb0d8..0ebea53 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -1991,10 +1991,113 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
     }
 }
 
+#define TAU (2*M_PI)
+
+static void
+install_corners (MetaWindow       *window,
+                 MetaFrameBorders *borders,
+                 cairo_t          *cr)
+{
+  float top_left, top_right, bottom_left, bottom_right;
+  int x, y;
+  MetaRectangle outer;
+
+  meta_frame_get_corner_radiuses (window->frame,
+                                  &top_left,
+                                  &top_right,
+                                  &bottom_left,
+                                  &bottom_right);
+
+  meta_window_get_outer_rect (window, &outer);
+
+  /* top left */
+  x = borders->invisible.left;
+  y = borders->invisible.top;
+
+  cairo_arc (cr,
+             x + top_left,
+             y + top_left,
+             top_left,
+             2 * TAU / 4,
+             3 * TAU / 4);
+
+  /* top right */
+  x = borders->invisible.left + outer.width - top_right;
+  y = borders->invisible.top;
+
+  cairo_arc (cr,
+             x,
+             y + top_right,
+             top_right,
+             3 * TAU / 4,
+             4 * TAU / 4);
+
+  /* bottom right */
+  x = borders->invisible.left + outer.width - bottom_right;
+  y = borders->invisible.top + outer.height - bottom_right;
+
+  cairo_arc (cr,
+             x,
+             y,
+             bottom_right,
+             0 * TAU / 4,
+             1 * TAU / 4);
+
+  /* bottom left */
+  x = borders->invisible.left;
+  y = borders->invisible.top + outer.height - bottom_left;
+
+  cairo_arc (cr,
+             x + bottom_left,
+             y,
+             bottom_left,
+             1 * TAU / 4,
+             2 * TAU / 4);
+
+  cairo_set_source_rgba (cr, 1, 1, 1, 1);
+  cairo_fill (cr);
+}
+
 static void
-generate_mask (MetaWindowActor  *self,
-               MetaFrameBorders *borders,
-               cairo_region_t   *shape_region)
+scan_visible_region (guchar         *mask_data,
+                     int             stride,
+                     cairo_region_t *scan_area,
+                     cairo_region_t *union_against)
+{
+  int i, n_rects;
+  n_rects = cairo_region_num_rectangles (scan_area);
+
+  for (i = 0; i < n_rects; i++)
+    {
+      int x, y;
+      cairo_rectangle_int_t rect;
+
+      cairo_region_get_rectangle (scan_area, i, &rect);
+
+      for (y = rect.y; y < (rect.y + rect.height); y++)
+        {
+          for (x = rect.x; x < (rect.x + rect.width); x++)
+            {
+              int w = x;
+              while (mask_data[y * stride + w] == 255 && w < (rect.x + rect.width))
+                w++;
+
+              if (w > 0)
+                {
+                  cairo_rectangle_int_t tmp = { x, y, w - x, 1 };
+                  cairo_region_union_rectangle (union_against, &tmp);
+                  x = w;
+                }
+            }
+        }
+    }
+}
+
+static void
+build_and_scan_frame_mask (MetaWindowActor       *self,
+                           MetaFrameBorders      *borders,
+                           cairo_rectangle_int_t *client_area,
+                           cairo_region_t        *shape_region)
 {
   MetaWindowActorPrivate *priv = self->priv;
   guchar *mask_data;
@@ -2026,6 +2129,24 @@ generate_mask (MetaWindowActor  *self,
   gdk_cairo_region (cr, shape_region);
   cairo_fill (cr);
 
+  if (priv->window->frame != NULL)
+    {
+      cairo_region_t *frame_paint_region;
+      cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height };
+
+      /* Make sure we don't paint the frame over the client window. */
+      frame_paint_region = cairo_region_create_rectangle (&rect);
+      cairo_region_subtract_rectangle (frame_paint_region, client_area);
+
+      gdk_cairo_region (cr, frame_paint_region);
+      cairo_clip (cr);
+
+      install_corners (priv->window, borders, cr);
+
+      cairo_surface_flush (surface);
+      scan_visible_region (mask_data, stride, frame_paint_region, shape_region);
+    }
+
   cairo_destroy (cr);
   cairo_surface_destroy (surface);
 
@@ -2066,44 +2187,30 @@ check_needs_reshape (MetaWindowActor *self)
   MetaDisplay *display = meta_screen_get_display (screen);
   MetaFrameBorders borders;
   cairo_region_t *region;
+  cairo_rectangle_int_t client_area;
 
   if (!priv->needs_reshape)
     return;
 
-  meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE);
-  meta_window_actor_clear_shape_region (self);
-
   meta_frame_calc_borders (priv->window->frame, &borders);
 
-  region = meta_window_get_frame_bounds (priv->window);
-  if (region != NULL)
-    {
-      /* This returns the window's internal frame bounds region,
-       * so we need to copy it because we modify it below. */
-      region = cairo_region_copy (region);
-    }
-  else
-    {
-      /* If we have no region, we have no frame. We have no frame,
-       * so just use the bounding region instead */
-      region = cairo_region_copy (priv->bounding_region);
-    }
+  client_area.x = borders.total.left;
+  client_area.y = borders.total.top;
+  client_area.width = priv->window->rect.width;
+  client_area.height = priv->window->rect.height;
+
+  meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE);
+  meta_window_actor_clear_shape_region (self);
 
 #ifdef HAVE_SHAPE
   if (priv->window->has_shape)
     {
+      /* 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;
-      cairo_rectangle_int_t client_area;
-
-      client_area.width = priv->window->rect.width;
-      client_area.height = priv->window->rect.height;
-      client_area.x = borders.total.left;
-      client_area.y = borders.total.top;
-
-      /* Punch out client area. */
-      cairo_region_subtract_rectangle (region, &client_area);
+      cairo_rectangle_int_t *cairo_rects = NULL;
 
       meta_error_trap_push (display);
       rects = XShapeGetRectangles (xdisplay,
@@ -2116,20 +2223,34 @@ check_needs_reshape (MetaWindowActor *self)
       if (rects)
         {
           int i;
+          cairo_rects = g_new (cairo_rectangle_int_t, n_rects);
           for (i = 0; i < n_rects; i ++)
             {
-              cairo_rectangle_int_t rect = { rects[i].x + client_area.x,
-                                             rects[i].y + client_area.y,
-                                             rects[i].width,
-                                             rects[i].height };
-              cairo_region_union_rectangle (region, &rect);
+              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);
     }
+  else
 #endif
+    {
+      /* 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);
+    }
 
-  generate_mask (self, &borders, region);
+  /* 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, &borders, &client_area, region);
   meta_window_actor_update_shape_region (self, region);
 
   cairo_region_destroy (region);



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