summaryrefslogtreecommitdiffstats
path: root/compton.c
diff options
context:
space:
mode:
authorRichard Grenville <[email protected]>2013-01-28 21:39:38 +0800
committerRichard Grenville <[email protected]>2013-01-28 21:39:38 +0800
commit679bfe3cab740f06b38f606d599304f515b9de4d (patch)
treef5112867914ecf0e32101f4659e0f9db78395fd5 /compton.c
parent56a35506b1f65bd36e4f5b30054b348eea79f515 (diff)
downloadtdebase-679bfe3cab740f06b38f606d599304f515b9de4d.tar.gz
tdebase-679bfe3cab740f06b38f606d599304f515b9de4d.zip
Feature #16: Advanced window matching
- Add advanced window matching system, capable of matching against arbitrary window properties as well as a series of internal properties, with 4 additional operators (>, <, >=, <=) useful for integer targets, and support of logical operators. The old matching system is removed, but compatibility with the format is retained. - As the new matching system is pretty complicated, and I have no past experience in writing a parser, it's pretty possible that bugs are present. It also has inferior performance, but I hope it doesn't matter on modern CPUs. - It's possible to disable matching system at compile time with NO_C2=1 now. - Add ps->o.config_file to track which config file we have actually read. Queryable via D-Bus. - Parse -d in first pass in get_cfg() as c2 needs to query X to get atoms during condition parsing. - Fix a bug in wid_get_prop_adv() that 0 == rformat is not handled correctly. - Fix incompatibility with FreeBSD sed in dbus-examples/cdbus-driver.sh . - Add recipe to generate .clang_complete in Makefile, used by Vim clang_complete plugin. - Add DEBUG_C2 for debugging condition string parsing. DEBUG_WINMATCH is still used for match debugging. - Rename win_on_wdata_change() to win_on_factor_change(). - Extra malloc() failure checks. Add const to matching cache members in session_t. Code clean-up. Documentation update.
Diffstat (limited to 'compton.c')
-rw-r--r--compton.c396
1 files changed, 91 insertions, 305 deletions
diff --git a/compton.c b/compton.c
index 814bf4a3b..cbb5e7b61 100644
--- a/compton.c
+++ b/compton.c
@@ -567,7 +567,7 @@ wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
if (Success == XGetWindowProperty(ps->dpy, w, atom, offset, length,
False, rtype, &type, &format, &nitems, &after, &data)
&& nitems && (AnyPropertyType == type || type == rtype)
- && (!format || format == rformat)
+ && (!rformat || format == rformat)
&& (8 == format || 16 == format || 32 == format)) {
return (winprop_t) {
.data.p8 = data,
@@ -630,243 +630,19 @@ win_rounded_corners(session_t *ps, win *w) {
}
/**
- * Match a window against a single window condition.
- *
- * @return true if matched, false otherwise.
- */
-static bool
-win_match_once(win *w, const wincond_t *cond) {
- const char *target;
- bool matched = false;
-
-#ifdef DEBUG_WINMATCH
- printf("win_match_once(%#010lx \"%s\"): cond = %p", w->id, w->name,
- cond);
-#endif
-
- if (InputOnly == w->a.class) {
-#ifdef DEBUG_WINMATCH
- printf(": InputOnly\n");
-#endif
- return false;
- }
-
- // Determine the target
- target = NULL;
- switch (cond->target) {
- case CONDTGT_NAME:
- target = w->name;
- break;
- case CONDTGT_CLASSI:
- target = w->class_instance;
- break;
- case CONDTGT_CLASSG:
- target = w->class_general;
- break;
- case CONDTGT_ROLE:
- target = w->role;
- break;
- }
-
- if (!target) {
-#ifdef DEBUG_WINMATCH
- printf(": Target not found\n");
-#endif
- return false;
- }
-
- // Determine pattern type and match
- switch (cond->type) {
- case CONDTP_EXACT:
- if (cond->flags & CONDF_IGNORECASE)
- matched = !strcasecmp(target, cond->pattern);
- else
- matched = !strcmp(target, cond->pattern);
- break;
- case CONDTP_ANYWHERE:
- if (cond->flags & CONDF_IGNORECASE)
- matched = strcasestr(target, cond->pattern);
- else
- matched = strstr(target, cond->pattern);
- break;
- case CONDTP_FROMSTART:
- if (cond->flags & CONDF_IGNORECASE)
- matched = !strncasecmp(target, cond->pattern,
- strlen(cond->pattern));
- else
- matched = !strncmp(target, cond->pattern,
- strlen(cond->pattern));
- break;
- case CONDTP_WILDCARD:
- {
- int flags = 0;
- if (cond->flags & CONDF_IGNORECASE)
- flags = FNM_CASEFOLD;
- matched = !fnmatch(cond->pattern, target, flags);
- }
- break;
- case CONDTP_REGEX_PCRE:
-#ifdef CONFIG_REGEX_PCRE
- matched = (pcre_exec(cond->regex_pcre, cond->regex_pcre_extra,
- target, strlen(target), 0, 0, NULL, 0) >= 0);
-#endif
- break;
- }
-
-#ifdef DEBUG_WINMATCH
- printf(", matched = %d\n", matched);
-#endif
-
- return matched;
-}
-
-/**
- * Match a window against a condition linked list.
- *
- * @param cache a place to cache the last matched condition
- * @return true if matched, false otherwise.
- */
-static bool
-win_match(win *w, wincond_t *condlst, wincond_t **cache) {
- // Check if the cached entry matches firstly
- if (cache && *cache && win_match_once(w, *cache))
- return true;
-
- // Then go through the whole linked list
- for (; condlst; condlst = condlst->next) {
- if (win_match_once(w, condlst)) {
- if (cache)
- *cache = condlst;
- return true;
- }
- }
-
- return false;
-}
-
-/**
* Add a pattern to a condition linked list.
*/
static bool
-condlst_add(wincond_t **pcondlst, const char *pattern) {
+condlst_add(session_t *ps, c2_lptr_t **pcondlst, const char *pattern) {
if (!pattern)
return false;
- unsigned plen = strlen(pattern);
- wincond_t *cond;
- const char *pos;
-
- if (plen < 4 || ':' != pattern[1] || !strchr(pattern + 2, ':')) {
- printf("Pattern \"%s\": Format invalid.\n", pattern);
- return false;
- }
-
- // Allocate memory for the new condition
- cond = malloc(sizeof(wincond_t));
-
- // Determine the pattern target
- switch (pattern[0]) {
- case 'n':
- cond->target = CONDTGT_NAME;
- break;
- case 'i':
- cond->target = CONDTGT_CLASSI;
- break;
- case 'g':
- cond->target = CONDTGT_CLASSG;
- break;
- case 'r':
- cond->target = CONDTGT_ROLE;
- break;
- default:
- printf("Pattern \"%s\": Target \"%c\" invalid.\n",
- pattern, pattern[0]);
- free(cond);
- return false;
- }
-
- // Determine the pattern type
- switch (pattern[2]) {
- case 'e':
- cond->type = CONDTP_EXACT;
- break;
- case 'a':
- cond->type = CONDTP_ANYWHERE;
- break;
- case 's':
- cond->type = CONDTP_FROMSTART;
- break;
- case 'w':
- cond->type = CONDTP_WILDCARD;
- break;
-#ifdef CONFIG_REGEX_PCRE
- case 'p':
- cond->type = CONDTP_REGEX_PCRE;
- break;
-#endif
- default:
- printf("Pattern \"%s\": Type \"%c\" invalid.\n",
- pattern, pattern[2]);
- free(cond);
- return false;
- }
-
- // Determine the pattern flags
- pos = &pattern[3];
- cond->flags = 0;
- while (':' != *pos) {
- switch (*pos) {
- case 'i':
- cond->flags |= CONDF_IGNORECASE;
- break;
- default:
- printf("Pattern \"%s\": Flag \"%c\" invalid.\n",
- pattern, *pos);
- break;
- }
- ++pos;
- }
-
- // Copy the pattern
- ++pos;
- cond->pattern = NULL;
-#ifdef CONFIG_REGEX_PCRE
- cond->regex_pcre = NULL;
- cond->regex_pcre_extra = NULL;
-#endif
- if (CONDTP_REGEX_PCRE == cond->type) {
-#ifdef CONFIG_REGEX_PCRE
- const char *error = NULL;
- int erroffset = 0;
- int options = 0;
-
- if (cond->flags & CONDF_IGNORECASE)
- options |= PCRE_CASELESS;
-
- cond->regex_pcre = pcre_compile(pos, options, &error, &erroffset,
- NULL);
- if (!cond->regex_pcre) {
- printf("Pattern \"%s\": PCRE regular expression parsing failed on "
- "offset %d: %s\n", pattern, erroffset, error);
- free(cond);
- return false;
- }
-#ifdef CONFIG_REGEX_PCRE_JIT
- cond->regex_pcre_extra = pcre_study(cond->regex_pcre, PCRE_STUDY_JIT_COMPILE, &error);
- if (!cond->regex_pcre_extra) {
- printf("Pattern \"%s\": PCRE regular expression study failed: %s",
- pattern, error);
- }
-#endif
+#ifdef CONFIG_C2
+ if (!c2_parse(ps, pcondlst, pattern))
+ exit(1);
+#else
+ printf_errfq(1, "(): Condition support not compiled in.");
#endif
- }
- else {
- cond->pattern = mstrcpy(pos);
- }
-
- // Insert it into the linked list
- cond->next = *pcondlst;
- *pcondlst = cond;
return true;
}
@@ -2313,7 +2089,7 @@ win_determine_shadow(session_t *ps, win *w) {
w->shadow = (UNSET == w->shadow_force ?
(ps->o.wintype_shadow[w->window_type]
- && !win_match(w, ps->o.shadow_blacklist, &w->cache_sblst)
+ && !win_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst)
&& !(ps->o.shadow_ignore_shaped && w->bounding_shaped
&& !w->rounded_corners)
&& !(ps->o.respect_prop_shadow && 0 == w->prop_shadow))
@@ -2347,7 +2123,7 @@ win_determine_invert_color(session_t *ps, win *w) {
if (UNSET != w->invert_color_force)
w->invert_color = w->invert_color_force;
else
- w->invert_color = win_match(w, ps->o.invert_color_list, &w->cache_ivclst);
+ w->invert_color = win_match(ps, w, ps->o.invert_color_list, &w->cache_ivclst);
if (w->invert_color != invert_color_old)
add_damage_win(ps, w);
@@ -2361,13 +2137,15 @@ win_on_wtype_change(session_t *ps, win *w) {
win_determine_shadow(ps, w);
win_determine_fade(ps, w);
win_update_focused(ps, w);
+ if (ps->o.invert_color_list)
+ win_determine_invert_color(ps, w);
}
/**
* Function to be called on window data changes.
*/
static void
-win_on_wdata_change(session_t *ps, win *w) {
+win_on_factor_change(session_t *ps, win *w) {
if (ps->o.shadow_blacklist)
win_determine_shadow(ps, w);
if (ps->o.fade_blacklist)
@@ -2481,9 +2259,11 @@ win_mark_client(session_t *ps, win *w, Window client) {
win_get_name(ps, w);
win_get_class(ps, w);
win_get_role(ps, w);
- win_on_wdata_change(ps, w);
}
+ // Update everything related to conditions
+ win_on_factor_change(ps, w);
+
// Update window focus state
win_update_focused(ps, w);
}
@@ -3048,7 +2828,7 @@ win_update_focused(session_t *ps, win *w) {
|| (ps->o.mark_wmwin_focused && w->wmwin)
|| (ps->o.mark_ovredir_focused
&& w->id == w->client_win && !w->wmwin)
- || win_match(w, ps->o.focus_blacklist, &w->cache_fcblst))
+ || win_match(ps, w, ps->o.focus_blacklist, &w->cache_fcblst))
w->focused = true;
// If window grouping detection is enabled, mark the window active if
@@ -3102,6 +2882,9 @@ win_set_focused(session_t *ps, win *w, bool focused) {
else {
win_update_focused(ps, w);
}
+
+ // Update everything related to conditions
+ win_on_factor_change(ps, w);
}
}
/**
@@ -3153,6 +2936,9 @@ win_set_leader(session_t *ps, win *w, Window nleader) {
else {
win_update_focused(ps, w);
}
+
+ // Update everything related to conditions
+ win_on_factor_change(ps, w);
}
}
@@ -3746,7 +3532,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
&& (ps->atom_name == ev->atom || ps->atom_name_ewmh == ev->atom)) {
win *w = find_toplevel(ps, ev->window);
if (w && 1 == win_get_name(ps, w)) {
- win_on_wdata_change(ps, w);
+ win_on_factor_change(ps, w);
}
}
@@ -3755,7 +3541,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
win *w = find_toplevel(ps, ev->window);
if (w) {
win_get_class(ps, w);
- win_on_wdata_change(ps, w);
+ win_on_factor_change(ps, w);
}
}
@@ -3763,7 +3549,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
if (ps->o.track_wdata && ps->atom_role == ev->atom) {
win *w = find_toplevel(ps, ev->window);
if (w && 1 == win_get_role(ps, w)) {
- win_on_wdata_change(ps, w);
+ win_on_factor_change(ps, w);
}
}
@@ -3790,7 +3576,7 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
if (!w)
w = find_toplevel(ps, ev->window);
if (w)
- win_on_wdata_change(ps, w);
+ win_on_factor_change(ps, w);
break;
}
}
@@ -4095,24 +3881,7 @@ usage(void) {
" inverted color. Resource-hogging, and is not well tested.\n"
"--dbus\n"
" Enable remote control via D-Bus. See the D-BUS API section in the\n"
- " man page for more details.\n"
- "\n"
- "Format of a condition:\n"
- "\n"
- " condition = <target>:<type>[<flags>]:<pattern>\n"
- "\n"
- " <target> is one of \"n\" (window name), \"i\" (window class\n"
- " instance), \"g\" (window general class), and \"r\"\n"
- " (window role).\n"
- "\n"
- " <type> is one of \"e\" (exact match), \"a\" (match anywhere),\n"
- " \"s\" (match from start), \"w\" (wildcard), and \"p\" (PCRE\n"
- " regular expressions, if compiled with the support).\n"
- "\n"
- " <flags> could be a series of flags. Currently the only defined\n"
- " flag is \"i\" (ignore case).\n"
- "\n"
- " <pattern> is the actual pattern string.\n";
+ " man page for more details.\n";
fputs(usage_text , stderr);
exit(1);
@@ -4270,8 +4039,6 @@ open_config_file(char *cpath, char **ppath) {
f = fopen(path, "r");
if (f && ppath)
*ppath = path;
- else
- free(path);
return f;
}
@@ -4356,7 +4123,7 @@ parse_vsync(session_t *ps, const char *optarg) {
* Parse a condition list in configuration file.
*/
static void
-parse_cfg_condlst(const config_t *pcfg, wincond_t **pcondlst,
+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) {
@@ -4364,12 +4131,12 @@ parse_cfg_condlst(const config_t *pcfg, wincond_t **pcondlst,
if (config_setting_is_array(setting)) {
int i = config_setting_length(setting);
while (i--) {
- condlst_add(pcondlst, config_setting_get_string_elem(setting, 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(pcondlst, config_setting_get_string(setting));
+ condlst_add(ps, pcondlst, config_setting_get_string(setting));
}
}
}
@@ -4378,7 +4145,7 @@ parse_cfg_condlst(const config_t *pcfg, wincond_t **pcondlst,
* Parse a configuration file from default location.
*/
static void
-parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
+parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
char *path = NULL;
FILE *f;
config_t cfg;
@@ -4386,10 +4153,14 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
double dval = 0.0;
const char *sval = NULL;
- f = open_config_file(cpath, &path);
+ f = open_config_file(ps->o.config_file, &path);
if (!f) {
- if (cpath)
- printf_errfq(1, "(): Failed to read the specified configuration file.");
+ 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;
}
@@ -4417,7 +4188,10 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
}
config_set_auto_convert(&cfg, 1);
- free(path);
+ 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
@@ -4512,11 +4286,11 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
lcfg_lookup_bool(&cfg, "detect-client-leader",
&ps->o.detect_client_leader);
// --shadow-exclude
- parse_cfg_condlst(&cfg, &ps->o.shadow_blacklist, "shadow-exclude");
+ parse_cfg_condlst(ps, &cfg, &ps->o.shadow_blacklist, "shadow-exclude");
// --focus-exclude
- parse_cfg_condlst(&cfg, &ps->o.focus_blacklist, "focus-exclude");
+ parse_cfg_condlst(ps, &cfg, &ps->o.focus_blacklist, "focus-exclude");
// --invert-color-include
- parse_cfg_condlst(&cfg, &ps->o.invert_color_list, "invert-color-include");
+ parse_cfg_condlst(ps, &cfg, &ps->o.invert_color_list, "invert-color-include");
// --blur-background
lcfg_lookup_bool(&cfg, "blur-background", &ps->o.blur_background);
// --blur-background-frame
@@ -4554,7 +4328,7 @@ parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp) {
* Process arguments and configuration files.
*/
static void
-get_cfg(session_t *ps, int argc, char *const *argv) {
+get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
const static char *shortopts = "D:I:O:d:r:o:m:l:t:i:e:hscnfFCaSzGb";
const static struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
@@ -4595,14 +4369,33 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
{ NULL, 0, NULL, 0 },
};
+ int o = 0, longopt_idx = -1, i = 0;
+
+ if (first_pass) {
+ // Pre-parse the commandline arguments to check for --config and invalid
+ // switches
+ // Must reset optind to 0 here in case we reread the commandline
+ // arguments
+ optind = 1;
+ while (-1 !=
+ (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
+ if (256 == o)
+ ps->o.config_file = mstrcpy(optarg);
+ else if ('d' == o)
+ ps->o.display = mstrcpy(optarg);
+ else if ('?' == o || ':' == o)
+ usage();
+ }
+
+ return;
+ }
+
struct options_tmp cfgtmp = {
.no_dock_shadow = false,
.no_dnd_shadow = false,
.menu_opacity = 1.0,
};
bool shadow_enable = false, fading_enable = false;
- int o, longopt_idx, i;
- char *config_file = NULL;
char *lc_numeric_old = mstrcpy(setlocale(LC_NUMERIC, NULL));
for (i = 0; i < NUM_WINTYPES; ++i) {
@@ -4611,21 +4404,8 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
ps->o.wintype_opacity[i] = 1.0;
}
- // Pre-parse the commandline arguments to check for --config and invalid
- // switches
- // Must reset optind to 0 here in case we reread the commandline
- // arguments
- optind = 1;
- while (-1 !=
- (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
- if (256 == o)
- config_file = mstrcpy(optarg);
- else if ('?' == o || ':' == o)
- usage();
- }
-
#ifdef CONFIG_LIBCONFIG
- parse_config(ps, config_file, &cfgtmp);
+ parse_config(ps, &cfgtmp);
#endif
// Parse commandline arguments. Range checking will be done later.
@@ -4643,7 +4423,6 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
usage();
break;
case 'd':
- ps->o.display = mstrcpy(optarg);
break;
case 'D':
ps->o.fade_delta = atoi(optarg);
@@ -4732,7 +4511,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
break;
case 263:
// --shadow-exclude
- condlst_add(&ps->o.shadow_blacklist, optarg);
+ condlst_add(ps, &ps->o.shadow_blacklist, optarg);
break;
case 264:
// --mark-ovredir-focused
@@ -4796,7 +4575,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
break;
case 279:
// --focus-exclude
- condlst_add(&ps->o.focus_blacklist, optarg);
+ condlst_add(ps, &ps->o.focus_blacklist, optarg);
break;
case 280:
// --inactive-dim-fixed
@@ -4832,7 +4611,7 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
break;
case 288:
// --invert-color-include
- condlst_add(&ps->o.invert_color_list, optarg);
+ condlst_add(ps, &ps->o.invert_color_list, optarg);
break;
default:
usage();
@@ -4884,11 +4663,6 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
ps->o.track_focus = true;
}
- // Determine whether we need to track window name and class
- if (ps->o.shadow_blacklist || ps->o.fade_blacklist
- || ps->o.focus_blacklist || ps->o.invert_color_list)
- ps->o.track_wdata = true;
-
// Determine whether we track window grouping
if (ps->o.detect_transient || ps->o.detect_client_leader) {
ps->o.track_leader = true;
@@ -5702,7 +5476,8 @@ session_init(session_t *ps_old, int argc, char **argv) {
ps->o.wintype_focus[WINTYPE_NORMAL] = false;
ps->o.wintype_focus[WINTYPE_UTILITY] = false;
- get_cfg(ps, argc, argv);
+ // First pass
+ get_cfg(ps, argc, argv, true);
// Inherit old Display if possible, primarily for resource leak checking
if (ps_old && ps_old->dpy)
@@ -5712,11 +5487,13 @@ session_init(session_t *ps_old, int argc, char **argv) {
if (!ps->dpy) {
ps->dpy = XOpenDisplay(ps->o.display);
if (!ps->dpy) {
- fprintf(stderr, "Can't open display\n");
- exit(1);
+ printf_errfq(1, "(): Can't open display.");
}
}
+ // Second pass
+ get_cfg(ps, argc, argv, false);
+
XSetErrorHandler(error);
if (ps->o.synchronize) {
XSynchronize(ps->dpy, 1);
@@ -5973,11 +5750,24 @@ 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);
free_wincondlst(&ps->o.focus_blacklist);
free_wincondlst(&ps->o.invert_color_list);
+#endif
+
+ // Free tracked atom list
+ {
+ latom_t *next = NULL;
+ for (latom_t *this = ps->track_atom_lst; this; this = next) {
+ next = this->next;
+ free(this);
+ }
+
+ ps->track_atom_lst = NULL;
+ }
// Free ignore linked list
{
@@ -6025,6 +5815,7 @@ session_destroy(session_t *ps) {
free(ps->gaussian_map);
free(ps->o.display);
free(ps->o.logpath);
+ free(ps->o.config_file);
free(ps->pfds_read);
free(ps->pfds_write);
free(ps->pfds_except);
@@ -6164,11 +5955,6 @@ main(int argc, char **argv) {
printf_errf("Failed to create new session.");
return 1;
}
-#ifdef DEBUG_C2
- // c2_parse(ps_g, NULL, "name ~= \"master\"");
- // c2_parse(ps_g, NULL, "n:e:Notification");
- c2_parse(ps_g, NULL, "(WM_NAME:16s = 'Notification' || class_g = 'fox') && class_g = 'fox'");
-#endif
session_run(ps_g);
ps_old = ps_g;
session_destroy(ps_g);