Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: try to convert legacy parameters to rules #1327

Open
wants to merge 9 commits into
base: next
Choose a base branch
from
4 changes: 2 additions & 2 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ bool load_plugin(const char *name, const char *include_dir) {
return handle != NULL;
}

bool parse_config(options_t *opt, const char *config_file) {
bool parse_config(options_t *opt, const char *config_file, config_t *release_cfg) {
// clang-format off
*opt = (struct options){
.glx_no_stencil = false,
Expand Down Expand Up @@ -739,5 +739,5 @@ bool parse_config(options_t *opt, const char *config_file) {
list_init_head(&opt->rules);

opt->all_scripts = dynarr_new(struct script *, 4);
return parse_config_libconfig(opt, config_file);
return parse_config_libconfig(opt, config_file, release_cfg);
}
17 changes: 15 additions & 2 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ typedef struct options {
switch_t stoppaint_force;
/// Whether to enable D-Bus support.
bool dbus;
/// Dump configuration file to stdout.
bool dump_config;
/// Path to log file.
char *logpath;
/// Number of cycles to paint in benchmark mode. 0 for disabled.
Expand Down Expand Up @@ -426,6 +428,17 @@ typedef struct options {
bool has_both_style_of_rules;
} options_t;

// compatibility of *-exclude parameters with rules
typedef struct rule_replacement {
const char *exclude;
const char *parameter;
int type;
union {
bool boolean;
double floating;
} value;
} rule_replacement_t;

bool load_plugin(const char *name, const char *include_dir);
static inline void record_problematic_option(struct options *opt, const char *name) {
struct option_name *record = calloc(1, sizeof(*record));
Expand Down Expand Up @@ -469,13 +482,13 @@ char **xdg_config_dirs(void);
/// Parse a configuration file from default location.
///
/// @return if config is successfully parsed.
bool parse_config_libconfig(options_t *, const char *config_file);
bool parse_config_libconfig(options_t *, const char *config_file, config_t *release_cfg);

/// Parse a configuration file is that is enabled, also initialize the winopt_mask with
/// default values
/// Outputs and returns:
/// same as parse_config_libconfig
bool parse_config(options_t *, const char *config_file);
bool parse_config(options_t *, const char *config_file, config_t *release_cfg);

/**
* Parse a VSync option argument.
Expand Down
129 changes: 117 additions & 12 deletions src/config_libconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,103 @@ FILE *open_config_file(const char *cpath, char **ppath) {
return NULL;
}

/**
* Convert legacy *-exclude parameters into rules.
*
* For example:
* shadow-exclude = [
* "name = 'Program'"
* ];
*
* will be added to rules as entry:
*
* { match = "name = 'Program'", shadow = false; }
*/
void create_rules_compat(const config_t *pcfg, config_setting_t *rules_setting,
const rule_replacement_t *replacement) {
config_setting_t *setting = config_lookup(pcfg, replacement->exclude);
if (setting == NULL) {
return;
}

if (config_setting_is_array(setting)) {
int len = config_setting_length(setting);

if (len > 0) {
log_warn("Trying to convert parameters of \"%s\" into rules.",
replacement->exclude);
}

for (int i = 0; i < len; i++) {
auto rule =
config_setting_add(rules_setting, NULL, CONFIG_TYPE_GROUP);
auto match = config_setting_add(rule, "match", CONFIG_TYPE_STRING);
config_setting_set_string(
match, config_setting_get_string_elem(setting, i));
auto param = config_setting_add(rule, replacement->parameter,
replacement->type);
if (replacement->type == CONFIG_TYPE_BOOL) {
config_setting_set_bool(param, replacement->value.boolean);
} else if (replacement->type == CONFIG_TYPE_FLOAT) {
config_setting_set_float(param, replacement->value.floating);
}
}
} else if (config_setting_is_group(setting) &&
!strcmp(config_setting_name(setting), "wintypes")) {
int len = config_setting_length(setting);

if (len > 0) {
log_warn("Trying to convert wintypes into rules.");
}

for (unsigned i = 0; i < (unsigned)len; i++) {
auto wintype = config_setting_get_elem(setting, i);

auto rule =
config_setting_add(rules_setting, NULL, CONFIG_TYPE_GROUP);
auto match = config_setting_add(rule, "match", CONFIG_TYPE_STRING);
char *match_str;
asprintf(&match_str, "window_type = '%s'",
config_setting_name(wintype));
config_setting_set_string(match, match_str);
free(match_str);

for (unsigned j = 0; j < (unsigned)config_setting_length(wintype); j++) {
auto param = config_setting_get_elem(wintype, j);
const char *param_name = config_setting_name(param);

if (!strcmp(param_name, "redir-ignore")) {
param_name = "unredir";
} else if (!strcmp(param_name, "focus")) {
log_warn("Rules have no equevalent for wintypes' "
"\"focus\" parameter.");
continue;
}

auto new_param = config_setting_add(
rule, param_name, config_setting_type(param));

if (config_setting_type(param) == CONFIG_TYPE_BOOL) {
bool val = config_setting_get_bool(param);

if (!strcmp(param_name, "unredir")) {
val = !val;
}

config_setting_set_bool(new_param, val);
} else if (config_setting_type(param) == CONFIG_TYPE_FLOAT) {
config_setting_set_float(
new_param, config_setting_get_float(param));
} else {
log_warn("Data type %d is not yet implemented "
"for converting wintypes!",
config_setting_type(param));
}
}
}
}
}

/**
* Parse a condition list in configuration file.
*/
Expand Down Expand Up @@ -668,7 +765,8 @@ resolve_include(config_t *cfg, const char *include_dir, const char *path, const
return ret;
}

bool parse_config_libconfig(options_t *opt, const char *config_file) { /*NOLINT(readability-function-cognitive-complexity)*/
bool parse_config_libconfig(options_t *opt, const char *config_file,
config_t *release_cfg) { /*NOLINT(readability-function-cognitive-complexity)*/
char *path = NULL;
FILE *f;
config_t cfg;
Expand Down Expand Up @@ -768,6 +866,23 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) { /*NOLINT(

config_setting_t *rules = config_lookup(&cfg, "rules");
if (rules) {
static const rule_replacement_t replacements[] = {
{"blur-background-exclude", "blur-background", CONFIG_TYPE_BOOL, {.boolean = false}},
{"shadow-exclude", "shadow", CONFIG_TYPE_BOOL, {.boolean = false}},
{"fade-exclude", "fade", CONFIG_TYPE_BOOL, {.boolean = false}},
{"rounded-corners-exclude", "corner-radius", CONFIG_TYPE_FLOAT, {.floating = 0.0f}},
{"unredir-if-possible-exclude", "unredir", CONFIG_TYPE_BOOL, {.boolean = false}},
{"invert-color-include", "invert-color", CONFIG_TYPE_BOOL, {.boolean = true}},
{"transparent-clipping-exclude",
"transparent-clipping",
CONFIG_TYPE_BOOL,
{.boolean = false}},
{"wintypes", NULL, 0, 0}};

for (size_t i = 0; i < sizeof(replacements) / sizeof(*replacements); i++) {
create_rules_compat(&cfg, rules, &replacements[i]);
}

bool deprecated = false;
parse_rules(&opt->rules, rules, &opt->all_scripts, &deprecated);
if (deprecated) {
Expand Down Expand Up @@ -957,25 +1072,15 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) { /*NOLINT(
void (*free_value)(void *);
void *user_data;
} rule_list[] = {
{"transparent-clipping-exclude",
offsetof(struct options, transparent_clipping_blacklist)},
{"shadow-exclude", offsetof(struct options, shadow_blacklist)},
{"clip-shadow-above", offsetof(struct options, shadow_clip_list)},
{"fade-exclude", offsetof(struct options, fade_blacklist)},
{"focus-exclude", offsetof(struct options, focus_blacklist)},
{"invert-color-include", offsetof(struct options, invert_color_list)},
{"blur-background-exclude", offsetof(struct options, blur_background_blacklist)},
{"unredir-if-possible-exclude",
offsetof(struct options, unredir_if_possible_blacklist)},
{"rounded-corners-exclude", offsetof(struct options, rounded_corners_blacklist)},
{"corner-radius-rules", offsetof(struct options, corner_radius_rules),
parse_numeric_prefix, NULL, (int[]){0, INT_MAX}},
{"opacity-rule", offsetof(struct options, opacity_rules),
parse_numeric_prefix, NULL, (int[]){0, 100}},
{"window-shader-fg-rule", offsetof(struct options, window_shader_fg_rules),
parse_window_shader_prefix, free, (void *)config_get_include_dir(&cfg)},
};

if (!list_is_empty(&opt->rules)) {
for (size_t i = 0; i < ARR_SIZE(rule_list); i++) {
if (config_lookup(&cfg, rule_list[i].name)) {
Expand Down Expand Up @@ -1133,7 +1238,7 @@ bool parse_config_libconfig(options_t *opt, const char *config_file) { /*NOLINT(
succeeded = true;

out:
config_destroy(&cfg);
*release_cfg = cfg;
free(path);
return succeeded;
}
3 changes: 3 additions & 0 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,9 @@ static const struct picom_option picom_options[] = {
"transparent clipping applied. Useful for screenshot tools, where you "
"need to be able to see through transparent parts of the window."},

[342] = {"dump-config" , ENABLE(dump_config), "Dump config file to stdout. "
"Useful when you want to get legacy parameter conversions."},

// Rules that are too long to fit in one line
[304] = {"opacity-rule" , NUMERIC_RULES(opacity_rules, "OPACITY", 0, 100),
"Specify a list of opacity rules, see man page for more details"},
Expand Down
13 changes: 12 additions & 1 deletion src/picom.c
Original file line number Diff line number Diff line change
Expand Up @@ -2106,18 +2106,29 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
ps->glx_event = ext_info->first_event;
}

// The value to which the config will be written after loading
config_t cfg;
memset(&cfg, 0, sizeof(config_t));

// Parse configuration file
if (!parse_config(&ps->o, config_file)) {
if (!parse_config(&ps->o, config_file, &cfg)) {
config_destroy(&cfg);
return NULL;
}

// Parse all of the rest command line options
if (!get_cfg(&ps->o, argc, argv)) {
config_destroy(&cfg);
log_fatal("Failed to get configuration, usually mean you have specified "
"invalid options.");
return NULL;
}

if (ps->o.dump_config && cfg.root) {
config_write(&cfg, stdout);
}

config_destroy(&cfg);
show_config_warning_message_box(&ps->o);

const char *basename = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
Expand Down