Feature #113: Set opacity based on conditions
- Add --opacity-rule, which sets opacity based on conditions, as requested by zabbal. (#113) - Add a data field for each condition. - Correct the FAQ link in README.md. Silly me. - Code clean-up.
This commit is contained in:
parent
07bc7485c3
commit
75ebd56f74
|
@ -77,7 +77,7 @@ $ make install
|
||||||
|
|
||||||
## Known issues
|
## 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.
|
* 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.
|
||||||
|
|
||||||
|
|
16
src/c2.c
16
src/c2.c
|
@ -14,7 +14,8 @@
|
||||||
* Parse a condition string.
|
* Parse a condition string.
|
||||||
*/
|
*/
|
||||||
c2_lptr_t *
|
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)
|
if (!pattern)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) {
|
||||||
" list element.");
|
" list element.");
|
||||||
memcpy(plptr, &lptr_def, sizeof(c2_lptr_t));
|
memcpy(plptr, &lptr_def, sizeof(c2_lptr_t));
|
||||||
plptr->ptr = result;
|
plptr->ptr = result;
|
||||||
|
plptr->data = data;
|
||||||
if (pcondlst) {
|
if (pcondlst) {
|
||||||
plptr->next = *pcondlst;
|
plptr->next = *pcondlst;
|
||||||
*pcondlst = plptr;
|
*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.
|
* Match a window against a condition linked list.
|
||||||
*
|
*
|
||||||
* @param cache a place to cache the last matched condition
|
* @param cache a place to cache the last matched condition
|
||||||
|
* @param pdata a place to return the data
|
||||||
* @return true if matched, false otherwise.
|
* @return true if matched, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
c2_match(session_t *ps, win *w, const c2_lptr_t *condlst,
|
c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
|
||||||
const c2_lptr_t **cache) {
|
const c2_lptr_t **cache, void **pdata) {
|
||||||
// Check if the cached entry matches firstly
|
// 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;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Then go through the whole linked list
|
// Then go through the whole linked list
|
||||||
for (; condlst; condlst = condlst->next) {
|
for (; condlst; condlst = condlst->next) {
|
||||||
if (c2_match_once(ps, w, condlst->ptr)) {
|
if (c2_match_once(ps, w, condlst->ptr)) {
|
||||||
if (cache)
|
if (cache)
|
||||||
*cache = condlst;
|
*cache = condlst;
|
||||||
|
if (pdata)
|
||||||
|
*pdata = condlst->data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
src/c2.h
2
src/c2.h
|
@ -156,12 +156,14 @@ const static c2_l_t leaf_def = C2_L_INIT;
|
||||||
/// Linked list type of conditions.
|
/// Linked list type of conditions.
|
||||||
struct _c2_lptr {
|
struct _c2_lptr {
|
||||||
c2_ptr_t ptr;
|
c2_ptr_t ptr;
|
||||||
|
void *data;
|
||||||
struct _c2_lptr *next;
|
struct _c2_lptr *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initializer for c2_lptr_t.
|
/// Initializer for c2_lptr_t.
|
||||||
#define C2_LPTR_INIT { \
|
#define C2_LPTR_INIT { \
|
||||||
.ptr = C2_PTR_INIT, \
|
.ptr = C2_PTR_INIT, \
|
||||||
|
.data = NULL, \
|
||||||
.next = NULL, \
|
.next = NULL, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/common.h
17
src/common.h
|
@ -546,6 +546,8 @@ typedef struct {
|
||||||
bool inactive_dim_fixed;
|
bool inactive_dim_fixed;
|
||||||
/// Conditions of windows to have inverted colors.
|
/// Conditions of windows to have inverted colors.
|
||||||
c2_lptr_t *invert_color_list;
|
c2_lptr_t *invert_color_list;
|
||||||
|
/// Rules to change window opacity.
|
||||||
|
c2_lptr_t *opacity_rules;
|
||||||
|
|
||||||
// === Focus related ===
|
// === Focus related ===
|
||||||
/// Consider windows of specific types to be always focused.
|
/// 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_fcblst;
|
||||||
const c2_lptr_t *cache_ivclst;
|
const c2_lptr_t *cache_ivclst;
|
||||||
const c2_lptr_t *cache_bbblst;
|
const c2_lptr_t *cache_bbblst;
|
||||||
|
const c2_lptr_t *cache_oparule;
|
||||||
|
|
||||||
// Opacity-related members
|
// Opacity-related members
|
||||||
/// Current window opacity.
|
/// Current window opacity.
|
||||||
|
@ -933,6 +936,8 @@ typedef struct _win {
|
||||||
/// broken window managers not transferring client window's
|
/// broken window managers not transferring client window's
|
||||||
/// _NET_WM_OPACITY value
|
/// _NET_WM_OPACITY value
|
||||||
opacity_t opacity_prop_client;
|
opacity_t opacity_prop_client;
|
||||||
|
/// Last window opacity value we set.
|
||||||
|
long opacity_set;
|
||||||
|
|
||||||
// Fading-related members
|
// Fading-related members
|
||||||
/// Do not fade if it's false. Change on window type change.
|
/// 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_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_lptr_t *
|
||||||
c2_free_lptr(c2_lptr_t *lp);
|
c2_free_lptr(c2_lptr_t *lp);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
c2_match(session_t *ps, win *w, const c2_lptr_t *condlst,
|
c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
|
||||||
const c2_lptr_t **cache);
|
const c2_lptr_t **cache, void **pdata);
|
||||||
|
|
||||||
|
#define c2_match(ps, w, condlst, cache) c2_matchd((ps), (w), (condlst), \
|
||||||
|
(cache), NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
|
@ -2426,6 +2426,28 @@ win_determine_blur_background(session_t *ps, win *w) {
|
||||||
add_damage_win(ps, 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.
|
* 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);
|
win_update_focused(ps, w);
|
||||||
if (ps->o.invert_color_list)
|
if (ps->o.invert_color_list)
|
||||||
win_determine_invert_color(ps, w);
|
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);
|
win_update_focused(ps, w);
|
||||||
if (ps->o.blur_background_blacklist)
|
if (ps->o.blur_background_blacklist)
|
||||||
win_determine_blur_background(ps, w);
|
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_fcblst = NULL,
|
||||||
.cache_ivclst = NULL,
|
.cache_ivclst = NULL,
|
||||||
.cache_bbblst = NULL,
|
.cache_bbblst = NULL,
|
||||||
|
.cache_oparule = NULL,
|
||||||
|
|
||||||
.opacity = 0,
|
.opacity = 0,
|
||||||
.opacity_tgt = 0,
|
.opacity_tgt = 0,
|
||||||
.opacity_prop = OPAQUE,
|
.opacity_prop = OPAQUE,
|
||||||
.opacity_prop_client = OPAQUE,
|
.opacity_prop_client = OPAQUE,
|
||||||
|
.opacity_set = OPAQUE,
|
||||||
|
|
||||||
.fade = false,
|
.fade = false,
|
||||||
.fade_force = UNSET,
|
.fade_force = UNSET,
|
||||||
|
@ -4351,6 +4379,12 @@ usage(int ret) {
|
||||||
"--invert-color-include condition\n"
|
"--invert-color-include condition\n"
|
||||||
" Specify a list of conditions of windows that should be painted with\n"
|
" Specify a list of conditions of windows that should be painted with\n"
|
||||||
" inverted color. Resource-hogging, and is not well tested.\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"
|
"--backend backend\n"
|
||||||
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
|
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
|
||||||
"--glx-no-stencil\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);
|
return parse_matrix(ps, src, endptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a list of convolution kernels.
|
||||||
|
*/
|
||||||
static bool
|
static bool
|
||||||
parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) {
|
parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) {
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@ -4682,6 +4719,37 @@ parse_conv_kern_lst(session_t *ps, const char *src, XFixed **dest, int max) {
|
||||||
return true;
|
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
|
#ifdef CONFIG_LIBCONFIG
|
||||||
/**
|
/**
|
||||||
* Get a file stream of the configuration file to read.
|
* 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 },
|
{ "blur-kern", required_argument, NULL, 301 },
|
||||||
{ "resize-damage", required_argument, NULL, 302 },
|
{ "resize-damage", required_argument, NULL, 302 },
|
||||||
{ "glx-use-gpushader4", no_argument, NULL, 303 },
|
{ "glx-use-gpushader4", no_argument, NULL, 303 },
|
||||||
|
{ "opacity-rule", required_argument, NULL, 304 },
|
||||||
// Must terminate with a NULL entry
|
// Must terminate with a NULL entry
|
||||||
{ NULL, 0, NULL, 0 },
|
{ 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);
|
ps->o.resize_damage = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
P_CASEBOOL(303, glx_use_gpushader4);
|
P_CASEBOOL(303, glx_use_gpushader4);
|
||||||
|
case 304:
|
||||||
|
// --opacity-rule
|
||||||
|
if (!parse_rule_opacity(ps, optarg))
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(1);
|
usage(1);
|
||||||
break;
|
break;
|
||||||
|
@ -6216,6 +6290,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
||||||
.inactive_dim = 0.0,
|
.inactive_dim = 0.0,
|
||||||
.inactive_dim_fixed = false,
|
.inactive_dim_fixed = false,
|
||||||
.invert_color_list = NULL,
|
.invert_color_list = NULL,
|
||||||
|
.opacity_rules = NULL,
|
||||||
|
|
||||||
.wintype_focus = { false },
|
.wintype_focus = { false },
|
||||||
.use_ewmh_active_win = 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.focus_blacklist);
|
||||||
free_wincondlst(&ps->o.invert_color_list);
|
free_wincondlst(&ps->o.invert_color_list);
|
||||||
free_wincondlst(&ps->o.blur_background_blacklist);
|
free_wincondlst(&ps->o.blur_background_blacklist);
|
||||||
|
free_wincondlst(&ps->o.opacity_rules);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Free tracked atom list
|
// Free tracked atom list
|
||||||
|
|
|
@ -415,6 +415,17 @@ win_has_frame(const win *w) {
|
||||||
|| w->top_width || w->left_width || w->right_width || w->bottom_width;
|
|| 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.
|
* Dump an drawable's info.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue