mirror of https://github.com/yshui/picom.git
win, c2: cache properties used in rule-matching
Cache the property-values that are used in rule-matching for each window. Entries are evicted when the respective property changes.
This commit is contained in:
parent
208a1f32af
commit
7119207dee
259
src/c2.c
259
src/c2.c
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdalign.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -212,7 +213,7 @@ static const c2_predef_t C2_PREDEFS[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Get the numeric property value from a win_prop_t.
|
||||
* Get the numeric property value from a winprop_t.
|
||||
*/
|
||||
static inline long winprop_get_int(winprop_t prop, size_t index) {
|
||||
long tgt = 0;
|
||||
|
@ -231,6 +232,68 @@ static inline long winprop_get_int(winprop_t prop, size_t index) {
|
|||
return tgt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string representation of all atom values of a winprop_t.
|
||||
*
|
||||
* TODO(tryone144): Is this better off in x.c?
|
||||
*/
|
||||
static inline bool
|
||||
winprop_get_atoms(session_t *ps, const winprop_t prop, char ***pstrlst, size_t *pnstr) {
|
||||
if (prop.nitems == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query atom names from the X server
|
||||
auto name_cookies = ccalloc(prop.nitems, xcb_get_atom_name_cookie_t);
|
||||
auto name_replies = ccalloc(prop.nitems, xcb_get_atom_name_reply_t *);
|
||||
size_t cookie_count = 0;
|
||||
size_t reply_count = 0;
|
||||
size_t length = 0;
|
||||
|
||||
for (size_t i = 0; i < prop.nitems; ++i) {
|
||||
auto atom = (xcb_atom_t)winprop_get_int(prop, i);
|
||||
if (atom) {
|
||||
name_cookies[cookie_count] = xcb_get_atom_name(ps->c, atom);
|
||||
++cookie_count;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < cookie_count; ++i) {
|
||||
auto reply = xcb_get_atom_name_reply(ps->c, name_cookies[i], NULL);
|
||||
if (reply) {
|
||||
name_replies[reply_count] = reply;
|
||||
++reply_count;
|
||||
length += (size_t)xcb_get_atom_name_name_length(reply) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the pointers and the strings together
|
||||
size_t nstr = reply_count;
|
||||
void *buf = NULL;
|
||||
if (posix_memalign(&buf, alignof(char *), length + sizeof(char *) * nstr + 1) != 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
char **ret = buf;
|
||||
char *strlst = buf + sizeof(char *) * nstr;
|
||||
for (size_t i = 0; i < nstr; ++i) {
|
||||
auto reply = name_replies[i];
|
||||
auto len = (size_t)xcb_get_atom_name_name_length(reply);
|
||||
memcpy(strlst, xcb_get_atom_name_name(reply), len);
|
||||
strlst[len] = '\0'; // atom name reply is not null terminated
|
||||
free(reply);
|
||||
|
||||
ret[i] = strlst;
|
||||
strlst += len + 1;
|
||||
}
|
||||
|
||||
free(name_cookies);
|
||||
free(name_replies);
|
||||
|
||||
*pnstr = nstr;
|
||||
*pstrlst = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare next word in a string with another string.
|
||||
*/
|
||||
|
@ -333,7 +396,7 @@ static void attr_unused c2_dump(c2_ptr_t p);
|
|||
|
||||
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, struct managed_win *w, const c2_ptr_t cond);
|
||||
|
||||
/**
|
||||
* Parse a condition string.
|
||||
|
@ -1308,7 +1371,7 @@ static xcb_atom_t c2_get_atom_type(const c2_l_t *pleaf) {
|
|||
*
|
||||
* For internal use.
|
||||
*/
|
||||
static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w,
|
||||
static inline void c2_match_once_leaf(session_t *ps, struct managed_win *w,
|
||||
const c2_l_t *pleaf, bool *pres, bool *perr) {
|
||||
assert(pleaf);
|
||||
|
||||
|
@ -1319,13 +1382,12 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
return;
|
||||
}
|
||||
|
||||
const int idx = (pleaf->index < 0 ? 0 : pleaf->index);
|
||||
const unsigned int idx = (unsigned int)(pleaf->index < 0 ? 0 : pleaf->index);
|
||||
|
||||
switch (pleaf->ptntype) {
|
||||
// Deal with integer patterns
|
||||
case C2_L_PTINT: {
|
||||
long *targets = NULL;
|
||||
long *targets_free = NULL;
|
||||
size_t ntargets = 0;
|
||||
|
||||
// Get the value
|
||||
|
@ -1367,30 +1429,52 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
}
|
||||
// A raw window property
|
||||
else {
|
||||
int word_count = 1;
|
||||
if (pleaf->index < 0) {
|
||||
struct property_cache *cached_prop;
|
||||
HASH_FIND_INT(w->cached_props, &pleaf->tgtatom, cached_prop);
|
||||
|
||||
if (!cached_prop) {
|
||||
cached_prop = ccalloc(1, struct property_cache);
|
||||
cached_prop->atom = pleaf->tgtatom;
|
||||
cached_prop->type = PROP_CACHE_TINT;
|
||||
HASH_ADD_INT(w->cached_props, atom, cached_prop);
|
||||
log_trace("Cache property %d for window %#010x",
|
||||
cached_prop->atom, wid);
|
||||
|
||||
// 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, word_count,
|
||||
c2_get_atom_type(pleaf), pleaf->format);
|
||||
int word_count =
|
||||
to_int_checked((prop_info.length + 4 - 1) / 4);
|
||||
winprop_t prop =
|
||||
x_get_prop(ps, wid, pleaf->tgtatom, word_count,
|
||||
c2_get_atom_type(pleaf), pleaf->format);
|
||||
|
||||
ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1));
|
||||
if (ntargets > 0) {
|
||||
targets = targets_free = ccalloc(ntargets, long);
|
||||
*perr = false;
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
targets[i] = winprop_get_int(prop, i);
|
||||
cached_prop->nitems = prop.nitems;
|
||||
cached_prop->items.integer =
|
||||
ccalloc(cached_prop->nitems, long);
|
||||
for (size_t i = 0; i < cached_prop->nitems; ++i) {
|
||||
cached_prop->items.integer[i] =
|
||||
winprop_get_int(prop, i);
|
||||
}
|
||||
free_winprop(&prop);
|
||||
} else {
|
||||
log_trace("Use cached property %d for window %#010x",
|
||||
cached_prop->atom, wid);
|
||||
}
|
||||
|
||||
assert(cached_prop->type == PROP_CACHE_TINT);
|
||||
if (idx < cached_prop->nitems) {
|
||||
ntargets = (pleaf->index < 0 ? cached_prop->nitems
|
||||
: min2(cached_prop->nitems, 1));
|
||||
if (ntargets > 0) {
|
||||
targets = cached_prop->items.integer + idx;
|
||||
}
|
||||
}
|
||||
free_winprop(&prop);
|
||||
}
|
||||
|
||||
if (*perr) {
|
||||
goto fail_int;
|
||||
if (ntargets == 0) {
|
||||
return;
|
||||
}
|
||||
*perr = false;
|
||||
|
||||
// Do comparison
|
||||
bool res = false;
|
||||
|
@ -1412,18 +1496,10 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
}
|
||||
}
|
||||
*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 **targets = NULL;
|
||||
const char **targets_free = NULL;
|
||||
const char **targets_free_inner = NULL;
|
||||
char **targets = NULL;
|
||||
size_t ntargets = 0;
|
||||
|
||||
// A predefined target
|
||||
|
@ -1440,63 +1516,77 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
default: assert(0); break;
|
||||
}
|
||||
ntargets = 1;
|
||||
targets = &predef_target;
|
||||
}
|
||||
// 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, word_count,
|
||||
c2_get_atom_type(pleaf), pleaf->format);
|
||||
targets = (char **)&predef_target;
|
||||
} else {
|
||||
struct property_cache *cached_prop;
|
||||
HASH_FIND_INT(w->cached_props, &pleaf->tgtatom, cached_prop);
|
||||
|
||||
ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1));
|
||||
targets = targets_free = (const char **)ccalloc(2 * ntargets, char *);
|
||||
targets_free_inner = targets + ntargets;
|
||||
if (!cached_prop) {
|
||||
cached_prop = ccalloc(1, struct property_cache);
|
||||
cached_prop->atom = pleaf->tgtatom;
|
||||
cached_prop->type = PROP_CACHE_TSTRING;
|
||||
HASH_ADD_INT(w->cached_props, atom, cached_prop);
|
||||
log_trace("Cache property %d for window %#010x",
|
||||
cached_prop->atom, wid);
|
||||
|
||||
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);
|
||||
// An atom type property, convert it to string
|
||||
if (pleaf->type == C2_L_TATOM) {
|
||||
// Get length of property in 32-bit multiples
|
||||
auto prop_info =
|
||||
x_get_prop_info(ps, wid, pleaf->tgtatom);
|
||||
int word_count =
|
||||
to_int_checked((prop_info.length + 4 - 1) / 4);
|
||||
winprop_t prop = x_get_prop(
|
||||
ps, wid, pleaf->tgtatom, word_count,
|
||||
c2_get_atom_type(pleaf), pleaf->format);
|
||||
|
||||
char **strlst = NULL;
|
||||
size_t nstr = 0;
|
||||
if (winprop_get_atoms(ps, prop, &strlst, &nstr)) {
|
||||
if (nstr > 0 && strlen(strlst[0]) > 0) {
|
||||
cached_prop->nitems = nstr;
|
||||
cached_prop->items.string = strlst;
|
||||
} else {
|
||||
free(strlst);
|
||||
}
|
||||
}
|
||||
free_winprop(&prop);
|
||||
}
|
||||
// Not an atom type, just fetch the string list
|
||||
else {
|
||||
char **strlst = NULL;
|
||||
size_t nstr = 0;
|
||||
if (wid_get_text_prop(ps, wid, pleaf->tgtatom,
|
||||
&strlst, &nstr)) {
|
||||
if (nstr > 0 && strlen(strlst[0]) > 0) {
|
||||
cached_prop->nitems = nstr;
|
||||
cached_prop->items.string = strlst;
|
||||
} else {
|
||||
free(strlst);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_trace("Use cached property %d for window %#010x",
|
||||
cached_prop->atom, wid);
|
||||
}
|
||||
free_winprop(&prop);
|
||||
}
|
||||
// Not an atom type, just fetch the string list
|
||||
else {
|
||||
char **strlst = NULL;
|
||||
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;
|
||||
|
||||
assert(cached_prop->type == PROP_CACHE_TSTRING);
|
||||
if (idx < cached_prop->nitems) {
|
||||
ntargets = (pleaf->index < 0 ? cached_prop->nitems
|
||||
: min2(cached_prop->nitems, 1));
|
||||
if (ntargets > 0) {
|
||||
targets = cached_prop->items.string + idx;
|
||||
}
|
||||
}
|
||||
if (strlst) {
|
||||
targets_free = (const char **)strlst;
|
||||
}
|
||||
}
|
||||
|
||||
if (ntargets == 0) {
|
||||
goto fail_str;
|
||||
if (ntargets == 0 || !targets) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < ntargets; ++i) {
|
||||
if (!targets[i]) {
|
||||
goto fail_str;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*perr = false;
|
||||
|
@ -1558,20 +1648,6 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
}
|
||||
}
|
||||
*pres = res;
|
||||
|
||||
fail_str:
|
||||
// Free the string after usage, if necessary
|
||||
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;
|
||||
}
|
||||
|
@ -1582,7 +1658,7 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w
|
|||
*
|
||||
* @return true if matched, false otherwise.
|
||||
*/
|
||||
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, struct managed_win *w, const c2_ptr_t cond) {
|
||||
bool result = false;
|
||||
bool error = true;
|
||||
|
||||
|
@ -1658,8 +1734,7 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p
|
|||
* @param pdata a place to return the data
|
||||
* @return true if matched, false otherwise.
|
||||
*/
|
||||
bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condlst,
|
||||
void **pdata) {
|
||||
bool c2_match(session_t *ps, struct managed_win *w, const c2_lptr_t *condlst, void **pdata) {
|
||||
assert(ps->server_grabbed);
|
||||
// Then go through the whole linked list
|
||||
for (; condlst; condlst = condlst->next) {
|
||||
|
|
2
src/c2.h
2
src/c2.h
|
@ -21,6 +21,6 @@ c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data);
|
|||
|
||||
c2_lptr_t *c2_free_lptr(c2_lptr_t *lp);
|
||||
|
||||
bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condlst, void **pdata);
|
||||
bool c2_match(session_t *ps, struct managed_win *w, const c2_lptr_t *condlst, void **pdata);
|
||||
|
||||
bool c2_list_postprocess(session_t *ps, c2_lptr_t *list);
|
||||
|
|
|
@ -574,11 +574,9 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
w = find_toplevel(ps, ev->window);
|
||||
}
|
||||
if (w) {
|
||||
// Set FACTOR_CHANGED so rules based on properties will be
|
||||
// re-evaluated.
|
||||
// Don't need to set property stale here, since that only
|
||||
// concerns properties we explicitly check.
|
||||
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
|
||||
// Explicitly mark property as stale so we don't have to
|
||||
// evict the whole cache
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
38
src/win.c
38
src/win.c
|
@ -376,6 +376,8 @@ void win_release_images(struct backend_base *backend, struct managed_win *w) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the `prop` property is stale
|
||||
static bool win_check_property_stale(struct managed_win *w, xcb_atom_t prop);
|
||||
/// Returns true if the `prop` property is stale, as well as clears the stale flag.
|
||||
static bool win_fetch_and_unset_property_stale(struct managed_win *w, xcb_atom_t prop);
|
||||
/// Returns true if any of the properties are stale, as well as clear all the stale flags.
|
||||
|
@ -384,6 +386,18 @@ static void win_clear_all_properties_stale(struct managed_win *w);
|
|||
/// Fetch new window properties from the X server, and run appropriate updates. Might set
|
||||
/// WIN_FLAGS_FACTOR_CHANGED
|
||||
static void win_update_properties(session_t *ps, struct managed_win *w) {
|
||||
// Evict previously cached property values
|
||||
struct property_cache *prop, *tmp_prop;
|
||||
HASH_ITER(hh, w->cached_props, prop, tmp_prop) {
|
||||
if (win_check_property_stale(w, prop->atom)) {
|
||||
log_trace("Evict cached property %d for window %#010x",
|
||||
prop->atom, w->base.id);
|
||||
HASH_DEL(w->cached_props, prop);
|
||||
free(prop->items.data);
|
||||
free(prop);
|
||||
}
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_WINDOW_TYPE)) {
|
||||
win_update_wintype(ps, w);
|
||||
}
|
||||
|
@ -609,7 +623,7 @@ static bool attr_pure win_has_rounded_corners(const struct managed_win *w) {
|
|||
|
||||
int win_update_name(session_t *ps, struct managed_win *w) {
|
||||
char **strlst = NULL;
|
||||
int nstr = 0;
|
||||
size_t nstr = 0;
|
||||
|
||||
if (!w->client_win) {
|
||||
return 0;
|
||||
|
@ -644,7 +658,7 @@ int win_update_name(session_t *ps, struct managed_win *w) {
|
|||
|
||||
static int win_update_role(session_t *ps, struct managed_win *w) {
|
||||
char **strlst = NULL;
|
||||
int nstr = 0;
|
||||
size_t nstr = 0;
|
||||
|
||||
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_WINDOW_ROLE, &strlst, &nstr)) {
|
||||
return -1;
|
||||
|
@ -1406,6 +1420,13 @@ void free_win_res(session_t *ps, struct managed_win *w) {
|
|||
free(w->stale_props);
|
||||
w->stale_props = NULL;
|
||||
w->stale_props_capacity = 0;
|
||||
|
||||
struct property_cache *prop, *tmp_prop;
|
||||
HASH_ITER(hh, w->cached_props, prop, tmp_prop) {
|
||||
HASH_DEL(w->cached_props, prop);
|
||||
free(prop->items.data);
|
||||
free(prop);
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a new window after list_node `prev`
|
||||
|
@ -1478,6 +1499,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
// change
|
||||
.stale_props = NULL,
|
||||
.stale_props_capacity = 0,
|
||||
.cached_props = NULL,
|
||||
|
||||
// Runtime variables, updated by dbus
|
||||
.fade_force = UNSET,
|
||||
|
@ -1755,7 +1777,7 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int
|
|||
*/
|
||||
bool win_update_class(session_t *ps, struct managed_win *w) {
|
||||
char **strlst = NULL;
|
||||
int nstr = 0;
|
||||
size_t nstr = 0;
|
||||
|
||||
// Can't do anything if there's no client window
|
||||
if (!w->client_win)
|
||||
|
@ -2704,6 +2726,16 @@ static void win_clear_all_properties_stale(struct managed_win *w) {
|
|||
win_clear_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
||||
}
|
||||
|
||||
static bool win_check_property_stale(struct managed_win *w, xcb_atom_t prop) {
|
||||
const auto bits_per_element = sizeof(*w->stale_props) * 8;
|
||||
if (prop >= w->stale_props_capacity * bits_per_element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto mask = 1UL << (prop % bits_per_element);
|
||||
return w->stale_props[prop / bits_per_element] & mask;
|
||||
}
|
||||
|
||||
static bool win_fetch_and_unset_property_stale(struct managed_win *w, xcb_atom_t prop) {
|
||||
const auto bits_per_element = sizeof(*w->stale_props) * 8;
|
||||
if (prop >= w->stale_props_capacity * bits_per_element) {
|
||||
|
|
22
src/win.h
22
src/win.h
|
@ -50,6 +50,26 @@ typedef struct {
|
|||
} glx_blur_cache_t;
|
||||
#endif
|
||||
|
||||
struct property_cache {
|
||||
UT_hash_handle hh;
|
||||
xcb_atom_t atom;
|
||||
size_t nitems;
|
||||
// XXX We can specify different types for the same atom given we have two rules.
|
||||
// Not sure if this is desired behaviour, but it breaks the cache.
|
||||
enum { PROP_CACHE_TUNDEFINED,
|
||||
PROP_CACHE_TINT,
|
||||
PROP_CACHE_TSTRING,
|
||||
} type;
|
||||
// TODO(tryone144): We should be fine with a simple (void *) to items and casting
|
||||
// it to the proper type while rule-matching as the data-type should be fixed for
|
||||
// any given atom.
|
||||
union {
|
||||
void *data;
|
||||
long *integer;
|
||||
char **string;
|
||||
} items;
|
||||
};
|
||||
|
||||
/// An entry in the window stack. May or may not correspond to a window we know about.
|
||||
struct window_stack_entry {
|
||||
struct list_node stack_neighbour;
|
||||
|
@ -140,6 +160,8 @@ struct managed_win {
|
|||
uint64_t *stale_props;
|
||||
/// number of uint64_ts that has been allocated for stale_props
|
||||
uint64_t stale_props_capacity;
|
||||
/// Cached property-values for rule matching.
|
||||
struct property_cache *cached_props;
|
||||
/// Whether this window is marked fullscreen in _NET_WM_STATE. DO NOT USE
|
||||
/// DIRECTLY! Query fullscreen state with `win_is_fullscreen`.
|
||||
bool fullscreen;
|
||||
|
|
6
src/x.c
6
src/x.c
|
@ -112,7 +112,7 @@ xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t apr
|
|||
* Get the value of a text property of a window.
|
||||
*/
|
||||
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
|
||||
int *pnstr) {
|
||||
size_t *pnstr) {
|
||||
assert(ps->server_grabbed);
|
||||
auto prop_info = x_get_prop_info(ps, wid, prop);
|
||||
auto type = prop_info.type;
|
||||
|
@ -160,7 +160,7 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
|
|||
if (nstr == 0) {
|
||||
// The property is set to an empty string, in that case, we return one
|
||||
// string
|
||||
char **strlst = malloc(sizeof(char *));
|
||||
char **strlst = cmalloc(char *);
|
||||
strlst[0] = "";
|
||||
*pnstr = 1;
|
||||
*pstrlst = strlst;
|
||||
|
@ -187,7 +187,7 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char **
|
|||
nstr += 1;
|
||||
}
|
||||
|
||||
*pnstr = to_int_checked(nstr);
|
||||
*pnstr = nstr;
|
||||
*pstrlst = ret;
|
||||
free(r);
|
||||
return true;
|
||||
|
|
2
src/x.h
2
src/x.h
|
@ -162,7 +162,7 @@ xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t apr
|
|||
* @param[out] pnstr Number of strings in the array
|
||||
*/
|
||||
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
|
||||
int *pnstr);
|
||||
size_t *pnstr);
|
||||
|
||||
const xcb_render_pictforminfo_t *
|
||||
x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t);
|
||||
|
|
Loading…
Reference in New Issue