summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberts Muktupāvels <alberts.muktupavels@gmail.com>2016-04-14 19:53:21 +0300
committerAlberts Muktupāvels <alberts.muktupavels@gmail.com>2016-04-14 20:30:30 +0300
commit933dbae63c717fa9a7d60754640c6e21e60ce98b (patch)
tree664e4303f039664b1bfff023eb2b25ab06e37e21
parent74f376458394a929a21f8db268de2c7da208ff35 (diff)
downloadmetacity-933dbae63c717fa9a7d60754640c6e21e60ce98b.tar.gz
compositor: add window mask
-rw-r--r--src/compositor/compositor-xrender.c115
-rw-r--r--src/ui/frames.c144
2 files changed, 132 insertions, 127 deletions
diff --git a/src/compositor/compositor-xrender.c b/src/compositor/compositor-xrender.c
index 6baa01e3..8f325146 100644
--- a/src/compositor/compositor-xrender.c
+++ b/src/compositor/compositor-xrender.c
@@ -33,6 +33,7 @@
#include <gdk/gdk.h>
#include <cairo/cairo-xlib.h>
+#include <cairo/cairo-xlib-xrender.h>
#include "display.h"
#include "screen.h"
@@ -167,6 +168,7 @@ typedef struct _MetaCompWindow
Damage damage;
Picture picture;
+ Picture mask;
Picture alpha_pict;
gboolean needs_shadow;
@@ -1290,6 +1292,92 @@ get_window_picture (MetaCompWindow *cw)
return None;
}
+static Picture
+get_window_mask (MetaCompWindow *cw)
+{
+ MetaFrame *frame;
+ MetaScreen *screen;
+ 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;
+
+ screen = cw->screen;
+ display = meta_screen_get_display (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,
@@ -1397,6 +1485,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)
@@ -1758,6 +1849,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);
@@ -2264,6 +2361,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);
@@ -3137,6 +3240,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);
@@ -3181,6 +3290,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 68dfc8bf..4bc4def0 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -810,37 +810,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,
@@ -2477,6 +2446,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 *
@@ -2494,102 +2480,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)