From d19a7bc0912905c29e46b8a6dd3e2f6c3fc038e5 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Tue, 13 Feb 2024 22:47:12 +0000 Subject: [PATCH] c2: start to separate some state out of session_t This is just the beginning, c2_match still needs session_t, everything is just so tangled... Signed-off-by: Yuxuan Shui --- src/c2.c | 71 +++++++++++++++++++++++++++++++++++----------------- src/c2.h | 14 ++++++++++- src/common.h | 4 +-- src/event.c | 26 +++++++++---------- src/picom.c | 39 +++++++++++------------------ 5 files changed, 90 insertions(+), 64 deletions(-) diff --git a/src/c2.c b/src/c2.c index e039821f..6d6ea67f 100644 --- a/src/c2.c +++ b/src/c2.c @@ -14,6 +14,7 @@ #include #include #include +#include // libpcre #ifdef CONFIG_REGEX_PCRE @@ -53,6 +54,16 @@ typedef struct { }; } c2_ptr_t; +struct c2_tracked_property { + UT_hash_handle hh; + xcb_atom_t property; +}; + +struct c2_state { + struct c2_tracked_property *tracked_properties; + struct atom *atoms; +}; + /// Initializer for c2_ptr_t. #define C2_PTR_INIT \ { .isbranch = false, .l = NULL, } @@ -1039,7 +1050,7 @@ fail: /** * Do postprocessing on a condition leaf. */ -static bool c2_l_postprocess(session_t *ps, c2_l_t *pleaf) { +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); @@ -1047,27 +1058,21 @@ static bool c2_l_postprocess(session_t *ps, c2_l_t *pleaf) { // Get target atom if it's not a predefined one if (pleaf->predef == C2_L_PUNDEFINED) { - pleaf->tgtatom = get_atom(ps->atoms, pleaf->tgt, ps->c.c); + pleaf->tgtatom = get_atom(state->atoms, pleaf->tgt, c); if (!pleaf->tgtatom) { log_error("Failed to get atom for target \"%s\".", pleaf->tgt); return false; } } - // Insert target Atom into atom track list + // Insert target atom into tracked property name list if (pleaf->tgtatom) { - bool found = false; - for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) { - if (pleaf->tgtatom == platom->atom) { - found = true; - break; - } - } - if (!found) { - auto pnew = cmalloc(latom_t); - pnew->next = ps->track_atom_lst; - pnew->atom = pleaf->tgtatom; - ps->track_atom_lst = pnew; + struct c2_tracked_property *property; + HASH_FIND_INT(state->tracked_properties, &pleaf->tgtatom, property); + if (property == NULL) { + property = cmalloc(struct c2_tracked_property); + property->property = pleaf->tgtatom; + HASH_ADD_INT(state->tracked_properties, property, property); } } @@ -1123,20 +1128,19 @@ static bool c2_l_postprocess(session_t *ps, c2_l_t *pleaf) { return true; } -static bool c2_tree_postprocess(session_t *ps, c2_ptr_t node) { +static bool c2_tree_postprocess(struct c2_state *state, xcb_connection_t *c, c2_ptr_t node) { if (!node.isbranch) { - return c2_l_postprocess(ps, node.l); + return c2_l_postprocess(state, c, node.l); } - if (!c2_tree_postprocess(ps, node.b->opr1)) { - return false; - } - return c2_tree_postprocess(ps, node.b->opr2); + + return c2_tree_postprocess(state, c, node.b->opr1) && + c2_tree_postprocess(state, c, node.b->opr2); } -bool c2_list_postprocess(session_t *ps, c2_lptr_t *list) { +bool c2_list_postprocess(struct c2_state *state, xcb_connection_t *c, c2_lptr_t *list) { c2_lptr_t *head = list; while (head) { - if (!c2_tree_postprocess(ps, head->ptr)) { + if (!c2_tree_postprocess(state, c, head->ptr)) { return false; } head = head->next; @@ -1729,3 +1733,24 @@ bool c2_list_foreach(const c2_lptr_t *condlist, c2_list_foreach_cb_t cb, void *d void *c2_list_get_data(const c2_lptr_t *condlist) { return condlist->data; } + +struct c2_state *c2_state_new(struct atom *atoms) { + auto ret = ccalloc(1, struct c2_state); + ret->atoms = atoms; + return ret; +} + +void c2_state_free(struct c2_state *state) { + struct c2_tracked_property *property, *tmp; + HASH_ITER(hh, state->tracked_properties, property, tmp) { + HASH_DEL(state->tracked_properties, property); + free(property); + } + free(state); +} + +bool c2_is_property_tracked(struct c2_state *state, xcb_atom_t property) { + struct c2_tracked_property *p; + HASH_FIND_INT(state->tracked_properties, &property, p); + return p != NULL; +} \ No newline at end of file diff --git a/src/c2.h b/src/c2.h index a7ddd392..93124583 100644 --- a/src/c2.h +++ b/src/c2.h @@ -13,9 +13,12 @@ #include #include +#include typedef struct _c2_lptr c2_lptr_t; typedef struct session session_t; +struct c2_state; +struct atom; struct managed_win; typedef void (*c2_userdata_free)(void *); @@ -23,10 +26,19 @@ c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data); c2_lptr_t *c2_free_lptr(c2_lptr_t *lp, c2_userdata_free f); +/// Create a new c2_state object. This is used for maintaining the internal state +/// used for c2 condition matching. This state object holds a reference to the +/// pass atom object, thus the atom object should be kept alive as long as the +/// state object is alive. +struct c2_state *c2_state_new(struct atom *atoms); +void c2_state_free(struct c2_state *state); +/// Returns true if value of the property is used in any condition. +bool c2_is_property_tracked(struct c2_state *state, xcb_atom_t property); + bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condlst, void **pdata); -bool c2_list_postprocess(session_t *ps, c2_lptr_t *list); +bool c2_list_postprocess(struct c2_state *state, xcb_connection_t *c, c2_lptr_t *list); typedef bool (*c2_list_foreach_cb_t)(const c2_lptr_t *cond, void *data); bool c2_list_foreach(const c2_lptr_t *list, c2_list_foreach_cb_t cb, void *data); /// Return user data stored in a condition. diff --git a/src/common.h b/src/common.h index f92803ae..a8ddfb32 100644 --- a/src/common.h +++ b/src/common.h @@ -234,6 +234,8 @@ typedef struct session { uint64_t root_flags; /// Program options. options_t o; + /// State object for c2. + struct c2_state *c2_state; /// Whether we have hit unredirection timeout. bool tmout_unredir_hit; /// If the backend is busy. This means two things: @@ -376,8 +378,6 @@ typedef struct session { struct atom *atoms; /// Array of atoms of all possible window types. xcb_atom_t atoms_wintypes[NUM_WINTYPES]; - /// Linked list of additional atoms to track. - latom_t *track_atom_lst; #ifdef CONFIG_DBUS // === DBus related === diff --git a/src/event.c b/src/event.c index 17374c3f..fed31819 100644 --- a/src/event.c +++ b/src/event.c @@ -11,6 +11,7 @@ #include #include "atom.h" +#include "c2.h" #include "common.h" #include "compiler.h" #include "config.h" @@ -573,20 +574,17 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t } // Check for other atoms we are tracking - for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) { - if (platom->atom == ev->atom) { - auto w = find_managed_win(ps, ev->window); - if (!w) { - 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); - } - break; + if (c2_is_property_tracked(ps->c2_state, ev->atom)) { + auto w = find_managed_win(ps, ev->window); + if (!w) { + 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); } } } diff --git a/src/picom.c b/src/picom.c index 57893514..f4fe7ce3 100644 --- a/src/picom.c +++ b/src/picom.c @@ -2071,7 +2071,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .xrfilter_convolution_exists = false, .atoms_wintypes = {0}, - .track_atom_lst = NULL, #ifdef CONFIG_DBUS .dbus_data = NULL, @@ -2266,19 +2265,21 @@ static session_t *session_init(int argc, char **argv, Display *dpy, SET_WM_TYPE_ATOM(DND); #undef SET_WM_TYPE_ATOM + ps->c2_state = c2_state_new(ps->atoms); + // Get needed atoms for c2 condition lists - if (!(c2_list_postprocess(ps, ps->o.unredir_if_possible_blacklist) && - c2_list_postprocess(ps, ps->o.paint_blacklist) && - c2_list_postprocess(ps, ps->o.shadow_blacklist) && - c2_list_postprocess(ps, ps->o.shadow_clip_list) && - c2_list_postprocess(ps, ps->o.fade_blacklist) && - c2_list_postprocess(ps, ps->o.blur_background_blacklist) && - c2_list_postprocess(ps, ps->o.invert_color_list) && - c2_list_postprocess(ps, ps->o.window_shader_fg_rules) && - c2_list_postprocess(ps, ps->o.opacity_rules) && - c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) && - c2_list_postprocess(ps, ps->o.corner_radius_rules) && - c2_list_postprocess(ps, ps->o.focus_blacklist))) { + if (!(c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.unredir_if_possible_blacklist) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.paint_blacklist) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.shadow_blacklist) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.shadow_clip_list) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.fade_blacklist) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.blur_background_blacklist) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.invert_color_list) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.window_shader_fg_rules) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.opacity_rules) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.rounded_corners_blacklist) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.corner_radius_rules) && + c2_list_postprocess(ps->c2_state, ps->c.c, ps->o.focus_blacklist))) { log_error("Post-processing of conditionals failed, some of your rules " "might not work"); } @@ -2693,17 +2694,7 @@ static void session_destroy(session_t *ps) { c2_list_free(&ps->o.rounded_corners_blacklist, NULL); c2_list_free(&ps->o.corner_radius_rules, NULL); c2_list_free(&ps->o.window_shader_fg_rules, free); - - // Free tracked atom list - { - latom_t *next = NULL; - for (latom_t *this = ps->track_atom_lst; this; this = next) { - next = this->next; - free(this); - } - - ps->track_atom_lst = NULL; - } + c2_state_free(ps->c2_state); // Free tgt_{buffer,picture} and root_picture if (ps->tgt_buffer.pict == ps->tgt_picture) {