From c2a9ccb7e2e0f7dc37866099a5e5a4a5727c679b Mon Sep 17 00:00:00 2001
From: Simon McVittie <simon.mcvittie@collabora.co.uk>
Date: Fri, 12 Apr 2013 18:00:15 +0100
Subject: [PATCH] Let the UI layer (via the core) construct the frame mask

This essentially just moves install_corners() from the compositor, through
the core, into the UI layer where it arguably should have been anyway,
leaving behind stub functions which call through the various layers. This
removes the compositor's special knowledge of how rounded corners work,
replacing it with "ask the UI for an alpha mask".

The computation of border widths and heights changes a bit, because the
width and height used in install_corners() are the
meta_window_get_outer_rect() (which includes the visible borders but not
the invisible ones), whereas the more readily-available rectangle is the
MetaFrame.rect (which includes both). Computing the same width and height
as meta_window_get_outer_rect() involves compensating for the invisible
borders, but the UI layer is the authority on those anyway, so it seems
clearer to have it do the calculations from scratch.

Bug: https://bugzilla.gnome.org/show_bug.cgi?id=697758
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Reviewed-by: Jasper St. Pierre <jstpierre@mecheye.net>
---
 src/compositor/meta-window-actor.c |  72 +------------------
 src/core/frame.c                   |  21 +++---
 src/core/frame.h                   |   9 +--
 src/ui/frames.c                    | 112 ++++++++++++++++++++++++-----
 src/ui/frames.h                    |  11 ++-
 src/ui/ui.c                        |  23 +++---
 src/ui/ui.h                        |  14 ++--
 7 files changed, 131 insertions(+), 131 deletions(-)

diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 5c667b060..04d754ba9 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -1993,73 +1993,6 @@ 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 cairo_region_t *
 scan_visible_region (guchar         *mask_data,
                      int             stride,
@@ -2099,7 +2032,6 @@ scan_visible_region (guchar         *mask_data,
 
 static void
 build_and_scan_frame_mask (MetaWindowActor       *self,
-                           MetaFrameBorders      *borders,
                            cairo_rectangle_int_t *client_area,
                            cairo_region_t        *shape_region)
 {
@@ -2145,7 +2077,7 @@ build_and_scan_frame_mask (MetaWindowActor       *self,
       gdk_cairo_region (cr, frame_paint_region);
       cairo_clip (cr);
 
-      install_corners (priv->window, borders, cr);
+      meta_frame_get_mask (priv->window->frame, cr);
 
       cairo_surface_flush (surface);
       scanned_region = scan_visible_region (mask_data, stride, frame_paint_region);
@@ -2308,7 +2240,7 @@ check_needs_reshape (MetaWindowActor *self)
        * and scans the mask looking for all opaque pixels,
        * adding it to region.
        */
-      build_and_scan_frame_mask (self, &borders, &client_area, region);
+      build_and_scan_frame_mask (self, &client_area, region);
     }
 
   priv->shape_region = region;
diff --git a/src/core/frame.c b/src/core/frame.c
index 15eb0cdcb..2c48bb166 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -332,19 +332,6 @@ meta_frame_calc_borders (MetaFrame        *frame,
                                borders);
 }
 
-void
-meta_frame_get_corner_radiuses (MetaFrame *frame,
-                                float     *top_left,
-                                float     *top_right,
-                                float     *bottom_left,
-                                float     *bottom_right)
-{
-  meta_ui_get_corner_radiuses (frame->window->screen->ui,
-                               frame->xwindow,
-                               top_left, top_right,
-                               bottom_left, bottom_right);
-}
-
 gboolean
 meta_frame_sync_to_window (MetaFrame *frame,
                            int        resize_gravity,
@@ -400,6 +387,14 @@ meta_frame_get_frame_bounds (MetaFrame *frame)
                                    frame->rect.height);
 }
 
+void
+meta_frame_get_mask (MetaFrame                    *frame,
+                     cairo_t                      *cr)
+{
+  meta_ui_get_frame_mask (frame->window->screen->ui, frame->xwindow,
+                          frame->rect.width, frame->rect.height, cr);
+}
+
 void
 meta_frame_queue_draw (MetaFrame *frame)
 {
diff --git a/src/core/frame.h b/src/core/frame.h
index d612f7779..cff9cb25c 100644
--- a/src/core/frame.h
+++ b/src/core/frame.h
@@ -63,12 +63,6 @@ Window         meta_frame_get_xwindow (MetaFrame *frame);
 void meta_frame_calc_borders      (MetaFrame        *frame,
                                    MetaFrameBorders *borders);
 
-void meta_frame_get_corner_radiuses (MetaFrame *frame,
-                                     float     *top_left,
-                                     float     *top_right,
-                                     float     *bottom_left,
-                                     float     *bottom_right);
-
 gboolean meta_frame_sync_to_window (MetaFrame         *frame,
                                     int                gravity,
                                     gboolean           need_move,
@@ -76,6 +70,9 @@ gboolean meta_frame_sync_to_window (MetaFrame         *frame,
 
 cairo_region_t *meta_frame_get_frame_bounds (MetaFrame *frame);
 
+void meta_frame_get_mask (MetaFrame *frame,
+                          cairo_t   *cr);
+
 void meta_frame_set_screen_cursor (MetaFrame	*frame,
 				   MetaCursor	cursor);
 
diff --git a/src/ui/frames.c b/src/ui/frames.c
index bd862000d..63f18379d 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -739,22 +739,6 @@ meta_ui_frame_get_corner_radiuses (MetaFrames  *frames,
     *bottom_right = fgeom.bottom_right_corner_rounded_radius + sqrt(fgeom.bottom_right_corner_rounded_radius);
 }
 
-void
-meta_frames_get_corner_radiuses (MetaFrames *frames,
-                                 Window      xwindow,
-                                 float      *top_left,
-                                 float      *top_right,
-                                 float      *bottom_left,
-                                 float      *bottom_right)
-{
-  MetaUIFrame *frame;
-
-  frame = meta_frames_lookup_window (frames, xwindow);
-
-  meta_ui_frame_get_corner_radiuses (frames, frame, top_left, top_right,
-                                     bottom_left, bottom_right);
-}
-
 void
 meta_frames_reset_bg (MetaFrames *frames,
                       Window  xwindow)
@@ -1851,6 +1835,102 @@ clip_region_to_visible_frame_border (cairo_region_t *region,
   cairo_region_destroy (frame_border);
 }
 
+#define TAU (2*M_PI)
+
+/*
+ * Draw the opaque and semi-opaque pixels of this frame into a mask.
+ *
+ * (0,0) in Cairo coordinates is assumed to be the top left corner of the
+ * invisible border.
+ *
+ * The parts of @cr's surface in the clip region are assumed to be
+ * initialized to fully-transparent, and the clip region is assumed to
+ * contain the invisible border and the visible parts of the frame, but
+ * not the client area.
+ *
+ * This function uses @cr to draw pixels of arbitrary color (it will
+ * typically be drawing in a %CAIRO_FORMAT_A8 surface, so the color is
+ * discarded anyway) with appropriate alpha values to reproduce this
+ * frame's alpha channel, as a mask to be applied to an opaque pixmap.
+ *
+ * @frame: This frame
+ * @xwindow: The X window for the frame, which has the client window as a child
+ * @width: The width of the framed window including any invisible borders
+ * @height: The height of the framed window including any invisible borders
+ * @cr: Used to draw the resulting mask
+ */
+void
+meta_frames_get_mask (MetaFrames          *frames,
+                      Window               xwindow,
+                      guint                width,
+                      guint                height,
+                      cairo_t             *cr)
+{
+  MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
+  float top_left, top_right, bottom_left, bottom_right;
+  int x, y;
+  MetaFrameBorders borders;
+
+  if (frame == NULL)
+    meta_bug ("No such frame 0x%lx\n", xwindow);
+
+  cairo_save (cr);
+
+  meta_ui_frame_get_borders (frames, frame, &borders);
+  meta_ui_frame_get_corner_radiuses (frames, frame,
+                                     &top_left, &top_right,
+                                     &bottom_left, &bottom_right);
+
+  /* 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 = width - borders.invisible.right - top_right;
+  y = borders.invisible.top;
+
+  cairo_arc (cr,
+             x,
+             y + top_right,
+             top_right,
+             3 * TAU / 4,
+             4 * TAU / 4);
+
+  /* bottom right */
+  x = width - borders.invisible.right - bottom_right;
+  y = height - borders.invisible.bottom - bottom_right;
+
+  cairo_arc (cr,
+             x,
+             y,
+             bottom_right,
+             0 * TAU / 4,
+             1 * TAU / 4);
+
+  /* bottom left */
+  x = borders.invisible.left;
+  y = height - borders.invisible.bottom - 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);
+
+  cairo_restore (cr);
+}
+
 static gboolean
 meta_frames_draw (GtkWidget *widget,
                   cairo_t   *cr)
diff --git a/src/ui/frames.h b/src/ui/frames.h
index be238a84b..3298fc2cf 100644
--- a/src/ui/frames.h
+++ b/src/ui/frames.h
@@ -140,12 +140,11 @@ cairo_region_t *meta_frames_get_frame_bounds (MetaFrames *frames,
                                               int         window_width,
                                               int         window_height);
 
-void meta_frames_get_corner_radiuses (MetaFrames *frames,
-                                      Window      xwindow,
-                                      float      *top_left,
-                                      float      *top_right,
-                                      float      *bottom_left,
-                                      float      *bottom_right);
+void meta_frames_get_mask (MetaFrames *frames,
+                           Window      xwindow,
+                           guint       width,
+                           guint       height,
+                           cairo_t    *cr);
 
 void meta_frames_move_resize_frame (MetaFrames *frames,
 				    Window      xwindow,
diff --git a/src/ui/ui.c b/src/ui/ui.c
index af28263be..c0c819e68 100644
--- a/src/ui/ui.c
+++ b/src/ui/ui.c
@@ -324,6 +324,16 @@ meta_ui_free (MetaUI *ui)
   g_free (ui);
 }
 
+void
+meta_ui_get_frame_mask (MetaUI  *ui,
+                        Window   frame_xwindow,
+                        guint    width,
+                        guint    height,
+                        cairo_t *cr)
+{
+  meta_frames_get_mask (ui->frames, frame_xwindow, width, height, cr);
+}
+
 void
 meta_ui_get_frame_borders (MetaUI *ui,
                            Window frame_xwindow,
@@ -333,19 +343,6 @@ meta_ui_get_frame_borders (MetaUI *ui,
                            borders);
 }
 
-void
-meta_ui_get_corner_radiuses (MetaUI *ui,
-                             Window  xwindow,
-                             float  *top_left,
-                             float  *top_right,
-                             float  *bottom_left,
-                             float  *bottom_right)
-{
-  meta_frames_get_corner_radiuses (ui->frames, xwindow,
-                                   top_left, top_right,
-                                   bottom_left, bottom_right);
-}
-
 Window
 meta_ui_create_frame_window (MetaUI *ui,
                              Display *xdisplay,
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 4a510b5c7..2ea3ca12c 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -66,6 +66,13 @@ void meta_ui_theme_get_frame_borders (MetaUI *ui,
 void meta_ui_get_frame_borders (MetaUI *ui,
                                 Window frame_xwindow,
                                 MetaFrameBorders *borders);
+
+void meta_ui_get_frame_mask (MetaUI *ui,
+                             Window frame_xwindow,
+                             guint width,
+                             guint height,
+                             cairo_t *cr);
+
 Window meta_ui_create_frame_window (MetaUI *ui,
                                     Display *xdisplay,
                                     Visual *xvisual,
@@ -102,13 +109,6 @@ cairo_region_t *meta_ui_get_frame_bounds (MetaUI  *ui,
                                           int      window_width,
                                           int      window_height);
 
-void meta_ui_get_corner_radiuses (MetaUI *ui,
-                                  Window  xwindow,
-                                  float  *top_left,
-                                  float  *top_right,
-                                  float  *bottom_left,
-                                  float  *bottom_right);
-
 void meta_ui_queue_frame_draw (MetaUI *ui,
                                Window xwindow);