diff --git a/src/backend/backend.c b/src/backend/backend.c index 59ddcaf2a0..b263082d4d 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -240,7 +240,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { auto real_win_mode = w->mode; coord_t window_coord = {.x = w->g.x, .y = w->g.y}; - if (w->blur_background && + if (w->blur_background && !w->blur_foreground && (ps->o.force_win_blend || real_win_mode == WMODE_TRANS || (ps->o.blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) { // Minimize the region we try to blur, if the window @@ -433,7 +433,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { } // Draw window on target - if (w->frame_opacity == 1) { + if (!w->blur_foreground && w->frame_opacity == 1) { ps->backend_data->ops->compose(ps->backend_data, w->win_image, window_coord, NULL, window_coord, ®_paint_in_bound, ®_visible); @@ -480,6 +480,14 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) { ps->backend_data->ops->release_image(ps->backend_data, new_img); pixman_region32_fini(®_visible_local); pixman_region32_fini(®_bound_local); + + // Blur window + if (w->blur_foreground) { + ps->backend_data->ops->blur( + ps->backend_data, ps->o.inactive_blur_opacity, + ps->backend_blur_fgcontext, w->mask_image, window_coord, + ®_paint_in_bound, ®_visible); + } } skip: pixman_region32_fini(®_bound); diff --git a/src/common.h b/src/common.h index 8f307dc9fd..b9c93557a1 100644 --- a/src/common.h +++ b/src/common.h @@ -173,6 +173,7 @@ typedef struct session { backend_t *backend_data; /// backend blur context void *backend_blur_context; + void *backend_blur_fgcontext; /// graphic drivers used enum driver drivers; /// file watch handle diff --git a/src/config.c b/src/config.c index 1013d128fa..d84f2f8226 100644 --- a/src/config.c +++ b/src/config.c @@ -764,6 +764,11 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .no_fading_destroyed_argb = false, .fade_blacklist = NULL, + .inactive_blur = false, + .inactive_blur_list = NULL, + .inactive_blur_opacity = 1.0, + .inactive_dim = 0.0, + .inactive_dim_fixed = false, .inactive_opacity = 1.0, .inactive_opacity_override = false, .active_opacity = 1.0, @@ -781,8 +786,6 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable, .blur_kernel_count = 0, .window_shader_fg = NULL, .window_shader_fg_rules = NULL, - .inactive_dim = 0.0, - .inactive_dim_fixed = false, .invert_color_list = NULL, .opacity_rules = NULL, .max_brightness = 1.0, diff --git a/src/config.h b/src/config.h index 5ce3ba9635..424009b04c 100644 --- a/src/config.h +++ b/src/config.h @@ -213,6 +213,12 @@ typedef struct options { char *window_shader_fg; /// Rules to change custom fragment shader for painting windows. c2_lptr_t *window_shader_fg_rules; + /// Whether to blur inactive window foregrounds + bool inactive_blur; + // Opacity of inactive foreground blurs + double inactive_blur_opacity; + /// List of windows that should be blurred out when inactive. + c2_lptr_t *inactive_blur_list; /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable. double inactive_dim; /// Whether to use fixed inactive dim opacity, instead of deciding diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 63f05412bf..fa337173de 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -541,6 +541,11 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad goto err; } } + // --inactive-blur + if (lcfg_lookup_bool(&cfg, "inactive-blur", &opt->inactive_blur)) { + parse_cfg_condlst(&cfg, &opt->inactive_blur_list, "inactive-blur-include"); + config_lookup_float(&cfg, "inactive-blur-opacity", &opt->inactive_blur_opacity); + } // --resize-damage config_lookup_int(&cfg, "resize-damage", &opt->resize_damage); // --glx-no-stencil diff --git a/src/options.c b/src/options.c index 9d500b8e65..b11fc798c4 100644 --- a/src/options.c +++ b/src/options.c @@ -57,6 +57,11 @@ static const struct picom_option picom_options[] = { {"shadow-blue" , required_argument, 259, NULL , "Blue color value of shadow (0.0 - 1.0, defaults to 0)."}, {"inactive-opacity-override" , no_argument , 260, NULL , "Inactive opacity set by -i overrides value of _NET_WM_WINDOW_OPACITY."}, {"inactive-dim" , required_argument, 261, NULL , "Dim inactive windows. (0.0 - 1.0, defaults to 0)"}, + {"inactive-blur" , no_argument , 341, NULL , "Blur the foreground of inactive windows."}, + {"inactive-blur-include" , required_argument, 342, NULL , "Conditions for windows that should be fully blurred when inactive." + "When --inactive-blur is enabled without an --inactive-blur-include" + "condition, the foreground of ALL inactive windows will be blurred."}, + {"inactive-blur-opacity" , required_argument, 343, NULL , "Set the opacity of inactive foreground blurs"}, {"mark-wmwin-focused" , no_argument , 262, NULL , "Try to detect WM windows and mark them as active."}, {"shadow-exclude" , required_argument, 263, NULL , "Exclude conditions for shadows."}, {"mark-ovredir-focused" , no_argument , 264, NULL , "Mark windows that have no WM frame as active."}, @@ -738,6 +743,18 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, // --dithered-present opt->dithered_present = true; break; + case 341: + // --inactive-blur + opt->inactive_blur = true; + break; + case 342: + // --inactive-blur-include + condlst_add(&opt->inactive_blur_list, optarg); + break; + case 343: + // --inactive-blur-opacity + opt->inactive_blur_opacity = normalize_d(atof(optarg)); + break; P_CASEBOOL(733, legacy_backends); P_CASEBOOL(800, monitor_repaint); case 801: diff --git a/src/picom.c b/src/picom.c index 8a7a967039..b9708df32b 100644 --- a/src/picom.c +++ b/src/picom.c @@ -507,6 +507,17 @@ static bool initialize_backend(session_t *ps) { goto err; } + if (ps->o.inactive_blur && ps->o.blur_method == BLUR_METHOD_NONE) { + log_info("No blur method set, defaulting to box for inactive blur"); + struct box_blur_args bargs; + bargs.size = 3; + void *args = (void *)&bargs; + ps->backend_blur_fgcontext = ps->backend_data->ops->create_blur_context( + ps->backend_data, BLUR_METHOD_BOX, args); + } else if (ps->o.inactive_blur) { + ps->backend_blur_fgcontext = ps->backend_blur_context; + } + // Create shaders HASH_ITER2(ps->shaders, shader) { assert(shader->backend_shader == NULL); @@ -1940,6 +1951,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, c2_list_postprocess(ps, ps->o.shadow_clip_list) && c2_list_postprocess(ps, ps->o.fade_blacklist) && c2_list_postprocess(ps, ps->o.blur_background_blacklist) && + c2_list_postprocess(ps, ps->o.inactive_blur_list) && c2_list_postprocess(ps, ps->o.invert_color_list) && c2_list_postprocess(ps, ps->o.window_shader_fg_rules) && c2_list_postprocess(ps, ps->o.opacity_rules) && @@ -2319,6 +2331,7 @@ static void session_destroy(session_t *ps) { c2_list_free(&ps->o.shadow_clip_list, NULL); c2_list_free(&ps->o.fade_blacklist, NULL); c2_list_free(&ps->o.focus_blacklist, NULL); + c2_list_free(&ps->o.inactive_blur_list, free); c2_list_free(&ps->o.invert_color_list, NULL); c2_list_free(&ps->o.blur_background_blacklist, NULL); c2_list_free(&ps->o.opacity_rules, NULL); diff --git a/src/render.c b/src/render.c index afde7db82b..ac6cfc60bd 100644 --- a/src/render.c +++ b/src/render.c @@ -868,6 +868,8 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y static inline void win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t tgt_buffer, const region_t *reg_paint) { + assert(w->blur_foreground == false); + const int16_t x = w->g.x; const int16_t y = w->g.y; const auto wid = to_u16_checked(w->widthb); @@ -1157,7 +1159,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) { #endif // Blur window background - if (w->blur_background && + if (w->blur_background && !w->blur_foreground && (w->mode == WMODE_TRANS || (ps->o.blur_background_frame && w->mode == WMODE_FRAME_TRANS) || ps->o.force_win_blend)) { diff --git a/src/win.c b/src/win.c index a97733dbd4..76fb69ddc1 100644 --- a/src/win.c +++ b/src/win.c @@ -1080,6 +1080,16 @@ void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val) { } } +static void +win_set_blur_foreground(session_t *ps, struct managed_win *w, bool blur_foreground_new) { + if (w->blur_foreground == blur_foreground_new) + return; + + w->blur_foreground = blur_foreground_new; + + add_damage_from_win(ps, w); +} + static void win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new) { if (w->blur_background == blur_background_new) @@ -1106,6 +1116,22 @@ win_set_fg_shader(session_t *ps, struct managed_win *w, struct shader_info *shad add_damage_from_win(ps, w); } +/** + * Determine whether a window's foreground should be blurred + */ +static void win_determine_blur_foreground(session_t *ps, struct managed_win *w) { + log_debug("Determining blur-foreground of window %#010x (%s)", w->base.id, w->name); + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) { + return; + } + + bool blur_foreground_new = + ps->o.inactive_blur && !w->focused && + (!ps->o.inactive_blur_list || c2_match(ps, w, ps->o.inactive_blur_list, NULL)); + + win_set_blur_foreground(ps, w, blur_foreground_new); +} + /** * Determine if a window should have background blurred. */ @@ -1115,7 +1141,10 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w) return; } - bool blur_background_new = ps->o.blur_method != BLUR_METHOD_NONE; + bool blur_background_new = false; + if (!w->blur_foreground) { + blur_background_new = ps->o.blur_method != BLUR_METHOD_NONE; + } if (blur_background_new) { if (!ps->o.wintype_option[w->window_type].blur_background) { log_debug("Blur background disabled by wintypes"); @@ -1220,6 +1249,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) { win_determine_shadow(ps, w); win_determine_clip_shadow_above(ps, w); win_determine_invert_color(ps, w); + win_determine_blur_foreground(ps, w); win_determine_blur_background(ps, w); win_determine_rounded_corners(ps, w); win_determine_fg_shader(ps, w); diff --git a/src/win.h b/src/win.h index fe733408b5..c59f9a00af 100644 --- a/src/win.h +++ b/src/win.h @@ -277,6 +277,9 @@ struct managed_win { /// Whether to blur window background. bool blur_background; + /// Whether to blur window foreground. + bool blur_foreground; + /// The custom window shader to use when rendering. struct shader_info *fg_shader;