From f7f27db9bb1b905a988432635d0a0b9a53c4124f Mon Sep 17 00:00:00 2001 From: Bernd Busse Date: Sun, 25 Oct 2020 21:21:44 +0100 Subject: [PATCH] c2: add new predefined target `wm_state` to match against `_NET_WM_STATE` in string New predefined target `wm_state` for rule-based matching. Matches against the cached `_NET_WM_STATE` property of a window in string representation. NOTE: `wm_state = 'fullscreen'` is not neccessarily identical to `fullscreen`, and `wm_state = 'focused'` is not identical to `focused`. --- man/picom.1.asciidoc | 5 ++++- src/c2.c | 17 +++++++++++++++-- src/common.h | 1 + src/picom.c | 9 +++++++++ src/win.h | 3 +++ 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index 466ab55b9a..68df50620c 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -274,7 +274,7 @@ With greater-than/less-than operators it looks like: '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`, `x`, `y`, `x2` (`x` + `widthb`), `y2` (like `x2`), `width`, `height`, `widthb` (`width` + 2 * `border_width`), `heightb` (like `widthb`), `border_width`, `fullscreen`, `override_redirect`, `argb` (whether the window has an ARGB visual), `focused`, `wmwin` (whether the window looks like a WM window, i.e. has no child window with `WM_STATE` and is not override-redirected), `bounding_shaped`, `rounded_corners` (requires *--detect-rounded-corners*), `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`. +'TARGET' is either a predefined target name, or the name of a window property to match. Supported predefined targets are `id`, `x`, `y`, `x2` (`x` + `widthb`), `y2` (like `x2`), `width`, `height`, `widthb` (`width` + 2 * `border_width`), `heightb` (like `widthb`), `border_width`, `fullscreen`, `override_redirect`, `argb` (whether the window has an ARGB visual), `focused`, `wmwin` (whether the window looks like a WM window, i.e. has no child window with `WM_STATE` and is not override-redirected), `bounding_shaped`, `rounded_corners` (requires *--detect-rounded-corners*), `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]`), `role`, and `wm_state` (window manager state hint in string). 'CLIENT/FRAME' is a single `@` if the window attribute should be be looked up on client window, nothing if on frame window; @@ -307,6 +307,9 @@ Examples: # If the window is a menu window_type *= "menu" _NET_WM_WINDOW_TYPE@:a *= "MENU" + # If the window is marked hidden + wm_state *= "hidden" + _NET_WM_STATE@:a *= "HIDDEN" # If the window name contains "Firefox", ignore case name *?= "Firefox" _NET_WM_NAME@:s *?= "Firefox" diff --git a/src/c2.c b/src/c2.c index 860ef50d27..7da9b25d34 100644 --- a/src/c2.c +++ b/src/c2.c @@ -133,6 +133,7 @@ struct _c2_l { C2_L_PCLASSG, C2_L_PCLASSI, C2_L_PROLE, + C2_L_PWMSTATE, } predef; enum c2_l_type { C2_L_TUNDEFINED, @@ -210,6 +211,7 @@ static const c2_predef_t C2_PREDEFS[] = { [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}, + [C2_L_PWMSTATE] = {"wm_state", C2_L_TSTRING, 0}, }; /** @@ -1395,10 +1397,21 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w case C2_L_PCLASSG: tgt = w->class_general; break; case C2_L_PCLASSI: tgt = w->class_instance; break; case C2_L_PROLE: tgt = w->role; break; + case C2_L_PWMSTATE: { + ntargets = 0; + for (enum wm_state i = 1; i < NUM_WMSTATES; ++i) { + if (win_check_wm_state(w, i)) { + targets[ntargets++] = WMSTATES[i]; + } + } + break; + } default: assert(0); break; } - ntargets = 1; - targets[0] = tgt; + if (tgt) { + ntargets = 1; + targets[0] = tgt; + } } // An atom type property, convert it to string else if (pleaf->type == C2_L_TATOM) { diff --git a/src/common.h b/src/common.h index f1a4db66fb..debda88bf9 100644 --- a/src/common.h +++ b/src/common.h @@ -386,6 +386,7 @@ typedef struct session { typedef enum { WIN_EVMODE_UNKNOWN, WIN_EVMODE_FRAME, WIN_EVMODE_CLIENT } win_evmode_t; extern const char *const WINTYPES[NUM_WINTYPES]; +extern const char *const WMSTATES[NUM_WMSTATES]; extern session_t *ps_g; void ev_xcb_error(session_t *ps, xcb_generic_error_t *err); diff --git a/src/picom.c b/src/picom.c index 49930de6ce..497fe4fad4 100644 --- a/src/picom.c +++ b/src/picom.c @@ -84,6 +84,15 @@ const char *const WINTYPES[NUM_WINTYPES] = { "popup_menu", "tooltip", "notification", "combo", "dnd", }; +/// Name string for window wm_states. +const char *const WMSTATES[NUM_WMSTATES] = { + "unknown", "modal", "sticky", + "maximized_vert", "maximized_horz", "shaded", + "skip_taskbar", "skip_pager", "hidden", + "fullscreen", "above", "below", + "demands_attention", "focused", +}; + // clang-format off /// Names of backends. const char *const BACKEND_STRS[] = {[BKEND_XRENDER] = "xrender", diff --git a/src/win.h b/src/win.h index aa37bcaa6c..6cddeb1622 100644 --- a/src/win.h +++ b/src/win.h @@ -410,6 +410,9 @@ bool attr_pure win_is_fullscreen(const session_t *ps, const struct managed_win * */ bool attr_pure win_is_focused_raw(const session_t *ps, const struct managed_win *w); +/// check if window has specific wm_state. +bool attr_pure win_check_wm_state(const struct managed_win *w, enum wm_state state); + /// check if window has ARGB visual bool attr_pure win_has_alpha(const struct managed_win *w);