From 198da194e821b19adc89b2c1e05963c1baf1e5bc Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 17 Feb 2024 23:01:29 +0000 Subject: [PATCH] c2: remove type specifiers Same logic as the format specifiers, we just use what the X server reports, asking the user for the type is just going to be confusing. Signed-off-by: Yuxuan Shui --- CHANGELOG.md | 2 +- man/picom.1.asciidoc | 20 ++-- src/c2.c | 274 +++++++++++++++---------------------------- src/x.c | 2 +- src/x.h | 6 + 5 files changed, 109 insertions(+), 195 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2500d65..980a375e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ## Notable changes * Marginally improve performance when resizing/opening/closing windows. (#1190) -* Format specifiers are no longer used in rules. Format specifier is the number you put after the colon (':') in rules, e.g. the `32` in `"_GTK_FRAME_EXTENTS@:32c"`. Now this information is ignored and the property is matched regardless of format. +* Type and format specifiers are no longer used in rules. These specifiers are what you put after the colon (':') in rules, e.g. the `:32c` in `"_GTK_FRAME_EXTENTS@:32c"`. Now this information is ignored and the property is matched regardless of format or type. ## Dependency changes diff --git a/man/picom.1.asciidoc b/man/picom.1.asciidoc index 9609b1f6..ccc8f51d 100644 --- a/man/picom.1.asciidoc +++ b/man/picom.1.asciidoc @@ -286,15 +286,15 @@ Some options accept a condition string to match certain windows. A condition str A condition with "exists" operator looks like this: - [] : + [] With equals operator it looks like: - [] : = + [] = With greater-than/less-than operators it looks like: - [] : + [] 'NEGATION' (optional) is one or more exclamation marks; @@ -304,8 +304,6 @@ With greater-than/less-than operators it looks like: 'INDEX' (optional) is the index number of the property to look up. For example, `[2]` means look at the third value in the property. If not specified, the first value (index `[0]`) is used implicitly. Use the special value `[*]` to perform matching against all available property values using logical OR. Do not specify it for predefined 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). @@ -328,24 +326,24 @@ Examples: override_redirect != 1 # If the window is a menu window_type *= "menu" - _NET_WM_WINDOW_TYPE@:a *= "MENU" + _NET_WM_WINDOW_TYPE@ *= "MENU" # If the window is marked hidden: _NET_WM_STATE contains _NET_WM_STATE_HIDDEN - _NET_WM_STATE@[*]:a = "_NET_WM_STATE_HIDDEN" + _NET_WM_STATE@[*] = "_NET_WM_STATE_HIDDEN" # If the window is marked sticky: _NET_WM_STATE contains an atom that contains # "sticky", ignore case - _NET_WM_STATE@[*]:a *?= "sticky" + _NET_WM_STATE@[*] *?= "sticky" # If the window name contains "Firefox", ignore case name *?= "Firefox" - _NET_WM_NAME@:s *?= "Firefox" + _NET_WM_NAME@ *?= "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 + _COMPTON_SHADOW = 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 + _NET_FRAME_EXTENTS@[2] < 20 || !_NET_FRAME_EXTENTS@ # The pattern here will be parsed as "dd4" name = "\x64\x64\o64" diff --git a/src/c2.c b/src/c2.c index 37cd61f3..0683d7fb 100644 --- a/src/c2.c +++ b/src/c2.c @@ -66,7 +66,6 @@ static_assert(sizeof(struct c2_tracked_property_key) == 8, "Padding bytes in " struct c2_tracked_property { UT_hash_handle hh; struct c2_tracked_property_key key; - bool is_string; }; struct c2_state { @@ -150,14 +149,6 @@ struct _c2_l { 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; enum { C2_L_PTUNDEFINED, C2_L_PTSTRING, @@ -172,12 +163,12 @@ struct _c2_l { }; /// 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 = 0, .type = C2_L_TUNDEFINED, \ - .ptntype = C2_L_PTUNDEFINED, .ptnstr = NULL, .ptnint = 0, \ +#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 = 0, \ + .ptntype = C2_L_PTUNDEFINED, .ptnstr = NULL, .ptnint = 0, \ } static const c2_l_t leaf_def = C2_L_INIT; @@ -196,35 +187,34 @@ struct _c2_lptr { /// Structure representing a predefined target. typedef struct { const char *name; - enum c2_l_type type; } c2_predef_t; // Predefined targets. -static const c2_predef_t C2_PREDEFS[] = { - [C2_L_PID] = {"id", C2_L_TCARDINAL}, - [C2_L_PX] = {"x", C2_L_TCARDINAL}, - [C2_L_PY] = {"y", C2_L_TCARDINAL}, - [C2_L_PX2] = {"x2", C2_L_TCARDINAL}, - [C2_L_PY2] = {"y2", C2_L_TCARDINAL}, - [C2_L_PWIDTH] = {"width", C2_L_TCARDINAL}, - [C2_L_PHEIGHT] = {"height", C2_L_TCARDINAL}, - [C2_L_PWIDTHB] = {"widthb", C2_L_TCARDINAL}, - [C2_L_PHEIGHTB] = {"heightb", C2_L_TCARDINAL}, - [C2_L_PBDW] = {"border_width", C2_L_TCARDINAL}, - [C2_L_PFULLSCREEN] = {"fullscreen", C2_L_TCARDINAL}, - [C2_L_POVREDIR] = {"override_redirect", C2_L_TCARDINAL}, - [C2_L_PARGB] = {"argb", C2_L_TCARDINAL}, - [C2_L_PFOCUSED] = {"focused", C2_L_TCARDINAL}, - [C2_L_PWMWIN] = {"wmwin", C2_L_TCARDINAL}, - [C2_L_PBSHAPED] = {"bounding_shaped", C2_L_TCARDINAL}, - [C2_L_PROUNDED] = {"rounded_corners", C2_L_TCARDINAL}, - [C2_L_PCLIENT] = {"client", C2_L_TWINDOW}, - [C2_L_PWINDOWTYPE] = {"window_type", C2_L_TSTRING}, - [C2_L_PLEADER] = {"leader", C2_L_TWINDOW}, - [C2_L_PNAME] = {"name", C2_L_TSTRING}, - [C2_L_PCLASSG] = {"class_g", C2_L_TSTRING}, - [C2_L_PCLASSI] = {"class_i", C2_L_TSTRING}, - [C2_L_PROLE] = {"role", C2_L_TSTRING}, +static const char *C2_PREDEFS[] = { + [C2_L_PID] = "id", + [C2_L_PX] = "x", + [C2_L_PY] = "y", + [C2_L_PX2] = "x2", + [C2_L_PY2] = "y2", + [C2_L_PWIDTH] = "width", + [C2_L_PHEIGHT] = "height", + [C2_L_PWIDTHB] = "widthb", + [C2_L_PHEIGHTB] = "heightb", + [C2_L_PBDW] = "border_width", + [C2_L_PFULLSCREEN] = "fullscreen", + [C2_L_POVREDIR] = "override_redirect", + [C2_L_PARGB] = "argb", + [C2_L_PFOCUSED] = "focused", + [C2_L_PWMWIN] = "wmwin", + [C2_L_PBSHAPED] = "bounding_shaped", + [C2_L_PROUNDED] = "rounded_corners", + [C2_L_PCLIENT] = "client", + [C2_L_PWINDOWTYPE] = "window_type", + [C2_L_PLEADER] = "leader", + [C2_L_PNAME] = "name", + [C2_L_PCLASSG] = "class_g", + [C2_L_PCLASSI] = "class_i", + [C2_L_PROLE] = "role", }; /** @@ -349,11 +339,7 @@ static inline void c2_freep(c2_ptr_t *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 xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf); - -static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_ptr_t cond); +static bool c2_match_once(session_t *ps, const struct managed_win *w, c2_ptr_t cond); /** * Parse a condition string. @@ -413,7 +399,7 @@ TEST_CASE(c2_parse) { TEST_STREQUAL(cond->ptr.l->ptnstr, "xterm"); size_t len = c2_condition_to_str(cond->ptr, str, sizeof(str)); - TEST_STREQUAL3(str, "name:s = \"xterm\"", len); + TEST_STREQUAL3(str, "name = \"xterm\"", len); c2_list_free(&cond, NULL); cond = c2_parse(NULL, "_GTK_FRAME_EXTENTS@:c", NULL); @@ -423,13 +409,12 @@ TEST_CASE(c2_parse) { TEST_EQUAL(cond->ptr.l->op, C2_L_OEXISTS); TEST_EQUAL(cond->ptr.l->match, C2_L_MEXACT); TEST_EQUAL(cond->ptr.l->predef, C2_L_PUNDEFINED); - TEST_EQUAL(cond->ptr.l->type, C2_L_TCARDINAL); TEST_TRUE(cond->ptr.l->tgt_onframe); TEST_NOTEQUAL(cond->ptr.l->tgt, NULL); TEST_STREQUAL(cond->ptr.l->tgt, "_GTK_FRAME_EXTENTS"); len = c2_condition_to_str(cond->ptr, str, sizeof(str)); - TEST_STREQUAL3(str, "_GTK_FRAME_EXTENTS@[0]:c", len); + TEST_STREQUAL3(str, "_GTK_FRAME_EXTENTS@[0]", len); c2_list_free(&cond, NULL); cond = c2_parse(NULL, "name = \"xterm\" && class_g *= \"XTerm\"", NULL); @@ -451,34 +436,33 @@ TEST_CASE(c2_parse) { TEST_EQUAL(cond->ptr.b->opr2.l->predef, C2_L_PCLASSG); len = c2_condition_to_str(cond->ptr, str, sizeof(str)); - TEST_STREQUAL3(str, "(name:s = \"xterm\" && class_g:s *= \"XTerm\")", len); + TEST_STREQUAL3(str, "(name = \"xterm\" && class_g *= \"XTerm\")", len); c2_list_free(&cond, NULL); cond = c2_parse(NULL, "_NET_WM_STATE[1]:32a *='_NET_WM_STATE_HIDDEN'", NULL); TEST_EQUAL(cond->ptr.l->index, 1); - TEST_EQUAL(cond->ptr.l->type, C2_L_TATOM); TEST_STREQUAL(cond->ptr.l->tgt, "_NET_WM_STATE"); TEST_STREQUAL(cond->ptr.l->ptnstr, "_NET_WM_STATE_HIDDEN"); len = c2_condition_to_str(cond->ptr, str, sizeof(str)); - TEST_STREQUAL3(str, "_NET_WM_STATE[1]:a *= \"_NET_WM_STATE_HIDDEN\"", len); + TEST_STREQUAL3(str, "_NET_WM_STATE[1] *= \"_NET_WM_STATE_HIDDEN\"", len); c2_list_free(&cond, NULL); cond = c2_parse(NULL, "_NET_WM_STATE[*]:32a*='_NET_WM_STATE_HIDDEN'", NULL); TEST_EQUAL(cond->ptr.l->index, -1); len = c2_condition_to_str(cond->ptr, str, sizeof(str)); - TEST_STREQUAL3(str, "_NET_WM_STATE[*]:a *= \"_NET_WM_STATE_HIDDEN\"", len); + TEST_STREQUAL3(str, "_NET_WM_STATE[*] *= \"_NET_WM_STATE_HIDDEN\"", len); c2_list_free(&cond, NULL); cond = c2_parse(NULL, "!class_i:0s", NULL); TEST_NOTEQUAL(cond, NULL); len = c2_condition_to_str(cond->ptr, str, sizeof(str)); - TEST_STREQUAL3(str, "!class_i:s", len); + TEST_STREQUAL3(str, "!class_i", len); c2_list_free(&cond, NULL); cond = c2_parse(NULL, "_NET_WM_STATE = '_NET_WM_STATE_HIDDEN'", NULL); - TEST_EQUAL(cond, NULL); + TEST_NOTEQUAL(cond, NULL); cond = c2_parse(NULL, "1A:\n1111111111111ar1", NULL); TEST_EQUAL(cond, NULL); @@ -492,8 +476,8 @@ TEST_CASE(c2_parse) { cond = c2_parse(NULL, "!!!!!!!((((((!(((((,", NULL); TEST_EQUAL(cond, NULL); - const char *rule = "(((role:s = \"\\\\tg^\\n\\n[\\t\" && role:s ~?= \"\") && " - "role:s ~?= \"\\n\\n\\n\\b\\n^\\n*0bon\") && role:s ~?= " + const char *rule = "(((role = \"\\\\tg^\\n\\n[\\t\" && role ~?= \"\") && " + "role ~?= \"\\n\\n\\n\\b\\n^\\n*0bon\") && role ~?= " "\"\\n\\n\\x8a\\b\\n^\\n*0\\n[\\n[\\n\\n\\b\\n\")"; cond = c2_parse(NULL, rule, NULL); TEST_NOTEQUAL(cond, NULL); @@ -732,9 +716,8 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) { // Check for predefined targets static const int npredefs = (int)(sizeof(C2_PREDEFS) / sizeof(C2_PREDEFS[0])); for (int i = 0; i < npredefs; ++i) { - if (!strcmp(C2_PREDEFS[i].name, pleaf->tgt)) { + if (!strcmp(C2_PREDEFS[i], pleaf->tgt)) { pleaf->predef = i; - pleaf->type = C2_PREDEFS[i].type; break; } } @@ -800,39 +783,27 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) { // Look for format bool hasformat = false; long format = 0; - { - char *endptr = NULL; - format = strtol(pattern + offset, &endptr, 0); - assert(endptr); - if ((hasformat = (endptr && endptr != pattern + offset))) { - offset = to_int_checked(endptr - pattern); - } - C2H_SKIP_SPACES(); + char *endptr = NULL; + format = strtol(pattern + offset, &endptr, 0); + assert(endptr); + hasformat = endptr && endptr != pattern + offset; + if (hasformat) { + offset = to_int_checked(endptr - pattern); } + C2H_SKIP_SPACES(); // Look for type - enum c2_l_type type = C2_L_TUNDEFINED; switch (pattern[offset]) { - case 'w': type = C2_L_TWINDOW; break; - case 'd': type = C2_L_TDRAWABLE; break; - case 'c': type = C2_L_TCARDINAL; break; - case 's': type = C2_L_TSTRING; break; - case 'a': type = C2_L_TATOM; break; + case 'w': + case 'd': + case 'c': + case 's': + case 'a': break; default: c2_error("Invalid type character."); } - if (type) { - if (pleaf->predef != C2_L_PUNDEFINED) { - log_warn("Type specified for a default target " - "will be ignored."); - } else { - if (pleaf->type && type != pleaf->type) { - log_warn("Default type overridden on " - "target."); - } - pleaf->type = type; - } - } + log_warn("Type \"%c\" specified on target \"%s\" will be ignored.", + pattern[offset], pleaf->tgt); offset++; C2H_SKIP_SPACES(); @@ -847,11 +818,6 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) { } } } - - if (!pleaf->type) { - c2_error("Target type cannot be determined."); - } - return offset; fail: @@ -1046,21 +1012,14 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult) c2_error("Invalid pattern type."); } - // Check if the type is correct - if (!(((C2_L_TSTRING == pleaf->type || C2_L_TATOM == pleaf->type) && - C2_L_PTSTRING == pleaf->ptntype) || - ((C2_L_TCARDINAL == pleaf->type || C2_L_TWINDOW == pleaf->type || - C2_L_TDRAWABLE == pleaf->type) && - C2_L_PTINT == pleaf->ptntype))) { - c2_error("Pattern type incompatible with target type."); - } - - if (C2_L_PTINT == pleaf->ptntype && pleaf->match) { - c2_error("Integer/boolean pattern cannot have operator qualifiers."); - } - - if (C2_L_PTINT == pleaf->ptntype && pleaf->match_ignorecase) { - c2_error("Integer/boolean pattern cannot have flags."); + if (pleaf->ptntype == C2_L_PTINT) { + if (pleaf->match) { + c2_error("Integer/boolean pattern cannot have operator " + "qualifiers."); + } + if (pleaf->match_ignorecase) { + c2_error("Integer/boolean pattern cannot have flags."); + } } if (C2_L_PTSTRING == pleaf->ptntype && @@ -1089,22 +1048,17 @@ static int c2_parse_legacy(const char *pattern, int offset, c2_ptr_t *presult) { presult->isbranch = false; presult->l = pleaf; memcpy(pleaf, &leaf_def, sizeof(c2_l_t)); - pleaf->type = C2_L_TSTRING; pleaf->op = C2_L_OEQ; pleaf->ptntype = C2_L_PTSTRING; // Determine the pattern target -#define TGTFILL(pdefid) \ - pleaf->predef = (pdefid); \ - pleaf->type = C2_PREDEFS[pdefid].type; switch (pattern[offset]) { - case 'n': TGTFILL(C2_L_PNAME); break; - case 'i': TGTFILL(C2_L_PCLASSI); break; - case 'g': TGTFILL(C2_L_PCLASSG); break; - case 'r': TGTFILL(C2_L_PROLE); break; + case 'n': pleaf->predef = C2_L_PNAME; break; + case 'i': pleaf->predef = C2_L_PCLASSI; break; + case 'g': pleaf->predef = C2_L_PCLASSG; break; + case 'r': pleaf->predef = C2_L_PROLE; break; default: c2_error("Target \"%c\" invalid.\n", pattern[offset]); } -#undef TGTFILL offset += 2; @@ -1144,11 +1098,6 @@ fail: * Do postprocessing on a condition leaf. */ static bool c2_l_postprocess(struct c2_state *state, xcb_connection_t *c, c2_l_t *pleaf) { - // Give a pattern type to a leaf with exists operator, if needed - if (C2_L_OEXISTS == pleaf->op && !pleaf->ptntype) { - pleaf->ptntype = (C2_L_TSTRING == pleaf->type ? C2_L_PTSTRING : C2_L_PTINT); - } - // Get target atom if it's not a predefined one if (pleaf->predef == C2_L_PUNDEFINED) { pleaf->tgtatom = get_atom_with_nul(state->atoms, pleaf->tgt, c); @@ -1171,18 +1120,6 @@ static bool c2_l_postprocess(struct c2_state *state, xcb_connection_t *c, c2_l_t property->key = key; HASH_ADD_KEYPTR(hh, state->tracked_properties, &property->key, sizeof(property->key), property); - property->is_string = pleaf->type == C2_L_TSTRING; - } else { - if (property->is_string != (pleaf->type == C2_L_TSTRING)) { - log_error("Type mismatch for property \"%s\", %s a " - "string, now %s. Offending rule is: %s, it " - "will be disabled.", - pleaf->tgt, property->is_string ? "was" : "wasn't", - pleaf->type == C2_L_TSTRING ? "is" : "isn't", - c2_condition_to_str2( - (c2_ptr_t){.isbranch = false, .l = pleaf})); - return false; - } } } @@ -1311,27 +1248,11 @@ c2_lptr_t *c2_free_lptr(c2_lptr_t *lp, c2_userdata_free f) { */ static const char *c2h_dump_str_tgt(const c2_l_t *pleaf) { if (pleaf->predef != C2_L_PUNDEFINED) { - return C2_PREDEFS[pleaf->predef].name; + return C2_PREDEFS[pleaf->predef]; } return pleaf->tgt; } -/** - * Get a string representation of a target. - */ -static const char *c2h_dump_str_type(const c2_l_t *pleaf) { - switch (pleaf->type) { - case C2_L_TWINDOW: return "w"; - case C2_L_TDRAWABLE: return "d"; - case C2_L_TCARDINAL: return "c"; - case C2_L_TSTRING: return "s"; - case C2_L_TATOM: return "a"; - case C2_L_TUNDEFINED: break; - } - - return NULL; -} - /** * Dump a condition tree to string. Return the number of characters that * would have been written if the buffer had been large enough, excluding @@ -1416,10 +1337,6 @@ static size_t c2_condition_to_str(c2_ptr_t p, char *output, size_t len) { } } - const char *type_str = c2h_dump_str_type(pleaf); - push_char(':'); - push_str(type_str); - if (C2_L_OEXISTS == pleaf->op) { return offset; } @@ -1509,21 +1426,6 @@ static const char *c2_condition_to_str2(c2_ptr_t ptr) { return buf; } -/** - * Get the type atom of a condition. - */ -static xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf) { - switch (pleaf->type) { - case C2_L_TCARDINAL: return XCB_ATOM_CARDINAL; - case C2_L_TWINDOW: return XCB_ATOM_WINDOW; - case C2_L_TSTRING: return XCB_ATOM_STRING; - case C2_L_TATOM: return XCB_ATOM_ATOM; - case C2_L_TDRAWABLE: return XCB_ATOM_DRAWABLE; - default: assert(0); break; - } - unreachable(); -} - /** * Match a window against a single leaf window condition. * @@ -1541,8 +1443,17 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w } const int idx = (pleaf->index < 0 ? 0 : pleaf->index); + auto type = pleaf->ptntype; + if (type == C2_L_PTUNDEFINED) { + auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom); + if (x_is_type_string(ps->atoms, prop_info.type)) { + type = C2_L_PTSTRING; + } else { + type = C2_L_PTINT; + } + } - switch (pleaf->ptntype) { + switch (type) { // Deal with integer patterns case C2_L_PTINT: { long long *targets = NULL; @@ -1590,9 +1501,8 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom); word_count = to_int_checked((prop_info.length + 4 - 1) / 4); } - winprop_t prop = - x_get_prop_with_offset(&ps->c, wid, pleaf->tgtatom, idx, - word_count, c2_get_atom_type(pleaf), 0); + winprop_t prop = x_get_prop_with_offset( + &ps->c, wid, pleaf->tgtatom, idx, word_count, 0, 0); ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1)); if (ntargets > 0) { @@ -1642,6 +1552,10 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w const char **targets_free = NULL; const char **targets_free_inner = NULL; size_t ntargets = 0; + winprop_info_t prop_info = {0}; + if (pleaf->predef == C2_L_PUNDEFINED) { + prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom); + } // A predefined target const char *predef_target = NULL; @@ -1658,18 +1572,15 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w } ntargets = 1; targets = &predef_target; - } - // An atom type property, convert it to string - else if (pleaf->type == C2_L_TATOM) { + } else if (prop_info.type == XCB_ATOM_ATOM) { + // An atom type property, convert it to string int word_count = 1; if (pleaf->index < 0) { // Get length of property in 32-bit multiples - auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom); word_count = to_int_checked((prop_info.length + 4 - 1) / 4); } - winprop_t prop = - x_get_prop_with_offset(&ps->c, wid, pleaf->tgtatom, idx, - word_count, c2_get_atom_type(pleaf), 0); + winprop_t prop = x_get_prop_with_offset( + &ps->c, wid, pleaf->tgtatom, idx, word_count, XCB_ATOM_ATOM, 0); ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1)); targets = targets_free = (const char **)ccalloc(2 * ntargets, char *); @@ -1689,9 +1600,8 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w } } free_winprop(&prop); - } - // Not an atom type, just fetch the string list - else { + } else { + // Not an atom type, just fetch the string list char **strlst = NULL; int nstr = 0; if (wid_get_text_prop(&ps->c, ps->atoms, wid, pleaf->tgtatom, @@ -1792,7 +1702,7 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w free(targets_free); } } break; - default: assert(0); break; + default: unreachable(); } } diff --git a/src/x.c b/src/x.c index a5f25ab2..c82bd984 100644 --- a/src/x.c +++ b/src/x.c @@ -193,7 +193,7 @@ bool wid_get_text_prop(struct x_connection *c, struct atom *atoms, xcb_window_t return false; } - if (type != XCB_ATOM_STRING && type != atoms->aUTF8_STRING && type != atoms->aC_STRING) { + if (!x_is_type_string(atoms, type)) { log_warn("Text property %d of window %#010x has unsupported type: %d", prop, wid, type); return false; diff --git a/src/x.h b/src/x.h index 78cd55d2..9041a7c7 100644 --- a/src/x.h +++ b/src/x.h @@ -11,6 +11,7 @@ #include #include +#include "atom.h" #include "compiler.h" #include "kernel.h" #include "log.h" @@ -264,6 +265,11 @@ xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_a bool wid_get_text_prop(struct x_connection *c, struct atom *atoms, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst, int *pnstr); +static inline bool x_is_type_string(struct atom *atoms, xcb_atom_t type) { + return type == XCB_ATOM_STRING || type == atoms->aUTF8_STRING || + type == atoms->aC_STRING; +} + const xcb_render_pictforminfo_t * x_get_pictform_for_visual(struct x_connection *, xcb_visualid_t);