From 6d459badbcb6b31ae622df329fa663b5b3293f48 Mon Sep 17 00:00:00 2001 From: oofsauce Date: Wed, 29 Mar 2023 21:18:41 +0100 Subject: [PATCH] Add corner-radius-rules configuration option This option accepts a list of patterns and overrides the corner radii of matching windows Authored-by: oofsauce Signed-off-by: Yuxuan Shui --- man/picom.1.asciidoc | 3 +++ src/config.c | 23 ++++++++++++++--------- src/config.h | 4 +++- src/config_libconfig.c | 37 +++++++++++++++++++++++++++++++++---- src/options.c | 9 ++++++++- src/win.c | 19 +++++++++++++++---- 6 files changed, 76 insertions(+), 19 deletions(-) diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index e7a91315..0a2e3c31 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -103,6 +103,9 @@ OPTIONS *--corner-radius* 'VALUE':: Sets the radius of rounded window corners. When > 0, the compositor will round the corners of windows. Does not interact well with *--transparent-clipping*. (defaults to 0). +*--corner-radius-rules* 'RADIUS':'CONDITION':: + Specify a list of corner radius rules. Overrides the corner radii of matching windows. This option takes precedence over the *--rounded-corners-exclude* option, and also overrides the default exclusion of fullscreen windows. The condition has the same format as *--opacity-rule*. + *--rounded-corners-exclude* 'CONDITION':: Exclude conditions for rounded corners. diff --git a/src/config.c b/src/config.c index dd231470..1013d128 100644 --- a/src/config.c +++ b/src/config.c @@ -509,32 +509,37 @@ parse_geometry_end: } /** - * Parse a list of opacity rules. + * Parse a list of window rules, prefixed with a number, separated by a ':' */ -bool parse_rule_opacity(c2_lptr_t **res, const char *src) { - // Find opacity value +bool parse_numeric_window_rule(c2_lptr_t **res, const char *src, long min, long max) { + if (!src) { + return false; + } + + // Find numeric value char *endptr = NULL; long val = strtol(src, &endptr, 0); if (!endptr || endptr == src) { - log_error("No opacity specified: %s", src); + log_error("No number specified: %s", src); return false; } - if (val > 100 || val < 0) { - log_error("Opacity %ld invalid: %s", val, src); + + if (val < min || val > max) { + log_error("Number not in range (%ld <= n <= %ld): %s", min, max, src); return false; } // Skip over spaces - while (*endptr && isspace((unsigned char)*endptr)) + while (*endptr && isspace((unsigned char)*endptr)) { ++endptr; + } if (':' != *endptr) { - log_error("Opacity terminator not found: %s", src); + log_error("Number separator (':') not found: %s", src); return false; } ++endptr; // Parse pattern - // I hope 1-100 is acceptable for (void *) return c2_parse(res, endptr, (void *)val); } diff --git a/src/config.h b/src/config.h index 632800c3..5ce3ba96 100644 --- a/src/config.h +++ b/src/config.h @@ -228,6 +228,8 @@ typedef struct options { int corner_radius; /// Rounded corners blacklist. A linked list of conditions. c2_lptr_t *rounded_corners_blacklist; + /// Rounded corner rules. A linked list of conditions. + c2_lptr_t *corner_radius_rules; // === Focus related === /// Whether to try to detect WM windows and mark them as focused. @@ -266,7 +268,7 @@ bool must_use parse_long(const char *, long *); bool must_use parse_int(const char *, int *); struct conv **must_use parse_blur_kern_lst(const char *, bool *hasneg, int *count); bool must_use parse_geometry(session_t *, const char *, region_t *); -bool must_use parse_rule_opacity(c2_lptr_t **, const char *); +bool must_use parse_numeric_window_rule(c2_lptr_t **, const char *, long, long); bool must_use parse_rule_window_shader(c2_lptr_t **, const char *, const char *); char *must_use locate_auxiliary_file(const char *scope, const char *path, const char *include_dir); diff --git a/src/config_libconfig.c b/src/config_libconfig.c index 589e139b..63f05412 100644 --- a/src/config_libconfig.c +++ b/src/config_libconfig.c @@ -135,6 +135,32 @@ void parse_cfg_condlst(const config_t *pcfg, c2_lptr_t **pcondlst, const char *n } } +/** + * Parse a window corner radius rule list in configuration file. + */ +static inline void +parse_cfg_condlst_corner(options_t *opt, const config_t *pcfg, const char *name) { + config_setting_t *setting = config_lookup(pcfg, name); + if (setting) { + // Parse an array of options + if (config_setting_is_array(setting)) { + int i = config_setting_length(setting); + while (i--) + if (!parse_numeric_window_rule( + &opt->corner_radius_rules, + config_setting_get_string_elem(setting, i), 0, INT_MAX)) + exit(1); + } + // Treat it as a single pattern if it's a string + else if (config_setting_type(setting) == CONFIG_TYPE_STRING) { + if (!parse_numeric_window_rule(&opt->corner_radius_rules, + config_setting_get_string(setting), + 0, INT_MAX)) + exit(1); + } + } +} + /** * Parse an opacity rule list in configuration file. */ @@ -146,15 +172,15 @@ parse_cfg_condlst_opct(options_t *opt, const config_t *pcfg, const char *name) { if (config_setting_is_array(setting)) { int i = config_setting_length(setting); while (i--) - if (!parse_rule_opacity( + if (!parse_numeric_window_rule( &opt->opacity_rules, - config_setting_get_string_elem(setting, i))) + config_setting_get_string_elem(setting, i), 0, 100)) exit(1); } // Treat it as a single pattern if it's a string else if (config_setting_type(setting) == CONFIG_TYPE_STRING) { - if (!parse_rule_opacity(&opt->opacity_rules, - config_setting_get_string(setting))) + if (!parse_numeric_window_rule( + &opt->opacity_rules, config_setting_get_string(setting), 0, 100)) exit(1); } } @@ -334,6 +360,9 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad config_lookup_int(&cfg, "corner-radius", &opt->corner_radius); // --rounded-corners-exclude parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude"); + // --corner-radius-rules + parse_cfg_condlst_corner(opt, &cfg, "corner-radius-rules"); + // -e (frame_opacity) config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity); // -c (shadow_enable) diff --git a/src/options.c b/src/options.c index d2020c6a..9d500b8e 100644 --- a/src/options.c +++ b/src/options.c @@ -161,6 +161,7 @@ static const struct picom_option picom_options[] = { {"corner-radius" , required_argument, 333, NULL , "Sets the radius of rounded window corners. When > 0, the compositor will " "round the corners of windows. (defaults to 0)."}, {"rounded-corners-exclude" , required_argument, 334, "COND" , "Exclude conditions for rounded corners."}, + {"corner-radius-rules" , required_argument, 340, "RADIUS:COND" , "Window rules for specific rounded corner radii."}, {"clip-shadow-above" , required_argument, 335, NULL , "Specify a list of conditions of windows to not paint a shadow over, such " "as a dock window."}, {"window-shader-fg" , required_argument, 336, "PATH" , "Specify GLSL fragment shader path for rendering window contents. Does not" @@ -174,6 +175,7 @@ static const struct picom_option picom_options[] = { {"dithered-present" , no_argument , 339, NULL , "Use higher precision during rendering, and apply dither when presenting the " "rendered screen. Reduces banding artifacts, but might cause performance " "degradation. Only works with OpenGL."}, + // 340 is corner-radius-rules {"legacy-backends" , no_argument , 733, NULL , "Use deprecated version of the backends."}, {"monitor-repaint" , no_argument , 800, NULL , "Highlight the updated area of the screen. For debugging."}, {"diagnostics" , no_argument , 801, NULL , "Print diagnostic information"}, @@ -619,7 +621,7 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, break; case 304: // --opacity-rule - if (!parse_rule_opacity(&opt->opacity_rules, optarg)) + if (!parse_numeric_window_rule(&opt->opacity_rules, optarg, 0, 100)) exit(1); break; case 305: @@ -723,6 +725,11 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable, // --rounded-corners-exclude condlst_add(&opt->rounded_corners_blacklist, optarg); break; + case 340: + // --corner-radius-rules + if (!parse_numeric_window_rule(&opt->corner_radius_rules, optarg, 0, INT_MAX)) + exit(1); + break; case 335: // --clip-shadow-above condlst_add(&opt->shadow_clip_list, optarg); diff --git a/src/win.c b/src/win.c index a52b4e1a..a97733db 100644 --- a/src/win.c +++ b/src/win.c @@ -1139,13 +1139,24 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) return; } - // Don't round full screen windows & excluded windows - if ((w && win_is_fullscreen(ps, w)) || - c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) { + void *radius_override = NULL; + if (c2_match(ps, w, ps->o.corner_radius_rules, &radius_override)) { + log_debug("Matched corner rule! %d", w->corner_radius); + } + + // Don't round full screen windows & excluded windows, + // unless we find a corner override in corner_radius_rules + if (!radius_override && ((w && win_is_fullscreen(ps, w)) || + c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL))) { w->corner_radius = 0; log_debug("Not rounding corners for window %#010x", w->base.id); } else { - w->corner_radius = ps->o.corner_radius; + if (radius_override) { + w->corner_radius = (int)(long)radius_override; + } else { + w->corner_radius = ps->o.corner_radius; + } + log_debug("Rounding corners for window %#010x", w->base.id); // Initialize the border color to an invalid value w->border_col[0] = w->border_col[1] = w->border_col[2] =