Add corner-radius-rules configuration option

This option accepts a list of patterns and overrides the corner radii of
matching windows

Authored-by: oofsauce <alanpanayotov@gmail.com>
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
oofsauce 2023-03-29 21:18:41 +01:00 committed by Yuxuan Shui
parent cee1287562
commit 6d459badbc
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
6 changed files with 76 additions and 19 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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] =