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.
This commit is contained in:
parent
00424b1082
commit
6d36ef2d0f
|
@ -38,4 +38,6 @@ oprofile_data/
|
|||
compton.plist
|
||||
callgrind.out.*
|
||||
man/*.html
|
||||
man/*.1
|
||||
doxygen/
|
||||
.clang_complete
|
||||
|
|
13
Makefile
13
Makefile
|
@ -55,10 +55,10 @@ ifeq "$(NO_DBUS)" ""
|
|||
endif
|
||||
|
||||
# ==== C2 ====
|
||||
# ifeq "$(NO_C2)" ""
|
||||
# CFG += -DCONFIG_C2
|
||||
# OBJS += c2.o
|
||||
# endif
|
||||
ifeq "$(NO_C2)" ""
|
||||
CFG += -DCONFIG_C2
|
||||
OBJS += c2.o
|
||||
endif
|
||||
|
||||
# === Version string ===
|
||||
COMPTON_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1 --date=short --pretty=format:%cd)
|
||||
|
@ -78,6 +78,9 @@ MANPAGES_HTML = $(addsuffix .html,$(MANPAGES))
|
|||
# === Recipes ===
|
||||
.DEFAULT_GOAL := compton
|
||||
|
||||
.clang_complete: Makefile
|
||||
@(for i in $(filter-out -O% -DNDEBUG, $(CFLAGS) $(INCS)); do echo "$$i"; done) > $@
|
||||
|
||||
%.o: src/%.c src/%.h src/common.h
|
||||
$(CC) $(CFLAGS) $(INCS) -c src/$*.c
|
||||
|
||||
|
@ -105,7 +108,7 @@ uninstall:
|
|||
@rm -f "$(DESTDIR)$(MANDIR)/compton-trans.1"
|
||||
|
||||
clean:
|
||||
@rm -f $(OBJS) compton $(MANPAGES) $(MANPAGES_HTML)
|
||||
@rm -f $(OBJS) compton $(MANPAGES) $(MANPAGES_HTML) .clang_complete
|
||||
|
||||
version:
|
||||
@echo "$(COMPTON_VERSION)"
|
||||
|
|
|
@ -10,7 +10,7 @@ shadow-offset-y = -7;
|
|||
# shadow-red = 0.0;
|
||||
# shadow-green = 0.0;
|
||||
# shadow-blue = 0.0;
|
||||
shadow-exclude = [ "n:e:Notification", "g:e:Conky" ];
|
||||
shadow-exclude = [ "name = 'Notification'", "class_g = 'Conky'" ];
|
||||
# shadow-exclude = "n:e:Notification";
|
||||
shadow-ignore-shaped = false;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ type_enum='uint16'
|
|||
dbus-send --print-reply --dest="$service" "$object" "${interface}.list_win"
|
||||
|
||||
# Get window ID of currently focused window
|
||||
focused=$(dbus-send --print-reply --dest="$service" "$object" "${interface}.find_win" string:focused | $SED -n 's/^[[:space:]]*'${type_win}'\s*\([[:digit:]]*\).*/\1/p')
|
||||
focused=$(dbus-send --print-reply --dest="$service" "$object" "${interface}.find_win" string:focused | $SED -n 's/^[[:space:]]*'${type_win}'[[:space:]]*\([[:digit:]]*\).*/\1/p')
|
||||
|
||||
if [ -n "$focused" ]; then
|
||||
# Get invert_color_force property of the window
|
||||
|
|
|
@ -180,8 +180,77 @@ OPTIONS
|
|||
|
||||
FORMAT OF CONDITIONS
|
||||
--------------------
|
||||
Some options accept a condition string to match certain windows. A condition string is formed by one or more conditions, joined by logical operators.
|
||||
|
||||
*--shadow-exclude* and *--focus-exclude* uses a condition string to blacklist certain windows. The format of the condition string is:
|
||||
A condition with "exists" operator looks like this:
|
||||
|
||||
<NEGATION> <TARGET> <CLIENT/FRAME> [<INDEX>] : <FORMAT> <TYPE>
|
||||
|
||||
With equals operator it looks like:
|
||||
|
||||
<NEGATION> <TARGET> <CLIENT/FRAME> [<INDEX>] : <FORMAT> <TYPE> <NEGATION> <OP QUALIFIER> <MATCH TYPE> = <PATTERN>
|
||||
|
||||
With greater-than/less-than operators it looks like:
|
||||
|
||||
<NEGATION> <TARGET> <CLIENT/FRAME> [<INDEX>] : <FORMAT> <TYPE> <NEGATION> <OPERATOR> <PATTERN>
|
||||
|
||||
'NEGATION' (optional) is one or more exclamation marks;
|
||||
|
||||
'TARGET' is either a predefined target name, or the name of a window property to match. Supported predefined targets are `id`, `override_redirect`, `focused`, `wmwin`, `client` (ID of client window), `window_type` (window type in string), `leader` (ID of window leader), `name`, `class_g` (= `WM_CLASS[1]`), `class_i` (= `WM_CLASS[0]`), and `role`.
|
||||
|
||||
'CLIENT/FRAME' is a single `@` if the window attribute should be be looked up on client window, nothing if on frame window;
|
||||
|
||||
'INDEX' (optional) is the index number of the property to look up. For example, `[2]` means look at the third value in the property. Do not specify it for predefined targets.
|
||||
|
||||
'FORMAT' (optional) specifies the format of the property, 8, 16, or 32. On absence we use format X reports. Do not specify it for predefined or string targets.
|
||||
|
||||
'TYPE' is a single character representing the type of the property to match for: `c` for 'CARDINAL', `a` for 'ATOM', `w` for 'WINDOW', `d` for 'DRAWABLE', `s` for 'STRING' (and any other string types, such as 'UTF8_STRING'). Do not specify it for predefined targets.
|
||||
|
||||
'OP QUALIFIER' (optional), applicable only for equals operator, could be `?` (ignore-case).
|
||||
|
||||
'MATCH TYPE' (optional), applicable only for equals operator, could be nothing (exact match), `*` (match anywhere), `^` (match from start), `%` (wildcard), or `~` (PCRE regular expression).
|
||||
|
||||
'OPERATOR' is one of `=` (equals), `<`, `>`, `<=`, `=>`, or nothing (exists). Exists operator checks whether a property exists on a window (but for predefined targets, exists means != 0 then).
|
||||
|
||||
'PATTERN' is either an integer or a string enclosed by single or double quotes. Python-3-style escape sequences and raw string are supported in the string format.
|
||||
|
||||
Supported logical operators are `&&` (and) and `||` (or). `&&` has higher precedence than `||`, left-to-right associativity. Use parentheses to change precedence.
|
||||
|
||||
Examples:
|
||||
|
||||
# If the window is focused
|
||||
focused
|
||||
focused = 1
|
||||
# If the window is not override-redirected
|
||||
!override_redirect
|
||||
override_redirect = false
|
||||
override_redirect != true
|
||||
override_redirect != 1
|
||||
# If the window is a menu
|
||||
window_type *= "menu"
|
||||
_NET_WM_WINDOW_TYPE@:a *= "MENU"
|
||||
# If the window name contains "Firefox", ignore case
|
||||
name *?= "Firefox"
|
||||
_NET_WM_NAME@:s *?= "Firefox"
|
||||
# If the window name ends with "Firefox"
|
||||
name %= "*Firefox"
|
||||
name ~= "Firefox$"
|
||||
# If the window has a property _COMPTON_SHADOW with value 0, type CARDINAL,
|
||||
# format 32, value 0, on its frame window
|
||||
_COMPTON_SHADOW:32c = 0
|
||||
# If the third value of _NET_FRAME_EXTENTS is less than 20, or there's no
|
||||
# _NET_FRAME_EXTENTS property on client window
|
||||
_NET_FRAME_EXTENTS@[2]:32c < 20 || !_NET_FRAME_EXTENTS@:32c
|
||||
# The pattern here will be parsed as "dd4"
|
||||
name = "\x64\x64\o64"
|
||||
# The pattern here will be parsed as "\x64\x64\x64"
|
||||
name = r"\x64\x64\o64"
|
||||
|
||||
|
||||
LEGACY FORMAT OF CONDITIONS
|
||||
---------------------------
|
||||
|
||||
This is the old condition format we once used. Support of this format might be removed in the future.
|
||||
|
||||
condition = TARGET:TYPE[FLAGS]:PATTERN
|
||||
|
||||
|
@ -239,7 +308,7 @@ $ compton -c --shadow-red 1 --shadow-green 1 --shadow-blue 1
|
|||
* Avoid drawing shadows on wbar window:
|
||||
+
|
||||
------------
|
||||
$ compton -c --shadow-exclude 'g:e:wbar'
|
||||
$ compton -c --shadow-exclude 'class_g = "wbar"'
|
||||
------------
|
||||
|
||||
* Enable OpenGL vsync:
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Compton - a compositor for X11
|
||||
*
|
||||
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
||||
*
|
||||
* Copyright (c) 2011-2013, Christopher Jeffrey
|
||||
* See LICENSE for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <ctype.h>
|
||||
|
||||
// libpcre
|
||||
#ifdef CONFIG_REGEX_PCRE
|
||||
#include <pcre.h>
|
||||
|
||||
// For compatiblity with <libpcre-8.20
|
||||
#ifndef PCRE_STUDY_JIT_COMPILE
|
||||
#define PCRE_STUDY_JIT_COMPILE 0
|
||||
#define LPCRE_FREE_STUDY(extra) pcre_free(extra)
|
||||
#else
|
||||
#define LPCRE_FREE_STUDY(extra) pcre_free_study(extra)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define C2_MAX_LEVELS 10
|
||||
|
||||
typedef struct _c2_b c2_b_t;
|
||||
typedef struct _c2_l c2_l_t;
|
||||
|
||||
/// Pointer to a condition tree.
|
||||
typedef struct {
|
||||
bool isbranch : 1;
|
||||
union {
|
||||
c2_b_t *b;
|
||||
c2_l_t *l;
|
||||
};
|
||||
} c2_ptr_t;
|
||||
|
||||
/// Initializer for c2_ptr_t.
|
||||
#define C2_PTR_INIT { \
|
||||
.isbranch = false, \
|
||||
.l = NULL, \
|
||||
}
|
||||
|
||||
const static c2_ptr_t C2_PTR_NULL = C2_PTR_INIT;
|
||||
|
||||
/// Operator of a branch element.
|
||||
typedef enum {
|
||||
C2_B_OUNDEFINED,
|
||||
C2_B_OAND,
|
||||
C2_B_OOR,
|
||||
C2_B_OXOR,
|
||||
} c2_b_op_t;
|
||||
|
||||
/// Structure for branch element in a window condition
|
||||
struct _c2_b {
|
||||
bool neg : 1;
|
||||
c2_b_op_t op;
|
||||
c2_ptr_t opr1;
|
||||
c2_ptr_t opr2;
|
||||
};
|
||||
|
||||
/// Initializer for c2_b_t.
|
||||
#define C2_B_INIT { \
|
||||
.neg = false, \
|
||||
.op = C2_B_OUNDEFINED, \
|
||||
.opr1 = C2_PTR_INIT, \
|
||||
.opr2 = C2_PTR_INIT, \
|
||||
}
|
||||
|
||||
/// Structure for leaf element in a window condition
|
||||
struct _c2_l {
|
||||
bool neg : 1;
|
||||
enum {
|
||||
C2_L_OEXISTS,
|
||||
C2_L_OEQ,
|
||||
C2_L_OGT,
|
||||
C2_L_OGTEQ,
|
||||
C2_L_OLT,
|
||||
C2_L_OLTEQ,
|
||||
} op : 3;
|
||||
enum {
|
||||
C2_L_MEXACT,
|
||||
C2_L_MSTART,
|
||||
C2_L_MCONTAINS,
|
||||
C2_L_MWILDCARD,
|
||||
C2_L_MPCRE,
|
||||
} match : 3;
|
||||
bool match_ignorecase : 1;
|
||||
char *tgt;
|
||||
Atom tgtatom;
|
||||
bool tgt_onframe;
|
||||
int index;
|
||||
enum {
|
||||
C2_L_PUNDEFINED,
|
||||
C2_L_PID,
|
||||
C2_L_POVREDIR,
|
||||
C2_L_PFOCUSED,
|
||||
C2_L_PWMWIN,
|
||||
C2_L_PCLIENT,
|
||||
C2_L_PWINDOWTYPE,
|
||||
C2_L_PLEADER,
|
||||
C2_L_PNAME,
|
||||
C2_L_PCLASSG,
|
||||
C2_L_PCLASSI,
|
||||
C2_L_PROLE,
|
||||
} predef;
|
||||
enum c2_l_type {
|
||||
C2_L_TUNDEFINED,
|
||||
C2_L_TSTRING,
|
||||
C2_L_TCARDINAL,
|
||||
C2_L_TWINDOW,
|
||||
C2_L_TATOM,
|
||||
C2_L_TDRAWABLE,
|
||||
} type;
|
||||
int format;
|
||||
enum {
|
||||
C2_L_PTUNDEFINED,
|
||||
C2_L_PTSTRING,
|
||||
C2_L_PTINT,
|
||||
} ptntype;
|
||||
char *ptnstr;
|
||||
long ptnint;
|
||||
#ifdef CONFIG_REGEX_PCRE
|
||||
pcre *regex_pcre;
|
||||
pcre_extra *regex_pcre_extra;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Initializer for c2_l_t.
|
||||
#define C2_L_INIT { \
|
||||
.neg = false, \
|
||||
.op = C2_L_OEXISTS, \
|
||||
.match = C2_L_MEXACT, \
|
||||
.match_ignorecase = false, \
|
||||
.tgt = NULL, \
|
||||
.tgtatom = 0, \
|
||||
.tgt_onframe = false, \
|
||||
.predef = C2_L_PUNDEFINED, \
|
||||
.index = -1, \
|
||||
.type = C2_L_TUNDEFINED, \
|
||||
.format = 0, \
|
||||
.ptntype = C2_L_PTUNDEFINED, \
|
||||
.ptnstr = NULL, \
|
||||
.ptnint = 0, \
|
||||
}
|
||||
|
||||
const static c2_l_t leaf_def = C2_L_INIT;
|
||||
|
||||
/// Linked list type of conditions.
|
||||
struct _c2_lptr {
|
||||
c2_ptr_t ptr;
|
||||
struct _c2_lptr *next;
|
||||
};
|
||||
|
||||
/// Initializer for c2_lptr_t.
|
||||
#define C2_LPTR_INIT { \
|
||||
.ptr = C2_PTR_INIT, \
|
||||
.next = NULL, \
|
||||
}
|
||||
|
||||
/// Structure representing a predefined target.
|
||||
typedef struct {
|
||||
const char *name;
|
||||
enum c2_l_type type;
|
||||
int format;
|
||||
} c2_predef_t;
|
||||
|
||||
// Predefined targets.
|
||||
const static c2_predef_t C2_PREDEFS[] = {
|
||||
[C2_L_PID ] = { "id" , C2_L_TCARDINAL , 0 },
|
||||
[C2_L_POVREDIR ] = { "override_redirect" , C2_L_TCARDINAL , 0 },
|
||||
[C2_L_PFOCUSED ] = { "focused" , C2_L_TCARDINAL , 0 },
|
||||
[C2_L_PWMWIN ] = { "wmwin" , C2_L_TCARDINAL , 0 },
|
||||
[C2_L_PCLIENT ] = { "client" , C2_L_TWINDOW , 0 },
|
||||
[C2_L_PWINDOWTYPE ] = { "window_type" , C2_L_TSTRING , 0 },
|
||||
[C2_L_PLEADER ] = { "leader" , C2_L_TWINDOW , 0 },
|
||||
[C2_L_PNAME ] = { "name" , C2_L_TSTRING , 0 },
|
||||
[C2_L_PCLASSG ] = { "class_g" , C2_L_TSTRING , 0 },
|
||||
[C2_L_PCLASSI ] = { "class_i" , C2_L_TSTRING , 0 },
|
||||
[C2_L_PROLE ] = { "role" , C2_L_TSTRING , 0 },
|
||||
};
|
||||
|
||||
#define mstrncmp(s1, s2) strncmp((s1), (s2), strlen(s1))
|
||||
|
||||
/**
|
||||
* Compare next word in a string with another string.
|
||||
*/
|
||||
static inline int
|
||||
strcmp_wd(const char *needle, const char *src) {
|
||||
int ret = mstrncmp(needle, src);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
char c = src[strlen(needle)];
|
||||
if (isalnum(c) || '_' == c)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a c2_ptr_t is empty.
|
||||
*/
|
||||
static inline bool
|
||||
c2_ptr_isempty(const c2_ptr_t p) {
|
||||
return !(p.isbranch ? (bool) p.b: (bool) p.l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a c2_ptr_t.
|
||||
*/
|
||||
static inline void
|
||||
c2_ptr_reset(c2_ptr_t *pp) {
|
||||
if (pp)
|
||||
memcpy(pp, &C2_PTR_NULL, sizeof(c2_ptr_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine two condition trees.
|
||||
*/
|
||||
static inline c2_ptr_t
|
||||
c2h_comb_tree(c2_b_op_t op, c2_ptr_t p1, c2_ptr_t p2) {
|
||||
c2_ptr_t p = {
|
||||
.isbranch = true,
|
||||
.b = malloc(sizeof(c2_b_t))
|
||||
};
|
||||
|
||||
p.b->opr1 = p1;
|
||||
p.b->opr2 = p2;
|
||||
p.b->op = op;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the precedence value of a condition branch operator.
|
||||
*/
|
||||
static inline int
|
||||
c2h_b_opp(c2_b_op_t op) {
|
||||
switch (op) {
|
||||
case C2_B_OAND: return 2;
|
||||
case C2_B_OOR: return 1;
|
||||
case C2_B_OXOR: return 1;
|
||||
default: break;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare precedence of two condition branch operators.
|
||||
*
|
||||
* Associativity is left-to-right, forever.
|
||||
*
|
||||
* @return positive number if op1 > op2, 0 if op1 == op2 in precedence,
|
||||
* negative number otherwise
|
||||
*/
|
||||
static inline int
|
||||
c2h_b_opcmp(c2_b_op_t op1, c2_b_op_t op2) {
|
||||
return c2h_b_opp(op1) - c2h_b_opp(op2);
|
||||
}
|
||||
|
||||
static int
|
||||
c2_parse_grp(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult, int level);
|
||||
|
||||
static int
|
||||
c2_parse_target(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult);
|
||||
|
||||
static int
|
||||
c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult);
|
||||
|
||||
static int
|
||||
c2_parse_pattern(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult);
|
||||
|
||||
static int
|
||||
c2_parse_legacy(session_t *ps, const char *pattern, int offset, c2_ptr_t *presult);
|
||||
|
||||
static bool
|
||||
c2_l_postprocess(session_t *ps, c2_l_t *pleaf);
|
||||
|
||||
static void
|
||||
c2_free(c2_ptr_t p);
|
||||
|
||||
/**
|
||||
* Wrapper of c2_free().
|
||||
*/
|
||||
static inline void
|
||||
c2_freep(c2_ptr_t *pp) {
|
||||
if (pp) {
|
||||
c2_free(*pp);
|
||||
c2_ptr_reset(pp);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
c2h_dump_str_tgt(const c2_l_t *pleaf);
|
||||
|
||||
static const char *
|
||||
c2h_dump_str_type(const c2_l_t *pleaf);
|
||||
|
||||
static void
|
||||
c2_dump_raw(c2_ptr_t p);
|
||||
|
||||
/**
|
||||
* Wrapper of c2_dump_raw().
|
||||
*/
|
||||
static inline void
|
||||
c2_dump(c2_ptr_t p) {
|
||||
c2_dump_raw(p);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static Atom
|
||||
c2_get_atom_type(const c2_l_t *pleaf);
|
||||
|
||||
static bool
|
||||
c2_match_once(session_t *ps, win *w, const c2_ptr_t cond);
|
||||
|
58
src/common.h
58
src/common.h
|
@ -76,20 +76,6 @@
|
|||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/Xdbe.h>
|
||||
|
||||
// libpcre
|
||||
#ifdef CONFIG_REGEX_PCRE
|
||||
#include <pcre.h>
|
||||
|
||||
// For compatiblity with <libpcre-8.20
|
||||
#ifndef PCRE_STUDY_JIT_COMPILE
|
||||
#define PCRE_STUDY_JIT_COMPILE 0
|
||||
#define LPCRE_FREE_STUDY(extra) pcre_free(extra)
|
||||
#else
|
||||
#define LPCRE_FREE_STUDY(extra) pcre_free_study(extra)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// libconfig
|
||||
#ifdef CONFIG_LIBCONFIG
|
||||
#include <libgen.h>
|
||||
|
@ -257,18 +243,6 @@ enum wincond_type {
|
|||
|
||||
#define CONDF_IGNORECASE 0x0001
|
||||
|
||||
typedef struct _wincond {
|
||||
enum wincond_target target;
|
||||
enum wincond_type type;
|
||||
char *pattern;
|
||||
#ifdef CONFIG_REGEX_PCRE
|
||||
pcre *regex_pcre;
|
||||
pcre_extra *regex_pcre_extra;
|
||||
#endif
|
||||
int16_t flags;
|
||||
struct _wincond *next;
|
||||
} wincond_t;
|
||||
|
||||
/// VSync modes.
|
||||
typedef enum {
|
||||
VSYNC_NONE,
|
||||
|
@ -297,13 +271,13 @@ struct _timeout_t;
|
|||
|
||||
struct _win;
|
||||
|
||||
#ifdef CONFIG_C2
|
||||
typedef struct _c2_lptr c2_lptr_t;
|
||||
#endif
|
||||
|
||||
/// Structure representing all options.
|
||||
typedef struct {
|
||||
// === General ===
|
||||
/// The configuration file we used.
|
||||
char *config_file;
|
||||
/// The display name we used. NULL means we are using the value of the
|
||||
/// <code>DISPLAY</code> environment variable.
|
||||
char *display;
|
||||
|
@ -350,7 +324,7 @@ typedef struct {
|
|||
double shadow_opacity;
|
||||
bool clear_shadow;
|
||||
/// Shadow blacklist. A linked list of conditions.
|
||||
wincond_t *shadow_blacklist;
|
||||
c2_lptr_t *shadow_blacklist;
|
||||
/// Whether bounding-shaped window should be ignored.
|
||||
bool shadow_ignore_shaped;
|
||||
/// Whether to respect _COMPTON_SHADOW.
|
||||
|
@ -368,7 +342,7 @@ typedef struct {
|
|||
/// Whether to disable fading on window open/close.
|
||||
bool no_fading_openclose;
|
||||
/// Fading blacklist. A linked list of conditions.
|
||||
wincond_t *fade_blacklist;
|
||||
c2_lptr_t *fade_blacklist;
|
||||
|
||||
// === Opacity ===
|
||||
/// Default opacity for specific window types
|
||||
|
@ -404,7 +378,7 @@ typedef struct {
|
|||
/// based on window opacity.
|
||||
bool inactive_dim_fixed;
|
||||
/// Conditions of windows to have inverted colors.
|
||||
wincond_t *invert_color_list;
|
||||
c2_lptr_t *invert_color_list;
|
||||
|
||||
// === Focus related ===
|
||||
/// Consider windows of specific types to be always focused.
|
||||
|
@ -412,7 +386,7 @@ typedef struct {
|
|||
/// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
|
||||
bool use_ewmh_active_win;
|
||||
/// A list of windows always to be considered focused.
|
||||
wincond_t *focus_blacklist;
|
||||
c2_lptr_t *focus_blacklist;
|
||||
/// Whether to do window grouping with <code>WM_TRANSIENT_FOR</code>.
|
||||
bool detect_transient;
|
||||
/// Whether to do window grouping with <code>WM_CLIENT_LEADER</code>.
|
||||
|
@ -736,10 +710,10 @@ typedef struct _win {
|
|||
char *class_general;
|
||||
/// <code>WM_WINDOW_ROLE</code> value of the window.
|
||||
char *role;
|
||||
wincond_t *cache_sblst;
|
||||
wincond_t *cache_fblst;
|
||||
wincond_t *cache_fcblst;
|
||||
wincond_t *cache_ivclst;
|
||||
const c2_lptr_t *cache_sblst;
|
||||
const c2_lptr_t *cache_fblst;
|
||||
const c2_lptr_t *cache_fcblst;
|
||||
const c2_lptr_t *cache_ivclst;
|
||||
|
||||
// Opacity-related members
|
||||
/// Current window opacity.
|
||||
|
@ -1056,10 +1030,13 @@ print_timestamp(session_t *ps) {
|
|||
/**
|
||||
* Allocate the space and copy a string.
|
||||
*/
|
||||
static inline char * __attribute__((const))
|
||||
static inline char *
|
||||
mstrcpy(const char *src) {
|
||||
char *str = malloc(sizeof(char) * (strlen(src) + 1));
|
||||
|
||||
if (!str)
|
||||
printf_errfq(1, "(): Failed to allocate memory.");
|
||||
|
||||
strcpy(str, src);
|
||||
|
||||
return str;
|
||||
|
@ -1068,10 +1045,13 @@ mstrcpy(const char *src) {
|
|||
/**
|
||||
* Allocate the space and copy a string.
|
||||
*/
|
||||
static inline char * __attribute__((const))
|
||||
static inline char *
|
||||
mstrncpy(const char *src, unsigned len) {
|
||||
char *str = malloc(sizeof(char) * (len + 1));
|
||||
|
||||
if (!str)
|
||||
printf_errfq(1, "(): Failed to allocate memory.");
|
||||
|
||||
strncpy(str, src, len);
|
||||
str[len] = '\0';
|
||||
|
||||
|
@ -1479,7 +1459,7 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val);
|
|||
///@{
|
||||
|
||||
c2_lptr_t *
|
||||
c2_parse(session_t *ps, c2_lptr_t **pcondlst, char *pattern);
|
||||
c2_parse(session_t *ps, c2_lptr_t **pcondlst, const char *pattern);
|
||||
|
||||
c2_lptr_t *
|
||||
c2_free_lptr(c2_lptr_t *lp);
|
||||
|
|
398
src/compton.c
398
src/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,
|
||||
|
@ -629,244 +629,20 @@ win_rounded_corners(session_t *ps, win *w) {
|
|||
XFree(rects);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
#ifdef CONFIG_C2
|
||||
if (!c2_parse(ps, pcondlst, pattern))
|
||||
exit(1);
|
||||
#else
|
||||
printf_errfq(1, "(): Condition support not compiled in.");
|
||||
#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
|
||||
#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,22 +4369,9 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
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) {
|
||||
ps->o.wintype_fade[i] = false;
|
||||
ps->o.wintype_shadow[i] = false;
|
||||
ps->o.wintype_opacity[i] = 1.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
|
||||
|
@ -4619,13 +4380,32 @@ get_cfg(session_t *ps, int argc, char *const *argv) {
|
|||
while (-1 !=
|
||||
(o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
|
||||
if (256 == o)
|
||||
config_file = mstrcpy(optarg);
|
||||
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;
|
||||
char *lc_numeric_old = mstrcpy(setlocale(LC_NUMERIC, NULL));
|
||||
|
||||
for (i = 0; i < NUM_WINTYPES; ++i) {
|
||||
ps->o.wintype_fade[i] = false;
|
||||
ps->o.wintype_shadow[i] = false;
|
||||
ps->o.wintype_opacity[i] = 1.0;
|
||||
}
|
||||
|
||||
#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);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <locale.h>
|
||||
#include <fnmatch.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef CONFIG_VSYNC_DRM
|
||||
|
@ -165,37 +164,16 @@ free_damage(session_t *ps, Damage *p) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_C2
|
||||
/**
|
||||
* Destroy a <code>wincond_t</code>.
|
||||
* Destroy a condition list.
|
||||
*/
|
||||
inline static void
|
||||
free_wincond(wincond_t *cond) {
|
||||
if (cond->pattern)
|
||||
free(cond->pattern);
|
||||
#ifdef CONFIG_REGEX_PCRE
|
||||
if (cond->regex_pcre_extra)
|
||||
LPCRE_FREE_STUDY(cond->regex_pcre_extra);
|
||||
if (cond->regex_pcre)
|
||||
pcre_free(cond->regex_pcre);
|
||||
static inline void
|
||||
free_wincondlst(c2_lptr_t **pcondlst) {
|
||||
while ((*pcondlst = c2_free_lptr(*pcondlst)))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
free(cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a linked list of <code>wincond_t</code>.
|
||||
*/
|
||||
inline static void
|
||||
free_wincondlst(wincond_t **cond_lst) {
|
||||
wincond_t *next = NULL;
|
||||
|
||||
for (wincond_t *cond = *cond_lst; cond; cond = next) {
|
||||
next = cond->next;
|
||||
|
||||
free_wincond(cond);
|
||||
}
|
||||
|
||||
*cond_lst = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all resources in a <code>struct _win</code>.
|
||||
|
@ -396,14 +374,20 @@ win_is_fullscreen(session_t *ps, const win *w) {
|
|||
static void
|
||||
win_rounded_corners(session_t *ps, win *w);
|
||||
|
||||
static bool
|
||||
win_match_once(win *w, const wincond_t *cond);
|
||||
/**
|
||||
* Wrapper of c2_match().
|
||||
*/
|
||||
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
|
||||
win_match(win *w, wincond_t *condlst, wincond_t * *cache);
|
||||
|
||||
static bool
|
||||
condlst_add(wincond_t **pcondlst, const char *pattern);
|
||||
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);
|
||||
|
@ -594,7 +578,7 @@ static void
|
|||
win_on_wtype_change(session_t *ps, win *w);
|
||||
|
||||
static void
|
||||
win_on_wdata_change(session_t *ps, win *w);
|
||||
win_on_factor_change(session_t *ps, win *w);
|
||||
|
||||
static void
|
||||
win_upd_run(session_t *ps, win *w, win_upd_t *pupd);
|
||||
|
@ -858,15 +842,15 @@ static FILE *
|
|||
open_config_file(char *cpath, char **path);
|
||||
|
||||
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);
|
||||
|
||||
static void
|
||||
parse_config(session_t *ps, char *cpath, struct options_tmp *pcfgtmp);
|
||||
parse_config(session_t *ps, struct options_tmp *pcfgtmp);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
static void
|
||||
init_atoms(session_t *ps);
|
||||
|
|
|
@ -859,6 +859,7 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
|
|||
return true;
|
||||
}
|
||||
|
||||
cdbus_m_opts_get_do(config_file, cdbus_reply_string);
|
||||
cdbus_m_opts_get_do(mark_wmwin_focused, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(mark_ovredir_focused, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
|
||||
|
|
Loading…
Reference in New Issue