[metacity] compositor: create picture with window mask



commit 29e227758897d2bd6531c8b05a778d6bb6b6c774
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Fri Apr 15 23:59:48 2016 +0300

    compositor: create picture with window mask

 src/compositor/compositor-xrender.c |  113 +++++++++++++++++++++++++++
 src/ui/frames.c                     |  144 ++++------------------------------
 2 files changed, 130 insertions(+), 127 deletions(-)
---
diff --git a/src/compositor/compositor-xrender.c b/src/compositor/compositor-xrender.c
index 0ade045..d4290fd 100644
--- a/src/compositor/compositor-xrender.c
+++ b/src/compositor/compositor-xrender.c
@@ -34,6 +34,7 @@
 #include <gdk/gdk.h>
 #include <libmetacity/meta-frame-borders.h>
 #include <cairo/cairo-xlib.h>
+#include <cairo/cairo-xlib-xrender.h>
 
 #include "display.h"
 #include "screen.h"
@@ -168,6 +169,7 @@ typedef struct _MetaCompWindow
 
   Damage damage;
   Picture picture;
+  Picture mask;
   Picture alpha_pict;
 
   gboolean needs_shadow;
@@ -1297,6 +1299,90 @@ get_window_picture (MetaCompWindow *cw)
   return None;
 }
 
+static Picture
+get_window_mask (MetaCompWindow *cw)
+{
+  MetaFrame *frame;
+  MetaDisplay *display;
+  Display *xdisplay;
+  int width;
+  int height;
+  XRenderPictFormat *format;
+  Pixmap pixmap;
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  Picture picture;
+
+  if (cw->window == NULL)
+    return None;
+
+  frame = meta_window_get_frame (cw->window);
+  if (frame == NULL)
+    return None;
+
+  display = meta_screen_get_display (cw->screen);
+  xdisplay = meta_display_get_xdisplay (display);
+  width = cw->attrs.width + cw->attrs.border_width * 2;
+  height = cw->attrs.height + cw->attrs.border_width * 2;
+  format = XRenderFindStandardFormat (xdisplay, PictStandardA8);
+
+  meta_error_trap_push (display);
+  pixmap = XCreatePixmap (xdisplay, cw->id, width, height, format->depth);
+  if (meta_error_trap_pop_with_return (display, FALSE) != 0)
+    return None;
+
+  surface = cairo_xlib_surface_create_with_xrender_format (xdisplay, pixmap,
+                                                           DefaultScreenOfDisplay (xdisplay),
+                                                           format, width, height);
+
+  cr = cairo_create (surface);
+
+  cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+  cairo_set_source_rgba (cr, 0, 0, 0, 1);
+  cairo_paint (cr);
+
+  {
+    cairo_rectangle_int_t rect;
+    cairo_region_t *frame_paint_region;
+    MetaFrameBorders borders;
+
+    rect.x = 0;
+    rect.y = 0;
+    rect.width = width;
+    rect.height = height;
+
+    frame_paint_region = cairo_region_create_rectangle (&rect);
+    meta_frame_calc_borders (frame, &borders);
+
+    rect.x += borders.total.left;
+    rect.y += borders.total.top;
+    rect.width -= borders.total.left + borders.total.right;
+    rect.height -= borders.total.top + borders.total.bottom;
+
+    cairo_region_subtract_rectangle (frame_paint_region, &rect);
+
+    gdk_cairo_region (cr, frame_paint_region);
+    cairo_clip (cr);
+
+    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+    meta_frame_get_mask (frame, cr);
+
+    cairo_surface_flush (surface);
+    cairo_region_destroy (frame_paint_region);
+  }
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+
+  meta_error_trap_push (display);
+  picture = XRenderCreatePicture (xdisplay, pixmap, format, 0, NULL);
+  meta_error_trap_pop (display, FALSE);
+
+  XFreePixmap (xdisplay, pixmap);
+
+  return picture;
+}
+
 static void
 paint_dock_shadows (MetaScreen   *screen,
                     Picture       root_buffer,
@@ -1404,6 +1490,9 @@ paint_windows (MetaScreen   *screen,
       if (cw->picture == None)
         cw->picture = get_window_picture (cw);
 
+      if (cw->mask == None)
+        cw->mask = get_window_mask (cw);
+
       /* If the clip region of the screen has been changed
          then we need to recreate the extents of the window */
       if (info->clip_changed)
@@ -1765,6 +1854,12 @@ free_win (MetaCompWindow *cw,
       cw->picture = None;
     }
 
+  if (cw->mask)
+    {
+      XRenderFreePicture (xdisplay, cw->mask);
+      cw->mask = None;
+    }
+
   if (cw->shadow)
     {
       XRenderFreePicture (xdisplay, cw->shadow);
@@ -2271,6 +2366,12 @@ resize_win (MetaCompWindow *cw,
           cw->picture = None;
         }
 
+      if (cw->mask)
+        {
+          XRenderFreePicture (xdisplay, cw->mask);
+          cw->mask = None;
+        }
+
       if (cw->shadow)
         {
           XRenderFreePicture (xdisplay, cw->shadow);
@@ -3144,6 +3245,12 @@ xrender_set_active_window (MetaCompositor *compositor,
 
       if (old_focus->attrs.map_state == IsViewable)
         {
+          if (old_focus->mask)
+            {
+              XRenderFreePicture (xdisplay, old_focus->mask);
+              old_focus->mask = None;
+            }
+
           if (old_focus->shadow)
             {
               XRenderFreePicture (xdisplay, old_focus->shadow);
@@ -3188,6 +3295,12 @@ xrender_set_active_window (MetaCompositor *compositor,
       determine_mode (display, screen, new_focus);
       new_focus->needs_shadow = window_has_shadow (new_focus);
 
+      if (new_focus->mask)
+        {
+          XRenderFreePicture (xdisplay, new_focus->mask);
+          new_focus->mask = None;
+        }
+
       if (new_focus->shadow)
         {
           XRenderFreePicture (xdisplay, new_focus->shadow);
diff --git a/src/ui/frames.c b/src/ui/frames.c
index 9219101..ad6a8e7 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -746,37 +746,6 @@ meta_frames_get_borders (MetaFrames       *frames,
 }
 
 static void
-meta_ui_frame_get_corner_radiuses (MetaFrames  *frames,
-                                   MetaUIFrame *frame,
-                                   float       *top_left,
-                                   float       *top_right,
-                                   float       *bottom_left,
-                                   float       *bottom_right)
-{
-  MetaFrameGeometry fgeom;
-
-  meta_frames_calc_geometry (frames, frame, &fgeom);
-
-  /* For compatibility with the code in get_visible_rect(), there's
-   * a mysterious sqrt() added to the corner radiuses:
-   *
-   * const float radius = sqrt(corner) + corner;
-   *
-   * It's unclear why the radius is calculated like this, but we
-   * need to be consistent with it.
-   */
-
-  if (top_left)
-    *top_left = fgeom.top_left_corner_rounded_radius + sqrt(fgeom.top_left_corner_rounded_radius);
-  if (top_right)
-    *top_right = fgeom.top_right_corner_rounded_radius + sqrt(fgeom.top_right_corner_rounded_radius);
-  if (bottom_left)
-    *bottom_left = fgeom.bottom_left_corner_rounded_radius + sqrt(fgeom.bottom_left_corner_rounded_radius);
-  if (bottom_right)
-    *bottom_right = fgeom.bottom_right_corner_rounded_radius + 
sqrt(fgeom.bottom_right_corner_rounded_radius);
-}
-
-static void
 apply_cairo_region_to_window (Display        *display,
                               Window          xwindow,
                               cairo_region_t *region,
@@ -2414,6 +2383,23 @@ cached_pixels_draw (CachedPixels   *pixels,
     }
 }
 
+void
+meta_frames_get_mask (MetaFrames *frames,
+                      Window      xwindow,
+                      guint       width,
+                      guint       height,
+                      cairo_t    *cr)
+{
+  MetaUIFrame *frame;
+
+  frame = meta_frames_lookup_window (frames, xwindow);
+
+  if (frame == NULL)
+    return;
+
+  meta_frames_paint (frames, frame, cr);
+}
+
 /* XXX -- this is disgusting. Find a better approach here.
  * Use multiple widgets? */
 static MetaUIFrame *
@@ -2431,102 +2417,6 @@ find_frame_to_draw (MetaFrames *frames,
   return NULL;
 }
 
-#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)


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