// SPDX-License-Identifier: MIT // Copyright (c) 2012-2014 Richard Grenville #include #include #include #include #include #include "common.h" #include "config.h" /** * Wrapper of libconfig's config_lookup_int. * * So it takes a pointer to bool. */ static inline int lcfg_lookup_bool(const config_t *config, const char *path, bool *value) { int ival; int ret = config_lookup_bool(config, path, &ival); if (ret) *value = ival; return ret; } /** * Get a file stream of the configuration file to read. * * Follows the XDG specification to search for the configuration file. */ FILE * open_config_file(char *cpath, char **ppath) { static const char *config_filename = "/compton.conf"; static const char *config_filename_legacy = "/.compton.conf"; static const char *config_home_suffix = "/.config"; static const char *config_system_dir = "/etc/xdg"; char *dir = NULL, *home = NULL; char *path = cpath; FILE *f = NULL; if (path) { f = fopen(path, "r"); if (f && ppath) *ppath = path; return f; } // Check user configuration file in $XDG_CONFIG_HOME firstly if (!((dir = getenv("XDG_CONFIG_HOME")) && strlen(dir))) { if (!((home = getenv("HOME")) && strlen(home))) return NULL; path = mstrjoin3(home, config_home_suffix, config_filename); } else path = mstrjoin(dir, config_filename); f = fopen(path, "r"); if (f && ppath) *ppath = path; else free(path); if (f) return f; // Then check user configuration file in $HOME if ((home = getenv("HOME")) && strlen(home)) { path = mstrjoin(home, config_filename_legacy); f = fopen(path, "r"); if (f && ppath) *ppath = path; else free(path); if (f) return f; } // Check system configuration file in $XDG_CONFIG_DIRS at last if ((dir = getenv("XDG_CONFIG_DIRS")) && strlen(dir)) { char *part = strtok(dir, ":"); while (part) { path = mstrjoin(part, config_filename); f = fopen(path, "r"); if (f && ppath) *ppath = path; else free(path); if (f) return f; part = strtok(NULL, ":"); } } else { path = mstrjoin(config_system_dir, config_filename); f = fopen(path, "r"); if (f && ppath) *ppath = path; else free(path); if (f) return f; } return NULL; } /** * Parse a condition list in configuration file. */ void parse_cfg_condlst(session_t *ps, const config_t *pcfg, c2_lptr_t **pcondlst, 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--) condlst_add(ps, pcondlst, config_setting_get_string_elem(setting, i)); } // Treat it as a single pattern if it's a string else if (CONFIG_TYPE_STRING == config_setting_type(setting)) { condlst_add(ps, pcondlst, config_setting_get_string(setting)); } } } /** * Parse an opacity rule list in configuration file. */ static inline void parse_cfg_condlst_opct(session_t *ps, 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_rule_opacity(ps, config_setting_get_string_elem(setting, i))) exit(1); } // Treat it as a single pattern if it's a string else if (CONFIG_TYPE_STRING == config_setting_type(setting)) { parse_rule_opacity(ps, config_setting_get_string(setting)); } } } /** * Parse a configuration file from default location. */ void parse_config(session_t *ps, struct options_tmp *pcfgtmp) { char *path = NULL; FILE *f; config_t cfg; int ival = 0; bool bval; double dval = 0.0; // libconfig manages string memory itself, so no need to manually free // anything const char *sval = NULL; f = open_config_file(ps->o.config_file, &path); if (!f) { if (ps->o.config_file) { printf_errfq(1, "(): Failed to read configuration file \"%s\".", ps->o.config_file); free(ps->o.config_file); ps->o.config_file = NULL; } return; } config_init(&cfg); { // dirname() could modify the original string, thus we must pass a // copy char *path2 = mstrcpy(path); char *parent = dirname(path2); if (parent) config_set_include_dir(&cfg, parent); free(path2); } { int read_result = config_read(&cfg, f); fclose(f); f = NULL; if (CONFIG_FALSE == read_result) { printf("Error when reading configuration file \"%s\", line %d: %s\n", path, config_error_line(&cfg), config_error_text(&cfg)); config_destroy(&cfg); free(path); return; } } config_set_auto_convert(&cfg, 1); if (path != ps->o.config_file) { free(ps->o.config_file); ps->o.config_file = path; } // Get options from the configuration file. We don't do range checking // right now. It will be done later // -D (fade_delta) if (config_lookup_int(&cfg, "fade-delta", &ival)) ps->o.fade_delta = ival; // -I (fade_in_step) if (config_lookup_float(&cfg, "fade-in-step", &dval)) ps->o.fade_in_step = normalize_d(dval) * OPAQUE; // -O (fade_out_step) if (config_lookup_float(&cfg, "fade-out-step", &dval)) ps->o.fade_out_step = normalize_d(dval) * OPAQUE; // -r (shadow_radius) config_lookup_int(&cfg, "shadow-radius", &ps->o.shadow_radius); // -o (shadow_opacity) config_lookup_float(&cfg, "shadow-opacity", &ps->o.shadow_opacity); // -l (shadow_offset_x) config_lookup_int(&cfg, "shadow-offset-x", &ps->o.shadow_offset_x); // -t (shadow_offset_y) config_lookup_int(&cfg, "shadow-offset-y", &ps->o.shadow_offset_y); // -i (inactive_opacity) if (config_lookup_float(&cfg, "inactive-opacity", &dval)) ps->o.inactive_opacity = normalize_d(dval) * OPAQUE; // --active_opacity if (config_lookup_float(&cfg, "active-opacity", &dval)) ps->o.active_opacity = normalize_d(dval) * OPAQUE; // -e (frame_opacity) config_lookup_float(&cfg, "frame-opacity", &ps->o.frame_opacity); // -c (shadow_enable) if (config_lookup_bool(&cfg, "shadow", &ival) && ival) wintype_arr_enable(ps->o.wintype_shadow); // -C (no_dock_shadow) lcfg_lookup_bool(&cfg, "no-dock-shadow", &pcfgtmp->no_dock_shadow); // -G (no_dnd_shadow) lcfg_lookup_bool(&cfg, "no-dnd-shadow", &pcfgtmp->no_dnd_shadow); // -m (menu_opacity) config_lookup_float(&cfg, "menu-opacity", &pcfgtmp->menu_opacity); // -f (fading_enable) if (config_lookup_bool(&cfg, "fading", &ival) && ival) wintype_arr_enable(ps->o.wintype_fade); // --no-fading-open-close lcfg_lookup_bool(&cfg, "no-fading-openclose", &ps->o.no_fading_openclose); // --no-fading-destroyed-argb lcfg_lookup_bool(&cfg, "no-fading-destroyed-argb", &ps->o.no_fading_destroyed_argb); // --shadow-red config_lookup_float(&cfg, "shadow-red", &ps->o.shadow_red); // --shadow-green config_lookup_float(&cfg, "shadow-green", &ps->o.shadow_green); // --shadow-blue config_lookup_float(&cfg, "shadow-blue", &ps->o.shadow_blue); // --shadow-exclude-reg if (config_lookup_string(&cfg, "shadow-exclude-reg", &sval)) ps->o.shadow_exclude_reg_str = strdup(sval); // --inactive-opacity-override lcfg_lookup_bool(&cfg, "inactive-opacity-override", &ps->o.inactive_opacity_override); // --inactive-dim config_lookup_float(&cfg, "inactive-dim", &ps->o.inactive_dim); // --mark-wmwin-focused lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &ps->o.mark_wmwin_focused); // --mark-ovredir-focused lcfg_lookup_bool(&cfg, "mark-ovredir-focused", &ps->o.mark_ovredir_focused); // --shadow-ignore-shaped lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", &ps->o.shadow_ignore_shaped); // --detect-rounded-corners lcfg_lookup_bool(&cfg, "detect-rounded-corners", &ps->o.detect_rounded_corners); // --xinerama-shadow-crop lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", &ps->o.xinerama_shadow_crop); // --detect-client-opacity lcfg_lookup_bool(&cfg, "detect-client-opacity", &ps->o.detect_client_opacity); // --refresh-rate config_lookup_int(&cfg, "refresh-rate", &ps->o.refresh_rate); // --vsync if (config_lookup_string(&cfg, "vsync", &sval) && !parse_vsync(ps, sval)) exit(1); // --backend if (config_lookup_string(&cfg, "backend", &sval) && !parse_backend(ps, sval)) exit(1); // --sw-opti lcfg_lookup_bool(&cfg, "sw-opti", &ps->o.sw_opti); // --use-ewmh-active-win lcfg_lookup_bool(&cfg, "use-ewmh-active-win", &ps->o.use_ewmh_active_win); // --unredir-if-possible lcfg_lookup_bool(&cfg, "unredir-if-possible", &ps->o.unredir_if_possible); // --unredir-if-possible-delay if (config_lookup_int(&cfg, "unredir-if-possible-delay", &ival)) ps->o.unredir_if_possible_delay = ival; // --inactive-dim-fixed lcfg_lookup_bool(&cfg, "inactive-dim-fixed", &ps->o.inactive_dim_fixed); // --detect-transient lcfg_lookup_bool(&cfg, "detect-transient", &ps->o.detect_transient); // --detect-client-leader lcfg_lookup_bool(&cfg, "detect-client-leader", &ps->o.detect_client_leader); // --shadow-exclude parse_cfg_condlst(ps, &cfg, &ps->o.shadow_blacklist, "shadow-exclude"); // --fade-exclude parse_cfg_condlst(ps, &cfg, &ps->o.fade_blacklist, "fade-exclude"); // --focus-exclude parse_cfg_condlst(ps, &cfg, &ps->o.focus_blacklist, "focus-exclude"); // --invert-color-include parse_cfg_condlst(ps, &cfg, &ps->o.invert_color_list, "invert-color-include"); // --blur-background-exclude parse_cfg_condlst(ps, &cfg, &ps->o.blur_background_blacklist, "blur-background-exclude"); // --opacity-rule parse_cfg_condlst_opct(ps, &cfg, "opacity-rule"); // --unredir-if-possible-exclude parse_cfg_condlst(ps, &cfg, &ps->o.unredir_if_possible_blacklist, "unredir-if-possible-exclude"); // --blur-background lcfg_lookup_bool(&cfg, "blur-background", &ps->o.blur_background); // --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); // --blur-kern if (config_lookup_string(&cfg, "blur-kern", &sval) && !parse_conv_kern_lst(ps, sval, ps->o.blur_kerns, MAX_BLUR_PASS)) exit(1); // --resize-damage config_lookup_int(&cfg, "resize-damage", &ps->o.resize_damage); // --glx-no-stencil lcfg_lookup_bool(&cfg, "glx-no-stencil", &ps->o.glx_no_stencil); // --glx-no-rebind-pixmap lcfg_lookup_bool(&cfg, "glx-no-rebind-pixmap", &ps->o.glx_no_rebind_pixmap); // --glx-swap-method if (config_lookup_string(&cfg, "glx-swap-method", &sval) && !parse_glx_swap_method(ps, sval)) exit(1); // --glx-use-gpushader4 lcfg_lookup_bool(&cfg, "glx-use-gpushader4", &ps->o.glx_use_gpushader4); // --xrender-sync lcfg_lookup_bool(&cfg, "xrender-sync", &ps->o.xrender_sync); // --xrender-sync-fence lcfg_lookup_bool(&cfg, "xrender-sync-fence", &ps->o.xrender_sync_fence); if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval)) printf_errf("(): \"clear-shadow\" is removed as an option, and is always" " enabled now. Consider removing it from your config file"); if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval)) printf_errf("(): \"paint-on-overlay\" has been removed as an option, and " "is enabled whenever possible"); if (config_lookup_float(&cfg, "alpha-step", &dval)) printf_errf("(): \"alpha-step\" has been removed, compton now tries to make use" " of all alpha values"); const char *deprecation_message = "has been removed. If you encounter problems " "without this feature, please feel free to open a bug report"; if (lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &bval) && bval) printf_errf("(): \"glx-use-copysubbuffermesa\" %s", deprecation_message); if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval) printf_errf("(): \"glx-copy-from-front\" %s", deprecation_message); // Wintype settings // XXX ! Refactor all the wintype_* arrays into a struct for (wintype_t i = 0; i < NUM_WINTYPES; ++i) { char *str = mstrjoin("wintypes.", WINTYPES[i]); config_setting_t *setting = config_lookup(&cfg, str); free(str); if (setting) { if (config_setting_lookup_bool(setting, "shadow", &ival)) ps->o.wintype_shadow[i] = (bool) ival; if (config_setting_lookup_bool(setting, "fade", &ival)) ps->o.wintype_fade[i] = (bool) ival; if (config_setting_lookup_bool(setting, "focus", &ival)) ps->o.wintype_focus[i] = (bool) ival; if (config_setting_lookup_bool(setting, "full-shadow", &ival)) ps->o.wintype_full_shadow[i] = ival; double fval; if (config_setting_lookup_float(setting, "opacity", &fval)) ps->o.wintype_opacity[i] = normalize_d(fval); } } config_destroy(&cfg); }