diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compositor/compositor-xrender.c | 115 | ||||
-rw-r--r-- | src/ui/frames.c | 144 |
2 files changed, 132 insertions, 127 deletions
diff --git a/src/compositor/compositor-xrender.c b/src/compositor/compositor-xrender.c index bc697f6c..3be9a340 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; @@ -1291,6 +1293,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, @@ -1398,6 +1486,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) @@ -1759,6 +1850,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); @@ -2265,6 +2362,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); @@ -3138,6 +3241,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); @@ -3182,6 +3291,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 92191017..ad6a8e71 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) |