diff --git a/src/atom.c b/src/atom.c index 76fc57f4..8ef699e8 100644 --- a/src/atom.c +++ b/src/atom.c @@ -8,13 +8,11 @@ #include "log.h" #include "utils.h" -static inline int -atom_getter(struct cache *cache, const char *atom_name, struct cache_handle **value) { - struct atom *atoms = container_of(cache, struct atom, c); +static inline int atom_getter(struct cache *cache attr_unused, const char *atom_name, + struct cache_handle **value, void *user_data) { + xcb_connection_t *c = user_data; xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply( - atoms->conn, - xcb_intern_atom(atoms->conn, 0, to_u16_checked(strlen(atom_name)), atom_name), - NULL); + c, xcb_intern_atom(c, 0, to_u16_checked(strlen(atom_name)), atom_name), NULL); xcb_atom_t atom = XCB_NONE; if (reply) { @@ -38,14 +36,22 @@ atom_entry_free(struct cache *cache attr_unused, struct cache_handle *handle) { free(entry); } +xcb_atom_t get_atom(struct atom *a, const char *key, xcb_connection_t *c) { + struct cache_handle *entry = NULL; + if (cache_get_or_fetch(&a->c, key, &entry, c, atom_getter) < 0) { + log_error("Failed to get atom %s", key); + return XCB_NONE; + } + return cache_entry(entry, struct atom_entry, entry)->atom; +} + /** * Create a new atom structure and fetch all predefined atoms */ struct atom *init_atoms(xcb_connection_t *c) { auto atoms = ccalloc(1, struct atom); - atoms->conn = c; - cache_init(&atoms->c, atom_getter); -#define ATOM_GET(x) atoms->a##x = get_atom(atoms, #x) + atoms->c = CACHE_INIT; +#define ATOM_GET(x) atoms->a##x = get_atom(atoms, #x, c) LIST_APPLY(ATOM_GET, SEP_COLON, ATOM_LIST1); LIST_APPLY(ATOM_GET, SEP_COLON, ATOM_LIST2); #undef ATOM_GET diff --git a/src/atom.h b/src/atom.h index 67873317..d5a41d58 100644 --- a/src/atom.h +++ b/src/atom.h @@ -55,7 +55,6 @@ #define ATOM_DEF(x) xcb_atom_t a##x struct atom { - xcb_connection_t *conn; struct cache c; LIST_APPLY(ATOM_DEF, SEP_COLON, ATOM_LIST1); LIST_APPLY(ATOM_DEF, SEP_COLON, ATOM_LIST2); @@ -66,20 +65,11 @@ struct atom_entry { xcb_atom_t atom; }; -/// Create a new atom object with a xcb connection, note that this atom object will hold a -/// reference to the connection, so the caller must keep the connection alive until the -/// atom object is destroyed. -struct atom *init_atoms(xcb_connection_t *); - -static inline xcb_atom_t get_atom(struct atom *a, const char *key) { - struct cache_handle *entry = NULL; - if (cache_get_or_fetch(&a->c, key, &entry) < 0) { - log_error("Failed to get atom %s", key); - return XCB_NONE; - } - return cache_entry(entry, struct atom_entry, entry)->atom; -} +/// Create a new atom object with a xcb connection. `struct atom` does not hold +/// a reference to the connection. +struct atom *init_atoms(xcb_connection_t *c); +xcb_atom_t get_atom(struct atom *a, const char *key, xcb_connection_t *c); static inline xcb_atom_t get_atom_cached(struct atom *a, const char *key) { return cache_entry(cache_get(&a->c, key), struct atom_entry, entry)->atom; } diff --git a/src/c2.c b/src/c2.c index 614c456c..140d2746 100644 --- a/src/c2.c +++ b/src/c2.c @@ -1047,7 +1047,7 @@ 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); + pleaf->tgtatom = get_atom(ps->atoms, pleaf->tgt, ps->c.c); if (!pleaf->tgtatom) { log_error("Failed to get atom for target \"%s\".", pleaf->tgt); return false; diff --git a/src/cache.c b/src/cache.c index d25a22fb..e297c4fe 100644 --- a/src/cache.c +++ b/src/cache.c @@ -8,13 +8,14 @@ struct cache_handle *cache_get(struct cache *c, const char *key) { return e; } -int cache_get_or_fetch(struct cache *c, const char *key, struct cache_handle **value) { +int cache_get_or_fetch(struct cache *c, const char *key, struct cache_handle **value, + void *user_data, cache_getter_t getter) { *value = cache_get(c, key); if (*value) { return 0; } - int err = c->getter(c, key, value); + int err = getter(c, key, value, user_data); assert(err <= 0); if (err < 0) { return err; @@ -49,8 +50,3 @@ void cache_invalidate_all(struct cache *c, cache_free_t free_fn) { cache_invalidate_impl(c, e, free_fn); } } - -void cache_init(struct cache *cache, cache_getter_t getter) { - cache->getter = getter; - cache->entries = NULL; -} diff --git a/src/cache.h b/src/cache.h index 60609190..a50ec4bc 100644 --- a/src/cache.h +++ b/src/cache.h @@ -12,27 +12,27 @@ struct cache_handle; /// Should return 0 if the value is fetched successfully, and a negative number if the /// value cannot be fetched. Getter doesn't need to initialize fields of `struct /// cache_handle`. -typedef int (*cache_getter_t)(struct cache *, const char *key, struct cache_handle **value); +typedef int (*cache_getter_t)(struct cache *, const char *key, + struct cache_handle **value, void *user_data); typedef void (*cache_free_t)(struct cache *, struct cache_handle *value); struct cache { - cache_getter_t getter; struct cache_handle *entries; }; +static const struct cache CACHE_INIT = {NULL}; + struct cache_handle { char *key; UT_hash_handle hh; }; -/// Initialize a cache with `getter` -void cache_init(struct cache *cache, cache_getter_t getter); - /// Get a value from the cache. If the value doesn't present in the cache yet, the /// getter will be called, and the returned value will be stored into the cache. /// Returns 0 if the value is already present in the cache, 1 if the value is fetched /// successfully, and a negative number if the value cannot be fetched. -int cache_get_or_fetch(struct cache *, const char *key, struct cache_handle **value); +int cache_get_or_fetch(struct cache *, const char *key, struct cache_handle **value, + void *user_data, cache_getter_t getter); /// Get a value from the cache. If the value doesn't present in the cache, NULL will be /// returned. diff --git a/src/picom.c b/src/picom.c index dc075c13..57893514 100644 --- a/src/picom.c +++ b/src/picom.c @@ -1346,7 +1346,7 @@ static int register_cm(session_t *ps) { log_fatal("Failed to allocate memory"); return -1; } - atom = get_atom(ps->atoms, buf); + atom = get_atom(ps->atoms, buf, ps->c.c); free(buf); xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply(