diff --git a/README.md b/README.md index 00eae45..1c6c111 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ $ make install ## Known issues -* Our [FAQ](https://github.com/chjj/compton/wiki/vsync-guide) covers some known issues. +* Our [FAQ](https://github.com/chjj/compton/wiki/faq) covers some known issues. * VSync does not work too well. You may check the [VSync Guide](https://github.com/chjj/compton/wiki/vsync-guide) for how to get (possibly) better effects. diff --git a/src/c2.c b/src/c2.c index 13c1940..bd28627 100644 --- a/src/c2.c +++ b/src/c2.c @@ -14,7 +14,8 @@ * Parse a condition string. */ c2_lptr_t * -c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) { +c2_parsed(session_t *ps, c2_lptr_t **pcondlst, const char *pattern, + void *data) { if (!pattern) return NULL; @@ -41,6 +42,7 @@ c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) { " list element."); memcpy(plptr, &lptr_def, sizeof(c2_lptr_t)); plptr->ptr = result; + plptr->data = data; if (pcondlst) { plptr->next = *pcondlst; *pcondlst = plptr; @@ -1274,20 +1276,26 @@ c2_match_once(session_t *ps, win *w, const c2_ptr_t cond) { * Match a window against a condition linked list. * * @param cache a place to cache the last matched condition + * @param pdata a place to return the data * @return true if matched, false otherwise. */ bool -c2_match(session_t *ps, win *w, const c2_lptr_t *condlst, - const c2_lptr_t **cache) { +c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst, + const c2_lptr_t **cache, void **pdata) { // Check if the cached entry matches firstly - if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) + if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) { + if (pdata) + *pdata = (*cache)->data; return true; + } // Then go through the whole linked list for (; condlst; condlst = condlst->next) { if (c2_match_once(ps, w, condlst->ptr)) { if (cache) *cache = condlst; + if (pdata) + *pdata = condlst->data; return true; } } diff --git a/src/c2.h b/src/c2.h index c794da1..b26a687 100644 --- a/src/c2.h +++ b/src/c2.h @@ -156,12 +156,14 @@ const static c2_l_t leaf_def = C2_L_INIT; /// Linked list type of conditions. struct _c2_lptr { c2_ptr_t ptr; + void *data; struct _c2_lptr *next; }; /// Initializer for c2_lptr_t. #define C2_LPTR_INIT { \ .ptr = C2_PTR_INIT, \ + .data = NULL, \ .next = NULL, \ } diff --git a/src/common.h b/src/common.h index cab29f7..0b97d50 100644 --- a/src/common.h +++ b/src/common.h @@ -546,6 +546,8 @@ typedef struct { bool inactive_dim_fixed; /// Conditions of windows to have inverted colors. c2_lptr_t *invert_color_list; + /// Rules to change window opacity. + c2_lptr_t *opacity_rules; // === Focus related === /// Consider windows of specific types to be always focused. @@ -921,6 +923,7 @@ typedef struct _win { const c2_lptr_t *cache_fcblst; const c2_lptr_t *cache_ivclst; const c2_lptr_t *cache_bbblst; + const c2_lptr_t *cache_oparule; // Opacity-related members /// Current window opacity. @@ -933,6 +936,8 @@ typedef struct _win { /// broken window managers not transferring client window's /// _NET_WM_OPACITY value opacity_t opacity_prop_client; + /// Last window opacity value we set. + long opacity_set; // Fading-related members /// Do not fade if it's false. Change on window type change. @@ -2027,14 +2032,20 @@ opts_set_no_fading_openclose(session_t *ps, bool newval); ///@{ c2_lptr_t * -c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern); +c2_parsed(session_t *ps, c2_lptr_t **pcondlst, const char *pattern, + void *data); + +#define c2_parse(ps, pcondlst, pattern) c2_parsed((ps), (pcondlst), (pattern), NULL) c2_lptr_t * c2_free_lptr(c2_lptr_t *lp); bool -c2_match(session_t *ps, win *w, const c2_lptr_t *condlst, - const c2_lptr_t **cache); +c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst, + const c2_lptr_t **cache, void **pdata); + +#define c2_match(ps, w, condlst, cache) c2_matchd((ps), (w), (condlst), \ + (cache), NULL) #endif ///@} diff --git a/src/compton.c b/src/compton.c index f058bf9..c55d045 100644 --- a/src/compton.c +++ b/src/compton.c @@ -2426,6 +2426,28 @@ win_determine_blur_background(session_t *ps, win *w) { add_damage_win(ps, w); } +/** + * Update window opacity according to opacity rules. + */ +static void +win_update_opacity_rule(session_t *ps, win *w) { + // If long is 32-bit, unfortunately there's no way could we express "unset", + // so we just entirely don't distinguish "unset" and OPAQUE + long opacity = OPAQUE; + void *val = NULL; + if (c2_matchd(ps, w, ps->o.opacity_rules, &w->cache_oparule, &val)) + opacity = ((double) (long) val) / 100.0 * OPAQUE; + + if (opacity == w->opacity_set) + return; + + if (OPAQUE != opacity) + wid_set_opacity_prop(ps, w->id, opacity); + else if (OPAQUE != w->opacity_set) + wid_rm_opacity_prop(ps, w->id); + w->opacity_set = opacity; +} + /** * Function to be called on window type changes. */ @@ -2436,6 +2458,8 @@ win_on_wtype_change(session_t *ps, win *w) { win_update_focused(ps, w); if (ps->o.invert_color_list) win_determine_invert_color(ps, w); + if (ps->o.opacity_rules) + win_update_opacity_rule(ps, w); } /** @@ -2453,6 +2477,8 @@ win_on_factor_change(session_t *ps, win *w) { win_update_focused(ps, w); if (ps->o.blur_background_blacklist) win_determine_blur_background(ps, w); + if (ps->o.opacity_rules) + win_update_opacity_rule(ps, w); } /** @@ -2670,11 +2696,13 @@ add_win(session_t *ps, Window id, Window prev) { .cache_fcblst = NULL, .cache_ivclst = NULL, .cache_bbblst = NULL, + .cache_oparule = NULL, .opacity = 0, .opacity_tgt = 0, .opacity_prop = OPAQUE, .opacity_prop_client = OPAQUE, + .opacity_set = OPAQUE, .fade = false, .fade_force = UNSET, @@ -4351,6 +4379,12 @@ usage(int ret) { "--invert-color-include condition\n" " Specify a list of conditions of windows that should be painted with\n" " inverted color. Resource-hogging, and is not well tested.\n" + "--opacity-rule opacity:condition\n" + " Specify a list of opacity rules, in the format \"PERCENT:PATTERN\",\n" + " like \'50:name *= \"Firefox\"'. compton-trans is recommended over\n" + " this. Note we do not distinguish 100% and unset, and we don't make\n" + " any guarantee about possible conflicts with other programs that set\n" + " _NET_WM_WINDOW_OPACITY on frame or client windows.\n" "--backend backend\n" " Choose backend. Possible choices are xrender and glx" WARNING ".\n" "--glx-no-stencil\n" @@ -4638,6 +4672,9 @@ 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 { @@ -4682,6 +4719,37 @@ parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) { return true; } +/** + * Parse a list of opacity rules. + */ +static inline 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); +} + #ifdef CONFIG_LIBCONFIG /** * Get a file stream of the configuration file to read. @@ -5049,6 +5117,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { { "blur-kern", required_argument, NULL, 301 }, { "resize-damage", required_argument, NULL, 302 }, { "glx-use-gpushader4", no_argument, NULL, 303 }, + { "opacity-rule", required_argument, NULL, 304 }, // Must terminate with a NULL entry { NULL, 0, NULL, 0 }, }; @@ -5282,6 +5351,11 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) { ps->o.resize_damage = atoi(optarg); break; P_CASEBOOL(303, glx_use_gpushader4); + case 304: + // --opacity-rule + if (!parse_rule_opacity(ps, optarg)) + exit(1); + break; default: usage(1); break; @@ -6216,6 +6290,7 @@ session_init(session_t *ps_old, int argc, char **argv) { .inactive_dim = 0.0, .inactive_dim_fixed = false, .invert_color_list = NULL, + .opacity_rules = NULL, .wintype_focus = { false }, .use_ewmh_active_win = false, @@ -6635,6 +6710,7 @@ session_destroy(session_t *ps) { free_wincondlst(&ps->o.focus_blacklist); free_wincondlst(&ps->o.invert_color_list); free_wincondlst(&ps->o.blur_background_blacklist); + free_wincondlst(&ps->o.opacity_rules); #endif // Free tracked atom list diff --git a/src/compton.h b/src/compton.h index b3695af..334e737 100644 --- a/src/compton.h +++ b/src/compton.h @@ -415,6 +415,17 @@ win_has_frame(const win *w) { || w->top_width || w->left_width || w->right_width || w->bottom_width; } +static inline void +wid_set_opacity_prop(session_t *ps, Window wid, long val) { + XChangeProperty(ps->dpy, wid, ps->atom_opacity, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) &val, 1); +} + +static inline void +wid_rm_opacity_prop(session_t *ps, Window wid) { + XDeleteProperty(ps->dpy, wid, ps->atom_opacity); +} + /** * Dump an drawable's info. */