From 1bfe21efb59184d73ce524849cef47a518167fed Mon Sep 17 00:00:00 2001 From: Richard Grenville Date: Sat, 15 Dec 2012 20:07:45 +0800 Subject: [PATCH] Improvement: Dynamic blur strength & improved frame blur performance - Remove the region expansion design in win_blur_background(). I must be sleep-walking when I wrote that! - Improve performance of blurring when a window is opaque but its frame is transparent. - Adjust blur strength according to window opacity. --blur-background-fixed restores the old behavior. - Add "use_offset" parameter to a few functions for convenience. Code clean-up. --- compton.sample.conf | 1 + src/compton.c | 99 ++++++++++++++++++++++++++++----------------- src/compton.h | 11 ++++- 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/compton.sample.conf b/compton.sample.conf index 0f2e4fb..f0fff0a 100644 --- a/compton.sample.conf +++ b/compton.sample.conf @@ -24,6 +24,7 @@ alpha-step = 0.06; # inactive-dim-fixed = true; # blur-background = true; # blur-background-frame = true; +blur-background-fixed = false; # Fading fading = true; diff --git a/src/compton.c b/src/compton.c index ceba178..eff195f 100644 --- a/src/compton.c +++ b/src/compton.c @@ -545,7 +545,7 @@ win_rounded_corners(session_t *ps, win *w) { // Fetch its bounding region if (!w->border_size) - w->border_size = border_size(ps, w); + w->border_size = border_size(ps, w, true); // Quit if border_size() returns None if (!w->border_size) @@ -991,11 +991,11 @@ paint_root(session_t *ps, Picture tgt_buffer) { * Get a rectangular region a window occupies, excluding shadow. */ static XserverRegion -win_get_region(session_t *ps, win *w) { +win_get_region(session_t *ps, win *w, bool use_offset) { XRectangle r; - r.x = w->a.x; - r.y = w->a.y; + r.x = (use_offset ? w->a.x: 0); + r.y = (use_offset ? w->a.y: 0); r.width = w->widthb; r.height = w->heightb; @@ -1006,11 +1006,11 @@ win_get_region(session_t *ps, win *w) { * Get a rectangular region a window occupies, excluding frame and shadow. */ static XserverRegion -win_get_region_noframe(session_t *ps, win *w) { +win_get_region_noframe(session_t *ps, win *w, bool use_offset) { XRectangle r; - r.x = w->a.x + w->a.border_width + w->left_width; - r.y = w->a.y + w->a.border_width + w->top_width; + r.x = (use_offset ? w->a.x: 0) + w->a.border_width + w->left_width; + r.y = (use_offset ? w->a.y: 0) + w->a.border_width + w->top_width; r.width = max_i(w->a.width - w->left_width - w->right_width, 0); r.height = max_i(w->a.height - w->top_width - w->bottom_width, 0); @@ -1069,9 +1069,9 @@ win_extents(session_t *ps, win *w) { * Retrieve the bounding shape of a window. */ static XserverRegion -border_size(session_t *ps, win *w) { +border_size(session_t *ps, win *w, bool use_offset) { // Start with the window rectangular region - XserverRegion fin = win_get_region(ps, w); + XserverRegion fin = win_get_region(ps, w, use_offset); // Only request for a bounding region if the window is shaped if (w->bounding_shaped) { @@ -1089,10 +1089,12 @@ border_size(session_t *ps, win *w) { if (!border) return fin; - // Translate the region to the correct place - XFixesTranslateRegion(ps->dpy, border, - w->a.x + w->a.border_width, - w->a.y + w->a.border_width); + if (use_offset) { + // Translate the region to the correct place + XFixesTranslateRegion(ps->dpy, border, + w->a.x + w->a.border_width, + w->a.y + w->a.border_width); + } // Intersect the bounding region we got with the window rectangle, to // make sure the bounding region is not bigger than the window @@ -1249,7 +1251,7 @@ paint_preprocess(session_t *ps, win *list) { if (to_paint) { // Fetch bounding region if (!w->border_size) { - w->border_size = border_size(ps, w); + w->border_size = border_size(ps, w, true); } // Fetch window extents @@ -1326,10 +1328,10 @@ paint_preprocess(session_t *ps, win *list) { if (w->border_size) w->reg_ignore = copy_region(ps, w->border_size); else - w->reg_ignore = win_get_region(ps, w); + w->reg_ignore = win_get_region(ps, w, true); } else { - w->reg_ignore = win_get_region_noframe(ps, w); + w->reg_ignore = win_get_region_noframe(ps, w, true); if (w->border_size) XFixesIntersectRegion(ps->dpy, w->reg_ignore, w->reg_ignore, w->border_size); @@ -1428,20 +1430,20 @@ win_paint_shadow(session_t *ps, win *w, Picture tgt_buffer) { static inline void win_blur_background(session_t *ps, win *w, Picture tgt_buffer, XserverRegion reg_paint) { + const static int convolution_blur_size = 3; // Convolution filter parameter (box blur) // gaussian or binomial filters are definitely superior, yet looks // like they aren't supported as of xorg-server-1.13.0 - const static XFixed convolution_blur[] = { + XFixed convolution_blur[] = { // Must convert to XFixed with XDoubleToFixed() // Matrix size - XDoubleToFixed(3), XDoubleToFixed(3), + XDoubleToFixed(convolution_blur_size), + XDoubleToFixed(convolution_blur_size), // Matrix XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), XDoubleToFixed(1), }; - // Extra pixels we have to get for the blur to work correctly. - const static int expand = 1; Pixmap tmp_pixmap = None; Picture tmp_picture = None; @@ -1451,15 +1453,9 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer, int wid = w->widthb; int hei = w->heightb; - int xe = x - expand; - int ye = y - expand; - int wide = wid + expand * 2; - int heie = hei + expand * 2; - // Directly copying from tgt_buffer does not work, so we create a - // Picture in the middle. We expand the region slightly, to make sure - // the blur on border pixels work correctly. - tmp_pixmap = XCreatePixmap(ps->dpy, ps->root, wide, heie, ps->depth); + // Picture in the middle. + tmp_pixmap = XCreatePixmap(ps->dpy, ps->root, wid, hei, ps->depth); if (!tmp_pixmap) goto win_blur_background_err; @@ -1468,14 +1464,31 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer, if (!tmp_picture) goto win_blur_background_err; - // Copy the content to tmp_picture, then copy back. - // We lift the PictureClipRegion here, to get the expanded pixels. - XFixesSetPictureClipRegion(ps->dpy, tgt_buffer, 0, 0, None); - XRenderComposite(ps->dpy, PictOpSrc, tgt_buffer, None, tmp_picture, xe, ye, 0, 0, 0, 0, wide, heie); - XFixesSetPictureClipRegion(ps->dpy, tgt_buffer, 0, 0, reg_paint); - XRenderSetPictureFilter(ps->dpy, tmp_picture, XRFILTER_CONVOLUTION, (XFixed *) convolution_blur, sizeof(convolution_blur) / sizeof(XFixed)); - XRenderComposite(ps->dpy, PictOpSrc, tmp_picture, None, tgt_buffer, expand, expand, 0, 0, x, y, wid, hei); - xrfilter_reset(ps, tmp_picture); + // Adjust blur strength according to window opacity, to make it appear + // better during fading + if (!ps->o.blur_background_fixed) { + double pct = 1.0 - get_opacity_percent(w) * (1.0 - 1.0 / 9.0); + convolution_blur[2 + convolution_blur_size + ((convolution_blur_size - 1) / 2)] = XDoubleToFixed(pct * 8.0 / (1.1 - pct)); + } + + // Minimize the region we try to blur, if the window itself is not + // opaque, only the frame is. + if (WINDOW_SOLID == w->mode && w->frame_opacity) { + XserverRegion reg_all = border_size(ps, w, false); + XserverRegion reg_noframe = win_get_region_noframe(ps, w, false); + XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe); + XFixesSetPictureClipRegion(ps->dpy, tmp_picture, reg_noframe, 0, 0); + free_region(ps, ®_all); + free_region(ps, ®_noframe); + } + + // Copy the content to tmp_picture, then copy back. The filter must + // be applied on tgt_buffer, to get the nearby pixels outside the + // window. + XRenderSetPictureFilter(ps->dpy, tgt_buffer, XRFILTER_CONVOLUTION, (XFixed *) convolution_blur, sizeof(convolution_blur) / sizeof(XFixed)); + XRenderComposite(ps->dpy, PictOpSrc, tgt_buffer, None, tmp_picture, x, y, 0, 0, 0, 0, wid, hei); + xrfilter_reset(ps, tgt_buffer); + XRenderComposite(ps->dpy, PictOpSrc, tmp_picture, None, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); win_blur_background_err: free_pixmap(ps, &tmp_pixmap); @@ -3492,7 +3505,7 @@ ev_shape_notify(session_t *ps, XShapeEvent *ev) { // Mark the old border_size as damaged add_damage(ps, w->border_size); - w->border_size = border_size(ps, w); + w->border_size = border_size(ps, w, true); // Mark the new border_size as damaged add_damage(ps, copy_region(ps, w->border_size)); @@ -3763,6 +3776,9 @@ usage(void) { " Blur background of windows when the window frame is not opaque.\n" " Implies --blur-background. Bad in performance. The switch name\n" " may change.\n" + "--blur-background-fixed\n" + " Use fixed blur strength instead of adjusting according to window\n" + " opacity.\n" "\n" "Format of a condition:\n" "\n" @@ -4174,6 +4190,9 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) { // --blur-background-frame lcfg_lookup_bool(&cfg, "blur-background-frame", &ps->o.blur_background_frame); + // --blur-background-fixed + lcfg_lookup_bool(&cfg, "blur-background-fixed", + &ps->o.blur_background_fixed); // Wintype settings { wintype_t i; @@ -4235,6 +4254,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) { { "detect-client-leader", no_argument, NULL, 282 }, { "blur-background", no_argument, NULL, 283 }, { "blur-background-frame", no_argument, NULL, 284 }, + { "blur-background-fixed", no_argument, NULL, 285 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -4460,6 +4480,10 @@ get_cfg(session_t *ps, int argc, char *const *argv) { // --blur-background-frame ps->o.blur_background_frame = true; break; + case 285: + // --blur-background-fixed + ps->o.blur_background_fixed = true; + break; default: usage(); } @@ -5029,6 +5053,7 @@ session_init(session_t *ps_old, int argc, char **argv) { .alpha_step = 0.03, .blur_background = false, .blur_background_frame = false, + .blur_background_fixed = false, .wintype_focus = { false }, .use_ewmh_active_win = false, diff --git a/src/compton.h b/src/compton.h index 8aecaa7..66ed396 100644 --- a/src/compton.h +++ b/src/compton.h @@ -335,6 +335,9 @@ typedef struct { /// Whether to blur background when the window frame is not opaque. /// Implies blur_background. bool blur_background_frame; + /// Whether to use fixed blur strength instead of adjusting according + /// to window opacity. + bool blur_background_fixed; // === Focus related === /// Consider windows of specific types to be always focused. @@ -1493,11 +1496,17 @@ root_tile_f(session_t *ps); static void paint_root(session_t *ps, Picture tgt_buffer); +static XserverRegion +win_get_region(session_t *ps, win *w, bool use_offset); + +static XserverRegion +win_get_region_noframe(session_t *ps, win *w, bool use_offset); + static XserverRegion win_extents(session_t *ps, win *w); static XserverRegion -border_size(session_t *ps, win *w); +border_size(session_t *ps, win *w, bool use_offset); static Window find_client_win(session_t *ps, Window w);