From fcef5e706d52fe1368c1487a76ef47ab90804020 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 22 Aug 2018 12:58:49 +0100 Subject: [PATCH] Some cleanup work * Remove NO_C2 option * Split configuration related functions into their own file * Drop support for libconfig < 1.4 * Fix dependencies in Makefile --- .gitignore | 2 - Makefile | 29 +- src/common.h | 33 +- src/compton.c | 700 +---------------------------------------- src/compton.h | 69 ---- src/config.c | 320 +++++++++++++++++++ src/config.h | 32 ++ src/config_libconfig.c | 398 +++++++++++++++++++++++ src/opengl.c | 2 +- 9 files changed, 783 insertions(+), 802 deletions(-) create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/config_libconfig.c diff --git a/.gitignore b/.gitignore index 5dc3f9c..cab0327 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,6 @@ .deps aclocal.m4 autom4te.cache -config.h -config.h.in config.log config.status configure diff --git a/Makefile b/Makefile index 83c8dd8..b851311 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,10 @@ PACKAGES = x11 xcomposite xfixes xdamage xrender xext xrandr LIBS = -lm -lrt INCS = -OBJS = compton.o +OBJS = compton.o config.o # === Configuration flags === -CFG = -std=c99 +CFG = -std=c99 -D_GNU_SOURCE # ==== Xinerama ==== # Enables support for --xinerama-shadow-crop @@ -30,10 +30,14 @@ endif ifeq "$(NO_LIBCONFIG)" "" CFG += -DCONFIG_LIBCONFIG PACKAGES += libconfig + OBJS += config_libconfig.o # libconfig-1.3* does not define LIBCONFIG_VER* macros, so we use # pkg-config to determine its version here - CFG += $(shell pkg-config --atleast-version=1.4 libconfig || echo '-DCONFIG_LIBCONFIG_LEGACY') + LIBCONFIG_VER = $(shell pkg-config --atleast-version=1.4 libconfig; echo $$?) + ifeq ($LIBCONFIG_VER, 1) + $(error "Your libconfig is too old, at least 1.4 is required") + endif endif # ==== PCRE regular expression ==== @@ -90,12 +94,7 @@ ifeq "$(NO_XSYNC)" "" CFG += -DCONFIG_XSYNC endif -# ==== C2 ==== -# Enable window condition support -ifeq "$(NO_C2)" "" - CFG += -DCONFIG_C2 - OBJS += c2.o -endif +OBJS += c2.o # ==== X resource checker ==== # Enable X resource leakage checking (Pixmap only, presently) @@ -141,7 +140,15 @@ MANPAGES_HTML = $(addsuffix .html,$(MANPAGES)) src/.clang_complete: Makefile @(for i in $(filter-out -O% -DNDEBUG, $(CFG) $(CPPFLAGS) $(CFLAGS) $(INCS)); do echo "$$i"; done) > $@ -%.o: src/%.c src/%.h src/common.h +.deps: + mkdir -p .deps + +%.o: src/%.c .deps + $(eval DEP=$(addprefix .deps/,$(@:.o=.d))) + @set -e; rm -f $(DEP); \ + $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $(DEP); \ + rm -f $@.$$$$ $(CC) $(CFG) $(CPPFLAGS) $(CFLAGS) $(INCS) -c src/$*.c compton: $(OBJS) @@ -183,8 +190,10 @@ endif clean: @rm -f $(OBJS) compton $(MANPAGES) $(MANPAGES_HTML) .clang_complete + @rm -rf .deps version: @echo "$(COMPTON_VERSION)" .PHONY: uninstall clean docs version +include $(addprefix .deps/,$(sources:.c=.d)) diff --git a/src/common.h b/src/common.h index 8147271..3641f63 100644 --- a/src/common.h +++ b/src/common.h @@ -8,8 +8,7 @@ * */ -#ifndef COMPTON_COMMON_H -#define COMPTON_COMMON_H +#pragma once // === Options === @@ -42,8 +41,6 @@ // #define CONFIG_REGEX_PCRE_JIT 1 // Whether to enable parsing of configuration files using libconfig. // #define CONFIG_LIBCONFIG 1 -// Whether we are using a legacy version of libconfig (1.3.x). -// #define CONFIG_LIBCONFIG_LEGACY 1 // Whether to enable DRM VSync support // #define CONFIG_VSYNC_DRM 1 // Whether to enable OpenGL support @@ -54,17 +51,11 @@ // #define CONFIG_VSYNC_OPENGL_FBO 1 // Whether to enable DBus support with libdbus. // #define CONFIG_DBUS 1 -// Whether to enable condition support. -// #define CONFIG_C2 1 // Whether to enable X Sync support. // #define CONFIG_XSYNC 1 // Whether to enable GLX Sync support. // #define CONFIG_GLX_XSYNC 1 -#if !defined(CONFIG_C2) && defined(DEBUG_C2) -#error Cannot enable c2 debugging without c2 support. -#endif - #if (!defined(CONFIG_XSYNC) || !defined(CONFIG_VSYNC_OPENGL)) && defined(CONFIG_GLX_SYNC) #error Cannot enable GL sync without X Sync / OpenGL support. #endif @@ -80,8 +71,6 @@ // === Includes === // For some special functions -#define _GNU_SOURCE - #include #include #include @@ -116,12 +105,6 @@ #define PictOpDifference 0x39 #endif -// libconfig -#ifdef CONFIG_LIBCONFIG -#include -#include -#endif - // libdbus #ifdef CONFIG_DBUS #include @@ -2483,7 +2466,6 @@ opts_set_no_fading_openclose(session_t *ps, bool newval); //!@} #endif -#ifdef CONFIG_C2 /** @name c2 */ ///@{ @@ -2503,7 +2485,6 @@ c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst, #define c2_match(ps, w, condlst, cache) c2_matchd((ps), (w), (condlst), \ (cache), NULL) -#endif ///@} @@ -2564,4 +2545,14 @@ hexdump(const char *data, int len) { fflush(stdout); } -#endif +/** + * Set a bool array of all wintypes to true. + */ +static inline void +wintype_arr_enable(bool arr[]) { + wintype_t i; + + for (i = 0; i < NUM_WINTYPES; ++i) { + arr[i] = true; + } +} diff --git a/src/compton.c b/src/compton.c index d3faa0d..618b627 100644 --- a/src/compton.c +++ b/src/compton.c @@ -9,6 +9,7 @@ */ #include "compton.h" +#include "config.h" #include // === Global constants === @@ -684,24 +685,6 @@ win_rounded_corners(session_t *ps, win *w) { cxfree(rects); } -/** - * Add a pattern to a condition linked list. - */ -static bool -condlst_add(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) { - if (!pattern) - return false; - -#ifdef CONFIG_C2 - if (!c2_parse(ps, pcondlst, pattern)) - exit(1); -#else - printf_errfq(1, "(): Condition support not compiled in."); -#endif - - return true; -} - /** * Determine the event mask for a window. */ @@ -2615,7 +2598,6 @@ win_update_opacity_rule(session_t *ps, win *w) { if (IsViewable != w->a.map_state) return; -#ifdef CONFIG_C2 opacity_t opacity = OPAQUE; bool is_set = false; void *val = NULL; @@ -2633,7 +2615,6 @@ win_update_opacity_rule(session_t *ps, win *w) { wid_rm_opacity_prop(ps, w->id); else wid_set_opacity_prop(ps, w->id, opacity); -#endif } /** @@ -4997,683 +4978,6 @@ write_pid(session_t *ps) { return true; } -/** - * Parse a long number. - */ -static inline bool -parse_long(const char *s, long *dest) { - const char *endptr = NULL; - long val = strtol(s, (char **) &endptr, 0); - if (!endptr || endptr == s) { - printf_errf("(\"%s\"): Invalid number.", s); - return false; - } - while (isspace(*endptr)) - ++endptr; - if (*endptr) { - printf_errf("(\"%s\"): Trailing characters.", s); - return false; - } - *dest = val; - return true; -} - -/** - * Parse a floating-point number in matrix. - */ -static inline const char * -parse_matrix_readnum(const char *src, double *dest) { - char *pc = NULL; - double val = strtod(src, &pc); - if (!pc || pc == src) { - printf_errf("(\"%s\"): No number found.", src); - return src; - } - - while (*pc && (isspace(*pc) || ',' == *pc)) - ++pc; - - *dest = val; - - return pc; -} - -/** - * Parse a matrix. - */ -static inline XFixed * -parse_matrix(session_t *ps, const char *src, const char **endptr) { - int wid = 0, hei = 0; - const char *pc = NULL; - XFixed *matrix = NULL; - - // Get matrix width and height - { - double val = 0.0; - if (src == (pc = parse_matrix_readnum(src, &val))) - goto parse_matrix_err; - src = pc; - wid = val; - if (src == (pc = parse_matrix_readnum(src, &val))) - goto parse_matrix_err; - src = pc; - hei = val; - } - - // Validate matrix width and height - if (wid <= 0 || hei <= 0) { - printf_errf("(): Invalid matrix width/height."); - goto parse_matrix_err; - } - if (!(wid % 2 && hei % 2)) { - printf_errf("(): Width/height not odd."); - goto parse_matrix_err; - } - if (wid > 16 || hei > 16) - printf_errf("(): Matrix width/height too large, may slow down" - "rendering, and/or consume lots of memory"); - - // Allocate memory - matrix = calloc(wid * hei + 2, sizeof(XFixed)); - if (!matrix) { - printf_errf("(): Failed to allocate memory for matrix."); - goto parse_matrix_err; - } - - // Read elements - { - int skip = hei / 2 * wid + wid / 2; - bool hasneg = false; - for (int i = 0; i < wid * hei; ++i) { - // Ignore the center element - if (i == skip) { - matrix[2 + i] = XDoubleToFixed(0); - continue; - } - double val = 0; - if (src == (pc = parse_matrix_readnum(src, &val))) - goto parse_matrix_err; - src = pc; - if (val < 0) hasneg = true; - matrix[2 + i] = XDoubleToFixed(val); - } - if (BKEND_XRENDER == ps->o.backend && hasneg) - printf_errf("(): A convolution kernel with negative values " - "may not work properly under X Render backend."); - } - - // Detect trailing characters - for ( ;*pc && ';' != *pc; ++pc) - if (!isspace(*pc) && ',' != *pc) { - printf_errf("(): Trailing characters in matrix string."); - goto parse_matrix_err; - } - - // Jump over spaces after ';' - if (';' == *pc) { - ++pc; - while (*pc && isspace(*pc)) - ++pc; - } - - // Require an end of string if endptr is not provided, otherwise - // copy end pointer to endptr - if (endptr) - *endptr = pc; - else if (*pc) { - printf_errf("(): Only one matrix expected."); - goto parse_matrix_err; - } - - // Fill in width and height - matrix[0] = XDoubleToFixed(wid); - matrix[1] = XDoubleToFixed(hei); - - return matrix; - -parse_matrix_err: - free(matrix); - return NULL; -} - -/** - * Parse a convolution kernel. - */ -static inline XFixed * -parse_conv_kern(session_t *ps, const char *src, const char **endptr) { - return parse_matrix(ps, src, endptr); -} - -/** - * Parse a list of convolution kernels. - */ -static bool -parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) { - static const struct { - const char *name; - const char *kern_str; - } CONV_KERN_PREDEF[] = { - { "3x3box", "3,3,1,1,1,1,1,1,1,1," }, - { "5x5box", "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, - { "7x7box", "7,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, - { "3x3gaussian", "3,3,0.243117,0.493069,0.243117,0.493069,0.493069,0.243117,0.493069,0.243117," }, - { "5x5gaussian", "5,5,0.003493,0.029143,0.059106,0.029143,0.003493,0.029143,0.243117,0.493069,0.243117,0.029143,0.059106,0.493069,0.493069,0.059106,0.029143,0.243117,0.493069,0.243117,0.029143,0.003493,0.029143,0.059106,0.029143,0.003493," }, - { "7x7gaussian", "7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003," }, - { "9x9gaussian", "9,9,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000," }, - { "11x11gaussian", "11,11,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000," }, - }; - for (int i = 0; - i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) - if (!strcmp(CONV_KERN_PREDEF[i].name, src)) - return parse_conv_kern_lst(ps, CONV_KERN_PREDEF[i].kern_str, dest, max); - - int i = 0; - const char *pc = src; - - // Free old kernels - for (i = 0; i < max; ++i) { - free(dest[i]); - dest[i] = NULL; - } - - // Continue parsing until the end of source string - i = 0; - while (pc && *pc && i < max - 1) { - if (!(dest[i++] = parse_conv_kern(ps, pc, &pc))) - return false; - } - - if (*pc) { - printf_errf("(): Too many blur kernels!"); - return false; - } - - return true; -} - -/** - * Parse a X geometry. - */ -static inline bool -parse_geometry(session_t *ps, const char *src, geometry_t *dest) { - geometry_t geom = { .wid = -1, .hei = -1, .x = -1, .y = -1 }; - long val = 0L; - char *endptr = NULL; - -#define T_STRIPSPACE() do { \ - while (*src && isspace(*src)) ++src; \ - if (!*src) goto parse_geometry_end; \ -} while(0) - - T_STRIPSPACE(); - - // Parse width - // Must be base 10, because "0x0..." may appear - if (!('+' == *src || '-' == *src)) { - val = strtol(src, &endptr, 10); - if (endptr && src != endptr) { - geom.wid = val; - assert(geom.wid >= 0); - src = endptr; - } - T_STRIPSPACE(); - } - - // Parse height - if ('x' == *src) { - ++src; - val = strtol(src, &endptr, 10); - if (endptr && src != endptr) { - geom.hei = val; - if (geom.hei < 0) { - printf_errf("(\"%s\"): Invalid height.", src); - return false; - } - src = endptr; - } - T_STRIPSPACE(); - } - - // Parse x - if ('+' == *src || '-' == *src) { - val = strtol(src, &endptr, 10); - if (endptr && src != endptr) { - geom.x = val; - if ('-' == *src && geom.x <= 0) - geom.x -= 2; - src = endptr; - } - T_STRIPSPACE(); - } - - // Parse y - if ('+' == *src || '-' == *src) { - val = strtol(src, &endptr, 10); - if (endptr && src != endptr) { - geom.y = val; - if ('-' == *src && geom.y <= 0) - geom.y -= 2; - src = endptr; - } - T_STRIPSPACE(); - } - - if (*src) { - printf_errf("(\"%s\"): Trailing characters.", src); - return false; - } - -parse_geometry_end: - *dest = geom; - return true; -} - -/** - * Parse a list of opacity rules. - */ -static inline bool -parse_rule_opacity(session_t *ps, const char *src) { -#ifdef CONFIG_C2 - // Find opacity value - char *endptr = NULL; - long val = strtol(src, &endptr, 0); - if (!endptr || endptr == src) { - printf_errf("(\"%s\"): No opacity specified?", src); - return false; - } - if (val > 100 || val < 0) { - printf_errf("(\"%s\"): Opacity %ld invalid.", src, val); - return false; - } - - // Skip over spaces - while (*endptr && isspace(*endptr)) - ++endptr; - if (':' != *endptr) { - printf_errf("(\"%s\"): Opacity terminator not found.", src); - return false; - } - ++endptr; - - // Parse pattern - // I hope 1-100 is acceptable for (void *) - return c2_parsed(ps, &ps->o.opacity_rules, endptr, (void *) val); -#else - printf_errf("(\"%s\"): Condition support not compiled in.", src); - return false; -#endif -} - -#ifdef CONFIG_LIBCONFIG -/** - * Get a file stream of the configuration file to read. - * - * Follows the XDG specification to search for the configuration file. - */ -static FILE * -open_config_file(char *cpath, char **ppath) { - const static char *config_filename = "/compton.conf"; - const static char *config_filename_legacy = "/.compton.conf"; - const static char *config_home_suffix = "/.config"; - const static 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. - */ -static inline 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. - */ -static void -parse_config(session_t *ps, struct options_tmp *pcfgtmp) { - char *path = NULL; - FILE *f; - config_t cfg; - int ival = 0; - 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); -#ifndef CONFIG_LIBCONFIG_LEGACY - { - // 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); - } -#endif - - { - 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 (lcfg_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) - lcfg_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) - lcfg_lookup_int(&cfg, "shadow-offset-x", &ps->o.shadow_offset_x); - // -t (shadow_offset_y) - lcfg_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); - // -z (clear_shadow) - lcfg_lookup_bool(&cfg, "clear-shadow", &ps->o.clear_shadow); - // -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) - && !parse_geometry(ps, sval, &ps->o.shadow_exclude_reg_geom)) - exit(1); - // --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 - lcfg_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); - // --alpha-step - config_lookup_float(&cfg, "alpha-step", &ps->o.alpha_step); - // --dbe - lcfg_lookup_bool(&cfg, "dbe", &ps->o.dbe); - // --paint-on-overlay - lcfg_lookup_bool(&cfg, "paint-on-overlay", &ps->o.paint_on_overlay); - // --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 (lcfg_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 - lcfg_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-copy-from-front - lcfg_lookup_bool(&cfg, "glx-copy-from-front", &ps->o.glx_copy_from_front); - // --glx-use-copysubbuffermesa - lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &ps->o.glx_use_copysubbuffermesa); - // --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); - // Wintype settings - { - wintype_t i; - - for (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; - - double fval; - if (config_setting_lookup_float(setting, "opacity", &fval)) - ps->o.wintype_opacity[i] = normalize_d(fval); - } - } - } - - config_destroy(&cfg); -} -#endif - /** * Process arguments and configuration files. */ @@ -7513,7 +6817,6 @@ session_destroy(session_t *ps) { ps->alpha_picts = NULL; } -#ifdef CONFIG_C2 // Free blacklists free_wincondlst(&ps->o.shadow_blacklist); free_wincondlst(&ps->o.fade_blacklist); @@ -7523,7 +6826,6 @@ session_destroy(session_t *ps) { free_wincondlst(&ps->o.opacity_rules); free_wincondlst(&ps->o.paint_blacklist); free_wincondlst(&ps->o.unredir_if_possible_blacklist); -#endif // Free tracked atom list { diff --git a/src/compton.h b/src/compton.h index 449d948..5ad6c30 100644 --- a/src/compton.h +++ b/src/compton.h @@ -69,18 +69,6 @@ sub_unslong(unsigned long a, unsigned long b) { return (a > b) ? a - b : 0; } -/** - * Set a bool array of all wintypes to true. - */ -static inline void -wintype_arr_enable(bool arr[]) { - wintype_t i; - - for (i = 0; i < NUM_WINTYPES; ++i) { - arr[i] = true; - } -} - /** * Set a switch_t array of all unset wintypes to true. */ @@ -186,10 +174,8 @@ free_damage(session_t *ps, Damage *p) { */ static inline void free_wincondlst(c2_lptr_t **pcondlst) { -#ifdef CONFIG_C2 while ((*pcondlst = c2_free_lptr(*pcondlst))) continue; -#endif } /** @@ -585,16 +571,9 @@ win_validate_pixmap(session_t *ps, win *w) { */ static inline bool win_match(session_t *ps, win *w, c2_lptr_t *condlst, const c2_lptr_t **cache) { -#ifdef CONFIG_C2 return c2_match(ps, w, condlst, cache); -#else - return false; -#endif } -static bool -condlst_add(session_t *ps, c2_lptr_t **pcondlst, const char *pattern); - static long determine_evmask(session_t *ps, Window wid, win_evmode_t mode); @@ -1174,54 +1153,6 @@ ev_handle(session_t *ps, XEvent *ev); static bool fork_after(session_t *ps); -#ifdef CONFIG_LIBCONFIG -/** - * Wrapper of libconfig's config_lookup_int. - * - * To convert int value config_lookup_bool - * returns to bool. - */ -static inline void -lcfg_lookup_bool(const config_t *config, const char *path, - bool *value) { - int ival; - - if (config_lookup_bool(config, path, &ival)) - *value = ival; -} - -/** - * Wrapper of libconfig's config_lookup_int. - * - * To deal with the different value types config_lookup_int - * returns in libconfig-1.3 and libconfig-1.4. - */ -static inline int -lcfg_lookup_int(const config_t *config, const char *path, int *value) { -#ifndef CONFIG_LIBCONFIG_LEGACY - return config_lookup_int(config, path, value); -#else - long lval; - int ret; - - if ((ret = config_lookup_int(config, path, &lval))) - *value = lval; - - return ret; -#endif -} - -static FILE * -open_config_file(char *cpath, char **path); - -static void -parse_cfg_condlst(session_t *ps, const config_t *pcfg, c2_lptr_t **pcondlst, - const char *name); - -static void -parse_config(session_t *ps, struct options_tmp *pcfgtmp); -#endif - static void get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass); diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..5e297c0 --- /dev/null +++ b/src/config.c @@ -0,0 +1,320 @@ +#include +#include + +#include "common.h" +#include "config.h" + +/** + * Parse a long number. + */ +bool +parse_long(const char *s, long *dest) { + const char *endptr = NULL; + long val = strtol(s, (char **) &endptr, 0); + if (!endptr || endptr == s) { + printf_errf("(\"%s\"): Invalid number.", s); + return false; + } + while (isspace(*endptr)) + ++endptr; + if (*endptr) { + printf_errf("(\"%s\"): Trailing characters.", s); + return false; + } + *dest = val; + return true; +} + +/** + * Parse a floating-point number in matrix. + */ +const char * +parse_matrix_readnum(const char *src, double *dest) { + char *pc = NULL; + double val = strtod(src, &pc); + if (!pc || pc == src) { + printf_errf("(\"%s\"): No number found.", src); + return src; + } + + while (*pc && (isspace(*pc) || ',' == *pc)) + ++pc; + + *dest = val; + + return pc; +} + +/** + * Parse a matrix. + */ +XFixed * +parse_matrix(session_t *ps, const char *src, const char **endptr) { + int wid = 0, hei = 0; + const char *pc = NULL; + XFixed *matrix = NULL; + + // Get matrix width and height + { + double val = 0.0; + if (src == (pc = parse_matrix_readnum(src, &val))) + goto parse_matrix_err; + src = pc; + wid = val; + if (src == (pc = parse_matrix_readnum(src, &val))) + goto parse_matrix_err; + src = pc; + hei = val; + } + + // Validate matrix width and height + if (wid <= 0 || hei <= 0) { + printf_errf("(): Invalid matrix width/height."); + goto parse_matrix_err; + } + if (!(wid % 2 && hei % 2)) { + printf_errf("(): Width/height not odd."); + goto parse_matrix_err; + } + if (wid > 16 || hei > 16) + printf_errf("(): Matrix width/height too large, may slow down" + "rendering, and/or consume lots of memory"); + + // Allocate memory + matrix = calloc(wid * hei + 2, sizeof(XFixed)); + if (!matrix) { + printf_errf("(): Failed to allocate memory for matrix."); + goto parse_matrix_err; + } + + // Read elements + { + int skip = hei / 2 * wid + wid / 2; + bool hasneg = false; + for (int i = 0; i < wid * hei; ++i) { + // Ignore the center element + if (i == skip) { + matrix[2 + i] = XDoubleToFixed(0); + continue; + } + double val = 0; + if (src == (pc = parse_matrix_readnum(src, &val))) + goto parse_matrix_err; + src = pc; + if (val < 0) hasneg = true; + matrix[2 + i] = XDoubleToFixed(val); + } + if (BKEND_XRENDER == ps->o.backend && hasneg) + printf_errf("(): A convolution kernel with negative values " + "may not work properly under X Render backend."); + } + + // Detect trailing characters + for ( ;*pc && ';' != *pc; ++pc) + if (!isspace(*pc) && ',' != *pc) { + printf_errf("(): Trailing characters in matrix string."); + goto parse_matrix_err; + } + + // Jump over spaces after ';' + if (';' == *pc) { + ++pc; + while (*pc && isspace(*pc)) + ++pc; + } + + // Require an end of string if endptr is not provided, otherwise + // copy end pointer to endptr + if (endptr) + *endptr = pc; + else if (*pc) { + printf_errf("(): Only one matrix expected."); + goto parse_matrix_err; + } + + // Fill in width and height + matrix[0] = XDoubleToFixed(wid); + matrix[1] = XDoubleToFixed(hei); + + return matrix; + +parse_matrix_err: + free(matrix); + return NULL; +} + +/** + * Parse a convolution kernel. + */ +XFixed * +parse_conv_kern(session_t *ps, const char *src, const char **endptr) { + return parse_matrix(ps, src, endptr); +} + +/** + * Parse a list of convolution kernels. + */ +bool +parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) { + static const struct { + const char *name; + const char *kern_str; + } CONV_KERN_PREDEF[] = { + { "3x3box", "3,3,1,1,1,1,1,1,1,1," }, + { "5x5box", "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, + { "7x7box", "7,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, + { "3x3gaussian", "3,3,0.243117,0.493069,0.243117,0.493069,0.493069,0.243117,0.493069,0.243117," }, + { "5x5gaussian", "5,5,0.003493,0.029143,0.059106,0.029143,0.003493,0.029143,0.243117,0.493069,0.243117,0.029143,0.059106,0.493069,0.493069,0.059106,0.029143,0.243117,0.493069,0.243117,0.029143,0.003493,0.029143,0.059106,0.029143,0.003493," }, + { "7x7gaussian", "7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003," }, + { "9x9gaussian", "9,9,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000," }, + { "11x11gaussian", "11,11,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000," }, + }; + for (int i = 0; + i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) + if (!strcmp(CONV_KERN_PREDEF[i].name, src)) + return parse_conv_kern_lst(ps, CONV_KERN_PREDEF[i].kern_str, dest, max); + + int i = 0; + const char *pc = src; + + // Free old kernels + for (i = 0; i < max; ++i) { + free(dest[i]); + dest[i] = NULL; + } + + // Continue parsing until the end of source string + i = 0; + while (pc && *pc && i < max - 1) { + if (!(dest[i++] = parse_conv_kern(ps, pc, &pc))) + return false; + } + + if (*pc) { + printf_errf("(): Too many blur kernels!"); + return false; + } + + return true; +} + +/** + * Parse a X geometry. + */ +bool +parse_geometry(session_t *ps, const char *src, geometry_t *dest) { + geometry_t geom = { .wid = -1, .hei = -1, .x = -1, .y = -1 }; + long val = 0L; + char *endptr = NULL; + +#define T_STRIPSPACE() do { \ + while (*src && isspace(*src)) ++src; \ + if (!*src) goto parse_geometry_end; \ +} while(0) + + T_STRIPSPACE(); + + // Parse width + // Must be base 10, because "0x0..." may appear + if (!('+' == *src || '-' == *src)) { + val = strtol(src, &endptr, 10); + if (endptr && src != endptr) { + geom.wid = val; + assert(geom.wid >= 0); + src = endptr; + } + T_STRIPSPACE(); + } + + // Parse height + if ('x' == *src) { + ++src; + val = strtol(src, &endptr, 10); + if (endptr && src != endptr) { + geom.hei = val; + if (geom.hei < 0) { + printf_errf("(\"%s\"): Invalid height.", src); + return false; + } + src = endptr; + } + T_STRIPSPACE(); + } + + // Parse x + if ('+' == *src || '-' == *src) { + val = strtol(src, &endptr, 10); + if (endptr && src != endptr) { + geom.x = val; + if ('-' == *src && geom.x <= 0) + geom.x -= 2; + src = endptr; + } + T_STRIPSPACE(); + } + + // Parse y + if ('+' == *src || '-' == *src) { + val = strtol(src, &endptr, 10); + if (endptr && src != endptr) { + geom.y = val; + if ('-' == *src && geom.y <= 0) + geom.y -= 2; + src = endptr; + } + T_STRIPSPACE(); + } + + if (*src) { + printf_errf("(\"%s\"): Trailing characters.", src); + return false; + } + +parse_geometry_end: + *dest = geom; + return true; +} + +/** + * Parse a list of opacity rules. + */ +bool parse_rule_opacity(session_t *ps, const char *src) { + // Find opacity value + char *endptr = NULL; + long val = strtol(src, &endptr, 0); + if (!endptr || endptr == src) { + printf_errf("(\"%s\"): No opacity specified?", src); + return false; + } + if (val > 100 || val < 0) { + printf_errf("(\"%s\"): Opacity %ld invalid.", src, val); + return false; + } + + // Skip over spaces + while (*endptr && isspace(*endptr)) + ++endptr; + if (':' != *endptr) { + printf_errf("(\"%s\"): Opacity terminator not found.", src); + return false; + } + ++endptr; + + // Parse pattern + // I hope 1-100 is acceptable for (void *) + return c2_parsed(ps, &ps->o.opacity_rules, endptr, (void *) val); +} + +/** + * Add a pattern to a condition linked list. + */ +bool +condlst_add(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) { + if (!pattern) + return false; + + if (!c2_parse(ps, pcondlst, pattern)) + exit(1); + + return true; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..f29807f --- /dev/null +++ b/src/config.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include + +#include "common.h" + +bool parse_long(const char *, long *); +const char *parse_matrix_readnum(const char *, double *); +XFixed *parse_matrix(session_t *, const char *, const char **); +XFixed *parse_conv_kern(session_t *, const char *, const char **); +bool parse_conv_kern_lst(session_t *, const char *, XFixed **, int); +bool parse_geometry(session_t *, const char *, geometry_t *); +bool parse_rule_opacity(session_t *, const char *); + +/** + * Add a pattern to a condition linked list. + */ +bool condlst_add(session_t *, c2_lptr_t **, const char *); + +#ifdef CONFIG_LIBCONFIG +FILE * +open_config_file(char *cpath, char **path); + +void +parse_cfg_condlst(session_t *ps, const config_t *pcfg, c2_lptr_t **pcondlst, + const char *name); + +void +parse_config(session_t *ps, struct options_tmp *pcfgtmp); +#endif diff --git a/src/config_libconfig.c b/src/config_libconfig.c new file mode 100644 index 0000000..94ea993 --- /dev/null +++ b/src/config_libconfig.c @@ -0,0 +1,398 @@ +#include +#include +#include + +#include +#include + +#include "common.h" +#include "config.h" + +/** + * Wrapper of libconfig's config_lookup_int. + * + * To convert int value config_lookup_bool + * returns to bool. + */ +static inline void +lcfg_lookup_bool(const config_t *config, const char *path, + bool *value) { + int ival; + + if (config_lookup_bool(config, path, &ival)) + *value = ival; +} + +/** + * Wrapper of libconfig's config_lookup_int. + * + * To deal with the different value types config_lookup_int + * returns in libconfig-1.3 and libconfig-1.4. + */ +static inline int +lcfg_lookup_int(const config_t *config, const char *path, int *value) { + return config_lookup_int(config, path, value); +} + +/** + * 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) { + const static char *config_filename = "/compton.conf"; + const static char *config_filename_legacy = "/.compton.conf"; + const static char *config_home_suffix = "/.config"; + const static 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; + 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 (lcfg_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) + lcfg_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) + lcfg_lookup_int(&cfg, "shadow-offset-x", &ps->o.shadow_offset_x); + // -t (shadow_offset_y) + lcfg_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); + // -z (clear_shadow) + lcfg_lookup_bool(&cfg, "clear-shadow", &ps->o.clear_shadow); + // -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) + && !parse_geometry(ps, sval, &ps->o.shadow_exclude_reg_geom)) + exit(1); + // --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 + lcfg_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); + // --alpha-step + config_lookup_float(&cfg, "alpha-step", &ps->o.alpha_step); + // --dbe + lcfg_lookup_bool(&cfg, "dbe", &ps->o.dbe); + // --paint-on-overlay + lcfg_lookup_bool(&cfg, "paint-on-overlay", &ps->o.paint_on_overlay); + // --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 (lcfg_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 + lcfg_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-copy-from-front + lcfg_lookup_bool(&cfg, "glx-copy-from-front", &ps->o.glx_copy_from_front); + // --glx-use-copysubbuffermesa + lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &ps->o.glx_use_copysubbuffermesa); + // --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); + // Wintype settings + + 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; + + double fval; + if (config_setting_lookup_float(setting, "opacity", &fval)) + ps->o.wintype_opacity[i] = normalize_d(fval); + } + } + + config_destroy(&cfg); +} diff --git a/src/opengl.c b/src/opengl.c index 3707b14..700ce9d 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -29,6 +29,7 @@ xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) { } #endif +#ifdef DEBUG_GLX_DEBUG_CONTEXT static inline GLXFBConfig get_fbconfig_from_visualinfo(session_t *ps, const XVisualInfo *visualinfo) { int nelements = 0; @@ -44,7 +45,6 @@ get_fbconfig_from_visualinfo(session_t *ps, const XVisualInfo *visualinfo) { return NULL; } -#ifdef DEBUG_GLX_DEBUG_CONTEXT static void glx_debug_msg_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message,