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 <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-02-13 22:47:12 +00:00
parent b99c7db73e
commit d19a7bc091
No known key found for this signature in database
GPG Key ID: D3A4405BE6CC17F4
5 changed files with 90 additions and 64 deletions

View File

@ -14,6 +14,7 @@
#include <fnmatch.h>
#include <stdio.h>
#include <string.h>
#include <uthash.h>
// 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;
}

View File

@ -13,9 +13,12 @@
#include <stdbool.h>
#include <stddef.h>
#include <xcb/xproto.h>
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.

View File

@ -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 ===

View File

@ -11,6 +11,7 @@
#include <xcb/xcb_event.h>
#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);
}
}
}

View File

@ -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) {