diff options
author | Richard Grenville <[email protected]> | 2013-01-28 21:39:38 +0800 |
---|---|---|
committer | Richard Grenville <[email protected]> | 2013-01-28 21:39:38 +0800 |
commit | 679bfe3cab740f06b38f606d599304f515b9de4d (patch) | |
tree | f5112867914ecf0e32101f4659e0f9db78395fd5 /c2.h | |
parent | 56a35506b1f65bd36e4f5b30054b348eea79f515 (diff) | |
download | tdebase-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 'c2.h')
-rw-r--r-- | c2.h | 326 |
1 files changed, 326 insertions, 0 deletions
@@ -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); + |