mirror of https://github.com/yshui/picom.git
Merge pull request #550 from tryone144/property-array-matching
c2: Perform matching against "all" property values with special index `[*]`
This commit is contained in:
commit
8802057ff3
|
@ -280,11 +280,11 @@ 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`, `width`, `height`, `widthb` (width + 2 * `border_width`), `heightb`, `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]`), 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.
|
||||
'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.
|
||||
|
||||
'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.
|
||||
|
||||
|
@ -313,6 +313,11 @@ Examples:
|
|||
# If the window is a menu
|
||||
window_type *= "menu"
|
||||
_NET_WM_WINDOW_TYPE@:a *= "MENU"
|
||||
# If the window is marked hidden: _NET_WM_STATE contains _NET_WM_STATE_HIDDEN
|
||||
_NET_WM_STATE@[*]:a = "_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"
|
||||
# If the window name contains "Firefox", ignore case
|
||||
name *?= "Firefox"
|
||||
_NET_WM_NAME@:s *?= "Firefox"
|
||||
|
|
329
src/c2.c
329
src/c2.c
|
@ -159,7 +159,7 @@ struct _c2_l {
|
|||
{ \
|
||||
.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, \
|
||||
.predef = C2_L_PUNDEFINED, .index = 0, .type = C2_L_TUNDEFINED, \
|
||||
.format = 0, .ptntype = C2_L_PTUNDEFINED, .ptnstr = NULL, .ptnint = 0, \
|
||||
}
|
||||
|
||||
|
@ -214,17 +214,17 @@ static const c2_predef_t C2_PREDEFS[] = {
|
|||
/**
|
||||
* Get the numeric property value from a win_prop_t.
|
||||
*/
|
||||
static inline long winprop_get_int(winprop_t prop) {
|
||||
static inline long winprop_get_int(winprop_t prop, size_t index) {
|
||||
long tgt = 0;
|
||||
|
||||
if (!prop.nitems) {
|
||||
if (!prop.nitems || index >= prop.nitems) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (prop.format) {
|
||||
case 8: tgt = *(prop.p8); break;
|
||||
case 16: tgt = *(prop.p16); break;
|
||||
case 32: tgt = *(prop.p32); break;
|
||||
case 8: tgt = *(prop.p8 + index); break;
|
||||
case 16: tgt = *(prop.p16 + index); break;
|
||||
case 32: tgt = *(prop.p32 + index); break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
|
||||
|
@ -611,24 +611,30 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) {
|
|||
|
||||
// Parse index
|
||||
if ('[' == pattern[offset]) {
|
||||
if (pleaf->predef != C2_L_PUNDEFINED) {
|
||||
c2_error("Predefined targets can't have index.");
|
||||
}
|
||||
|
||||
offset++;
|
||||
|
||||
C2H_SKIP_SPACES();
|
||||
|
||||
long index = -1;
|
||||
char *endptr = NULL;
|
||||
const char *endptr = NULL;
|
||||
|
||||
index = strtol(pattern + offset, &endptr, 0);
|
||||
if ('*' == pattern[offset]) {
|
||||
index = -1;
|
||||
endptr = pattern + offset + 1;
|
||||
} else {
|
||||
index = strtol(pattern + offset, (char **)&endptr, 0);
|
||||
if (index < 0) {
|
||||
c2_error("Index number invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!endptr || pattern + offset == endptr) {
|
||||
c2_error("No index number found after bracket.");
|
||||
}
|
||||
if (index < 0) {
|
||||
c2_error("Index number invalid.");
|
||||
}
|
||||
if (pleaf->predef != C2_L_PUNDEFINED) {
|
||||
c2_error("Predefined targets can't have index.");
|
||||
}
|
||||
|
||||
pleaf->index = to_int_checked(index);
|
||||
offset = to_int_checked(endptr - pattern);
|
||||
|
@ -678,9 +684,10 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) {
|
|||
log_warn("Type specified for a default target "
|
||||
"will be ignored.");
|
||||
} else {
|
||||
if (pleaf->type && type != pleaf->type)
|
||||
if (pleaf->type && type != pleaf->type) {
|
||||
log_warn("Default type overridden on "
|
||||
"target.");
|
||||
}
|
||||
pleaf->type = type;
|
||||
}
|
||||
}
|
||||
|
@ -710,23 +717,26 @@ static int c2_parse_target(const char *pattern, int offset, c2_ptr_t *presult) {
|
|||
"will be ignored.",
|
||||
format);
|
||||
} else {
|
||||
if (pleaf->format && pleaf->format != format)
|
||||
if (pleaf->format && pleaf->format != format) {
|
||||
log_warn("Default format %d overridden on "
|
||||
"target.",
|
||||
pleaf->format);
|
||||
}
|
||||
pleaf->format = to_int_checked(format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pleaf->type)
|
||||
if (!pleaf->type) {
|
||||
c2_error("Target type cannot be determined.");
|
||||
}
|
||||
|
||||
// if (!pleaf->predef && !pleaf->format && C2_L_TSTRING != pleaf->type)
|
||||
// c2_error("Target format cannot be determined.");
|
||||
|
||||
if (pleaf->format && 8 != pleaf->format && 16 != pleaf->format && 32 != pleaf->format)
|
||||
if (pleaf->format && 8 != pleaf->format && 16 != pleaf->format && 32 != pleaf->format) {
|
||||
c2_error("Invalid format.");
|
||||
}
|
||||
|
||||
return offset;
|
||||
|
||||
|
@ -1184,11 +1194,13 @@ static void c2_dump(c2_ptr_t p) {
|
|||
if (p.isbranch) {
|
||||
const c2_b_t *const pbranch = p.b;
|
||||
|
||||
if (!pbranch)
|
||||
if (!pbranch) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pbranch->neg)
|
||||
if (pbranch->neg) {
|
||||
putchar('!');
|
||||
}
|
||||
|
||||
printf("(");
|
||||
c2_dump(pbranch->opr1);
|
||||
|
@ -1207,27 +1219,36 @@ static void c2_dump(c2_ptr_t p) {
|
|||
else {
|
||||
const c2_l_t *const pleaf = p.l;
|
||||
|
||||
if (!pleaf)
|
||||
if (!pleaf) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (C2_L_OEXISTS == pleaf->op && pleaf->neg)
|
||||
if (C2_L_OEXISTS == pleaf->op && pleaf->neg) {
|
||||
putchar('!');
|
||||
}
|
||||
|
||||
// Print target name, type, and format
|
||||
{
|
||||
printf("%s", c2h_dump_str_tgt(pleaf));
|
||||
if (pleaf->tgt_onframe)
|
||||
if (pleaf->tgt_onframe) {
|
||||
putchar('@');
|
||||
if (pleaf->index >= 0)
|
||||
printf("[%d]", pleaf->index);
|
||||
}
|
||||
if (pleaf->predef == C2_L_PUNDEFINED) {
|
||||
if (pleaf->index < 0) {
|
||||
printf("[*]");
|
||||
} else {
|
||||
printf("[%d]", pleaf->index);
|
||||
}
|
||||
}
|
||||
printf(":%d%s", pleaf->format, c2h_dump_str_type(pleaf));
|
||||
}
|
||||
|
||||
// Print operator
|
||||
putchar(' ');
|
||||
|
||||
if (C2_L_OEXISTS != pleaf->op && pleaf->neg)
|
||||
if (C2_L_OEXISTS != pleaf->op && pleaf->neg) {
|
||||
putchar('!');
|
||||
}
|
||||
|
||||
switch (pleaf->match) {
|
||||
case C2_L_MEXACT: break;
|
||||
|
@ -1237,8 +1258,9 @@ static void c2_dump(c2_ptr_t p) {
|
|||
case C2_L_MWILDCARD: putchar('%'); break;
|
||||
}
|
||||
|
||||
if (pleaf->match_ignorecase)
|
||||
if (pleaf->match_ignorecase) {
|
||||
putchar('?');
|
||||
}
|
||||
|
||||
switch (pleaf->op) {
|
||||
case C2_L_OEXISTS: break;
|
||||
|
@ -1249,8 +1271,9 @@ static void c2_dump(c2_ptr_t p) {
|
|||
case C2_L_OLTEQ: fputs("<=", stdout); break;
|
||||
}
|
||||
|
||||
if (C2_L_OEXISTS == pleaf->op)
|
||||
if (C2_L_OEXISTS == pleaf->op) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Print pattern
|
||||
putchar(' ');
|
||||
|
@ -1301,11 +1324,14 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
switch (pleaf->ptntype) {
|
||||
// Deal with integer patterns
|
||||
case C2_L_PTINT: {
|
||||
long tgt = 0;
|
||||
long *targets = NULL;
|
||||
long *targets_free = NULL;
|
||||
size_t ntargets = 0;
|
||||
|
||||
// Get the value
|
||||
// A predefined target
|
||||
if (pleaf->predef != C2_L_PUNDEFINED) {
|
||||
long tgt = 0;
|
||||
*perr = false;
|
||||
switch (pleaf->predef) {
|
||||
case C2_L_PID: tgt = wid; break;
|
||||
|
@ -1332,45 +1358,73 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
assert(0);
|
||||
break;
|
||||
}
|
||||
ntargets = 1;
|
||||
targets = &tgt;
|
||||
}
|
||||
// A raw window property
|
||||
else {
|
||||
int word_count = 1;
|
||||
if (pleaf->index < 0) {
|
||||
// Get length of property in 32-bit multiples
|
||||
auto prop_info = x_get_prop_info(ps, wid, pleaf->tgtatom);
|
||||
word_count = to_int_checked((prop_info.length + 4 - 1) / 4);
|
||||
}
|
||||
winprop_t prop =
|
||||
x_get_prop_with_offset(ps, wid, pleaf->tgtatom, idx, 1L,
|
||||
x_get_prop_with_offset(ps, wid, pleaf->tgtatom, idx, word_count,
|
||||
c2_get_atom_type(pleaf), pleaf->format);
|
||||
if (prop.nitems) {
|
||||
|
||||
ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1));
|
||||
if (ntargets > 0) {
|
||||
targets = targets_free = ccalloc(ntargets, long);
|
||||
*perr = false;
|
||||
tgt = winprop_get_int(prop);
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
targets[i] = winprop_get_int(prop, i);
|
||||
}
|
||||
}
|
||||
free_winprop(&prop);
|
||||
}
|
||||
|
||||
if (*perr)
|
||||
return;
|
||||
if (*perr) {
|
||||
goto fail_int;
|
||||
}
|
||||
|
||||
// Do comparison
|
||||
switch (pleaf->op) {
|
||||
case C2_L_OEXISTS:
|
||||
*pres = (pleaf->predef != C2_L_PUNDEFINED ? tgt : true);
|
||||
break;
|
||||
case C2_L_OEQ: *pres = (tgt == pleaf->ptnint); break;
|
||||
case C2_L_OGT: *pres = (tgt > pleaf->ptnint); break;
|
||||
case C2_L_OGTEQ: *pres = (tgt >= pleaf->ptnint); break;
|
||||
case C2_L_OLT: *pres = (tgt < pleaf->ptnint); break;
|
||||
case C2_L_OLTEQ: *pres = (tgt <= pleaf->ptnint); break;
|
||||
default:
|
||||
*perr = true;
|
||||
assert(0);
|
||||
break;
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
long tgt = targets[i];
|
||||
switch (pleaf->op) {
|
||||
case C2_L_OEXISTS:
|
||||
res = (pleaf->predef != C2_L_PUNDEFINED ? tgt : true);
|
||||
break;
|
||||
case C2_L_OEQ: res = (tgt == pleaf->ptnint); break;
|
||||
case C2_L_OGT: res = (tgt > pleaf->ptnint); break;
|
||||
case C2_L_OGTEQ: res = (tgt >= pleaf->ptnint); break;
|
||||
case C2_L_OLT: res = (tgt < pleaf->ptnint); break;
|
||||
case C2_L_OLTEQ: res = (tgt <= pleaf->ptnint); break;
|
||||
default: *perr = true; assert(0);
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pres = res;
|
||||
|
||||
fail_int:
|
||||
// Free property values after usage, if necessary
|
||||
if (targets_free) {
|
||||
free(targets_free);
|
||||
}
|
||||
} break;
|
||||
// String patterns
|
||||
case C2_L_PTSTRING: {
|
||||
const char *tgt = NULL;
|
||||
char *tgt_free = NULL;
|
||||
const char **targets = NULL;
|
||||
const char **targets_free = NULL;
|
||||
const char **targets_free_inner = NULL;
|
||||
size_t ntargets = 0;
|
||||
|
||||
// A predefined target
|
||||
if (pleaf->predef != C2_L_PUNDEFINED) {
|
||||
const char *tgt = NULL;
|
||||
switch (pleaf->predef) {
|
||||
case C2_L_PWINDOWTYPE: tgt = WINTYPES[w->window_type]; break;
|
||||
case C2_L_PNAME: tgt = w->name; break;
|
||||
|
@ -1379,95 +1433,138 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
case C2_L_PROLE: tgt = w->role; break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
} else if (pleaf->type == C2_L_TATOM) {
|
||||
// An atom type property, convert it to string
|
||||
ntargets = 1;
|
||||
targets = &tgt;
|
||||
}
|
||||
// An atom type property, convert it to string
|
||||
else if (pleaf->type == C2_L_TATOM) {
|
||||
int word_count = 1;
|
||||
if (pleaf->index < 0) {
|
||||
// Get length of property in 32-bit multiples
|
||||
auto prop_info = x_get_prop_info(ps, wid, pleaf->tgtatom);
|
||||
word_count = to_int_checked((prop_info.length + 4 - 1) / 4);
|
||||
}
|
||||
winprop_t prop =
|
||||
x_get_prop_with_offset(ps, wid, pleaf->tgtatom, idx, 1L,
|
||||
x_get_prop_with_offset(ps, wid, pleaf->tgtatom, idx, word_count,
|
||||
c2_get_atom_type(pleaf), pleaf->format);
|
||||
xcb_atom_t atom = (xcb_atom_t)winprop_get_int(prop);
|
||||
if (atom) {
|
||||
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
|
||||
ps->c, xcb_get_atom_name(ps->c, atom), NULL);
|
||||
if (reply) {
|
||||
tgt_free = strndup(
|
||||
xcb_get_atom_name_name(reply),
|
||||
(size_t)xcb_get_atom_name_name_length(reply));
|
||||
free(reply);
|
||||
|
||||
ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1));
|
||||
targets = targets_free = (const char **)ccalloc(2 * ntargets, char *);
|
||||
targets_free_inner = targets + ntargets;
|
||||
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
xcb_atom_t atom = (xcb_atom_t)winprop_get_int(prop, i);
|
||||
if (atom) {
|
||||
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
|
||||
ps->c, xcb_get_atom_name(ps->c, atom), NULL);
|
||||
if (reply) {
|
||||
targets[i] = targets_free_inner[i] = strndup(
|
||||
xcb_get_atom_name_name(reply),
|
||||
(size_t)xcb_get_atom_name_name_length(reply));
|
||||
free(reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tgt_free) {
|
||||
tgt = tgt_free;
|
||||
}
|
||||
free_winprop(&prop);
|
||||
} else {
|
||||
// Not an atom type, just fetch the string list
|
||||
}
|
||||
// Not an atom type, just fetch the string list
|
||||
else {
|
||||
char **strlst = NULL;
|
||||
int nstr;
|
||||
if (wid_get_text_prop(ps, wid, pleaf->tgtatom, &strlst, &nstr) &&
|
||||
nstr > idx) {
|
||||
tgt_free = strdup(strlst[idx]);
|
||||
tgt = tgt_free;
|
||||
int nstr = 0;
|
||||
if (wid_get_text_prop(ps, wid, pleaf->tgtatom, &strlst, &nstr)) {
|
||||
if (pleaf->index < 0 && nstr > 0 && strlen(strlst[0]) > 0) {
|
||||
ntargets = to_u32_checked(nstr);
|
||||
targets = (const char **)strlst;
|
||||
} else if (nstr > idx) {
|
||||
ntargets = 1;
|
||||
targets = (const char **)strlst + idx;
|
||||
}
|
||||
}
|
||||
if (strlst) {
|
||||
free(strlst);
|
||||
targets_free = (const char **)strlst;
|
||||
}
|
||||
}
|
||||
|
||||
if (tgt) {
|
||||
*perr = false;
|
||||
} else {
|
||||
return;
|
||||
if (ntargets == 0) {
|
||||
goto fail_str;
|
||||
}
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
if (!targets[i]) {
|
||||
goto fail_str;
|
||||
}
|
||||
}
|
||||
*perr = false;
|
||||
|
||||
// Actual matching
|
||||
switch (pleaf->op) {
|
||||
case C2_L_OEXISTS: *pres = true; break;
|
||||
case C2_L_OEQ:
|
||||
switch (pleaf->match) {
|
||||
case C2_L_MEXACT:
|
||||
if (pleaf->match_ignorecase)
|
||||
*pres = !strcasecmp(tgt, pleaf->ptnstr);
|
||||
else
|
||||
*pres = !strcmp(tgt, pleaf->ptnstr);
|
||||
break;
|
||||
case C2_L_MCONTAINS:
|
||||
if (pleaf->match_ignorecase)
|
||||
*pres = strcasestr(tgt, pleaf->ptnstr);
|
||||
else
|
||||
*pres = strstr(tgt, pleaf->ptnstr);
|
||||
break;
|
||||
case C2_L_MSTART:
|
||||
if (pleaf->match_ignorecase)
|
||||
*pres = !strncasecmp(tgt, pleaf->ptnstr,
|
||||
strlen(pleaf->ptnstr));
|
||||
else
|
||||
*pres = !strncmp(tgt, pleaf->ptnstr,
|
||||
strlen(pleaf->ptnstr));
|
||||
break;
|
||||
case C2_L_MWILDCARD: {
|
||||
int flags = 0;
|
||||
if (pleaf->match_ignorecase)
|
||||
flags |= FNM_CASEFOLD;
|
||||
*pres = !fnmatch(pleaf->ptnstr, tgt, flags);
|
||||
} break;
|
||||
case C2_L_MPCRE:
|
||||
bool res = false;
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
const char *tgt = targets[i];
|
||||
switch (pleaf->op) {
|
||||
case C2_L_OEXISTS: res = true; break;
|
||||
case C2_L_OEQ:
|
||||
switch (pleaf->match) {
|
||||
case C2_L_MEXACT:
|
||||
if (pleaf->match_ignorecase) {
|
||||
res = !strcasecmp(tgt, pleaf->ptnstr);
|
||||
} else {
|
||||
res = !strcmp(tgt, pleaf->ptnstr);
|
||||
}
|
||||
break;
|
||||
case C2_L_MCONTAINS:
|
||||
if (pleaf->match_ignorecase) {
|
||||
res = strcasestr(tgt, pleaf->ptnstr);
|
||||
} else {
|
||||
res = strstr(tgt, pleaf->ptnstr);
|
||||
}
|
||||
break;
|
||||
case C2_L_MSTART:
|
||||
if (pleaf->match_ignorecase) {
|
||||
res = !strncasecmp(tgt, pleaf->ptnstr,
|
||||
strlen(pleaf->ptnstr));
|
||||
} else {
|
||||
res = !strncmp(tgt, pleaf->ptnstr,
|
||||
strlen(pleaf->ptnstr));
|
||||
}
|
||||
break;
|
||||
case C2_L_MWILDCARD: {
|
||||
int flags = 0;
|
||||
if (pleaf->match_ignorecase) {
|
||||
flags |= FNM_CASEFOLD;
|
||||
}
|
||||
res = !fnmatch(pleaf->ptnstr, tgt, flags);
|
||||
} break;
|
||||
case C2_L_MPCRE:
|
||||
#ifdef CONFIG_REGEX_PCRE
|
||||
assert(strlen(tgt) <= INT_MAX);
|
||||
*pres =
|
||||
(pcre_exec(pleaf->regex_pcre, pleaf->regex_pcre_extra,
|
||||
tgt, (int)strlen(tgt), 0, 0, NULL, 0) >= 0);
|
||||
assert(strlen(tgt) <= INT_MAX);
|
||||
res = (pcre_exec(pleaf->regex_pcre,
|
||||
pleaf->regex_pcre_extra, tgt,
|
||||
(int)strlen(tgt), 0, 0, NULL, 0) >= 0);
|
||||
#else
|
||||
assert(0);
|
||||
assert(0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: *perr = true; assert(0);
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: *perr = true; assert(0);
|
||||
}
|
||||
*pres = res;
|
||||
|
||||
fail_str:
|
||||
// Free the string after usage, if necessary
|
||||
if (tgt_free) {
|
||||
free(tgt_free);
|
||||
if (targets_free_inner) {
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
if (targets_free_inner[i]) {
|
||||
free((void *)targets_free_inner[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Free property values after usage, if necessary
|
||||
if (targets_free) {
|
||||
free(targets_free);
|
||||
}
|
||||
} break;
|
||||
default: assert(0); break;
|
||||
|
|
42
src/x.c
42
src/x.c
|
@ -69,6 +69,25 @@ winprop_t x_get_prop_with_offset(const session_t *ps, xcb_window_t w, xcb_atom_t
|
|||
.ptr = NULL, .nitems = 0, .type = XCB_GET_PROPERTY_TYPE_ANY, .format = 0};
|
||||
}
|
||||
|
||||
/// Get the type, format and size in bytes of a window's specific attribute.
|
||||
winprop_info_t x_get_prop_info(const session_t *ps, xcb_window_t w, xcb_atom_t atom) {
|
||||
xcb_generic_error_t *e = NULL;
|
||||
auto r = xcb_get_property_reply(
|
||||
ps->c, xcb_get_property(ps->c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e);
|
||||
if (!r) {
|
||||
log_debug_x_error(e, "Failed to get property info for window %#010x", w);
|
||||
free(e);
|
||||
return (winprop_info_t){
|
||||
.type = XCB_GET_PROPERTY_TYPE_ANY, .format = 0, .length = 0};
|
||||
}
|
||||
|
||||
winprop_info_t winprop_info = {
|
||||
.type = r->type, .format = r->format, .length = r->bytes_after};
|
||||
free(r);
|
||||
|
||||
return winprop_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a type-<code>xcb_window_t</code> property of a window.
|
||||
*
|
||||
|
@ -95,19 +114,10 @@ xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t apr
|
|||
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
|
||||
int *pnstr) {
|
||||
assert(ps->server_grabbed);
|
||||
xcb_generic_error_t *e = NULL;
|
||||
auto r = xcb_get_property_reply(
|
||||
ps->c, xcb_get_property(ps->c, 0, wid, prop, XCB_ATOM_ANY, 0, 0), &e);
|
||||
if (!r) {
|
||||
log_debug_x_error(e, "Failed to get window property for %#010x", wid);
|
||||
free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto type = r->type;
|
||||
auto format = r->format;
|
||||
auto length = r->bytes_after;
|
||||
free(r);
|
||||
auto prop_info = x_get_prop_info(ps, wid, prop);
|
||||
auto type = prop_info.type;
|
||||
auto format = prop_info.format;
|
||||
auto length = prop_info.length;
|
||||
|
||||
if (type == XCB_ATOM_NONE) {
|
||||
return false;
|
||||
|
@ -126,8 +136,10 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
|
|||
return false;
|
||||
}
|
||||
|
||||
r = xcb_get_property_reply(
|
||||
ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, length), &e);
|
||||
xcb_generic_error_t *e = NULL;
|
||||
auto word_count = (length + 4 - 1) / 4;
|
||||
auto r = xcb_get_property_reply(
|
||||
ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, word_count), &e);
|
||||
if (!r) {
|
||||
log_debug_x_error(e, "Failed to get window property for %#010x", wid);
|
||||
free(e);
|
||||
|
|
9
src/x.h
9
src/x.h
|
@ -33,6 +33,12 @@ typedef struct winprop {
|
|||
xcb_get_property_reply_t *r;
|
||||
} winprop_t;
|
||||
|
||||
typedef struct winprop_info {
|
||||
xcb_atom_t type;
|
||||
uint8_t format;
|
||||
uint32_t length;
|
||||
} winprop_info_t;
|
||||
|
||||
struct xvisual_info {
|
||||
/// Bit depth of the red component
|
||||
int red_size;
|
||||
|
@ -129,6 +135,9 @@ static inline winprop_t x_get_prop(const session_t *ps, xcb_window_t wid, xcb_at
|
|||
return x_get_prop_with_offset(ps, wid, atom, 0L, length, rtype, rformat);
|
||||
}
|
||||
|
||||
/// Get the type, format and size in bytes of a window's specific attribute.
|
||||
winprop_info_t x_get_prop_info(const session_t *ps, xcb_window_t w, xcb_atom_t atom);
|
||||
|
||||
/// Discard all X events in queue or in flight. Should only be used when the server is
|
||||
/// grabbed
|
||||
static inline void x_discard_events(xcb_connection_t *c) {
|
||||
|
|
Loading…
Reference in New Issue