diff --git a/awesome.c b/awesome.c index 228dd4f..828a4bd 100644 --- a/awesome.c +++ b/awesome.c @@ -386,7 +386,9 @@ main(int argc, char **argv) xutil_getlockmask(globalconf.connection, globalconf.keysyms, &globalconf.numlockmask, &globalconf.shiftlockmask, &globalconf.capslockmask); - /* init EWMH atoms */ + /* init Atoms cache and then EWMH atoms */ + globalconf.atoms = p_new(atom_cache_t *, 1); + atom_cache_list_init(globalconf.atoms); ewmh_init_atoms(); /* init screens struct */ diff --git a/client.c b/client.c index 0eb8af6..56ea6d1 100644 --- a/client.c +++ b/client.c @@ -60,8 +60,11 @@ client_loadprops(client_t * c, int screen) for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) ntags++; - if(xutil_gettextprop(globalconf.connection, c->win, - xutil_intern_atom(globalconf.connection, "_AWESOME_PROPERTIES"), + if(xutil_gettextprop(globalconf.connection, c->win, globalconf.atoms, + xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "_AWESOME_PROPERTIES")), &prop)) { for(i = 0, tag = globalconf.screens[screen].tags; tag && i < ntags && prop[i]; i++, tag = tag->next) @@ -90,13 +93,19 @@ static bool client_isprotodel(xcb_window_t win) { uint32_t i, n; + xcb_atom_t wm_delete_win_atom; xcb_atom_t *protocols; bool ret = false; if(xcb_get_wm_protocols(globalconf.connection, win, &n, &protocols)) { + wm_delete_win_atom = xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "WM_DELETE_WINDOW")); + for(i = 0; !ret && i < n; i++) - if(protocols[i] == xutil_intern_atom(globalconf.connection, "WM_DELETE_WINDOW")) + if(protocols[i] == wm_delete_win_atom) ret = true; p_delete(&protocols); } @@ -188,11 +197,18 @@ client_updatetitle(client_t *c) { char *name; - if(!xutil_gettextprop(globalconf.connection, c->win, - xutil_intern_atom(globalconf.connection, "_NET_WM_NAME"), + if(!xutil_gettextprop(globalconf.connection, c->win, globalconf.atoms, + xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "_NET_WM_NAME")), &name)) - if(!xutil_gettextprop(globalconf.connection, c->win, - xutil_intern_atom(globalconf.connection, "WM_NAME"), + if(!xutil_gettextprop(globalconf.connection, c->win, globalconf.atoms, + xutil_intern_atom_reply(globalconf.connection, + globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "WM_NAME")), &name)) return; @@ -687,7 +703,10 @@ client_saveprops(client_t *c) prop[++i] = '\0'; xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, - xutil_intern_atom(globalconf.connection, "_AWESOME_PROPERTIES"), + xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "_AWESOME_PROPERTIES")), STRING, 8, i, (unsigned char *) prop); p_delete(&prop); @@ -871,7 +890,11 @@ uicb_client_settrans(int screen __attribute__ ((unused)), char *arg) prop_r = xcb_get_property_reply(globalconf.connection, xcb_get_property_unchecked(globalconf.connection, false, sel->win, - xutil_intern_atom(globalconf.connection, "_NET_WM_WINDOW_OPACITY"), + xutil_intern_atom_reply(globalconf.connection, + globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "_NET_WM_WINDOW_OPACITY")), CARDINAL, 0, 1), NULL); @@ -1048,10 +1071,16 @@ client_kill(client_t *c) ev.response_type = XCB_CLIENT_MESSAGE; ev.window = c->win; - ev.type = xutil_intern_atom(globalconf.connection, "WM_PROTOCOLS"); + ev.type = xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "WM_PROTOCOLS")); ev.format = 32; - ev.data.data32[0] = xutil_intern_atom(globalconf.connection, "WM_DELETE_WINDOW"); + ev.data.data32[0] = xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "WM_DELETE_WINDOW")); ev.data.data32[1] = XCB_CURRENT_TIME; xcb_send_event(globalconf.connection, false, c->win, diff --git a/common/xutil.c b/common/xutil.c index 7fda19f..ed03146 100644 --- a/common/xutil.c +++ b/common/xutil.c @@ -38,8 +38,8 @@ * \return true on sucess, falsse on failure */ bool -xutil_gettextprop(xcb_connection_t *conn, xcb_window_t w, xcb_atom_t atom, - char **text) +xutil_gettextprop(xcb_connection_t *conn, xcb_window_t w, atom_cache_t **atoms, + xcb_atom_t atom, char **text) { xcb_get_property_cookie_t prop_c; xcb_get_property_reply_t *prop_r; @@ -67,7 +67,9 @@ xutil_gettextprop(xcb_connection_t *conn, xcb_window_t w, xcb_atom_t atom, * string or utf8 string. At the moment it doesn't handle * COMPOUND_TEXT and multibyte but it's not needed... */ if(prop_r->type == STRING || - prop_r->type == xutil_intern_atom(conn, "UTF8_STRING")) + prop_r->type == xutil_intern_atom_reply(conn, atoms, + xutil_intern_atom(conn, atoms, + "UTF8_STRING"))) { *text = p_new(char, prop_r->value_len + 1); /* use memcpy() because prop_val may not be \0 terminated */ @@ -157,24 +159,79 @@ xutil_get_transient_for_hint(xcb_connection_t *c, xcb_window_t win, * \param property atom name * \return an brand new xcb_atom_t */ +intern_atom_request_t +xutil_intern_atom(xcb_connection_t *c, atom_cache_t **atoms, + const char *name) +{ + intern_atom_request_t atom_req; + atom_cache_t *atom_next; + int cmp_cache; + + atom_req.name = strdup(name); + + for(atom_next = *atoms; + atom_next && (cmp_cache = a_strcmp(name, atom_next->name)) >= 0; + atom_next = atom_cache_list_next(NULL, atom_next)) + { + if(cmp_cache == 0) + { + atom_req.cache_hit = true; + atom_req.cache = atom_next; + return atom_req; + } + } + + atom_req.cache_hit = false; + atom_req.cookie = xcb_intern_atom_unchecked(c, false, a_strlen(name), + name); + + return atom_req; +} + xcb_atom_t -xutil_intern_atom(xcb_connection_t *c, const char *property) +xutil_intern_atom_reply(xcb_connection_t *c, atom_cache_t **atoms, + intern_atom_request_t atom_req) { - xcb_atom_t atom = 0; - xcb_intern_atom_reply_t *r_atom; - - if((r_atom = xcb_intern_atom_reply(c, - xcb_intern_atom_unchecked(c, - false, - a_strlen(property), - property), - NULL))) + xcb_intern_atom_reply_t *atom_rep; + atom_cache_t *atom_cache, *atom_next; + + if(atom_req.cache_hit) + return atom_req.cache->atom; + + if((atom_rep = xcb_intern_atom_reply(c, atom_req.cookie, NULL)) == NULL) + return 0; + + atom_cache = p_new(atom_cache_t, 1); + atom_cache->atom = atom_rep->atom; + atom_cache->name = atom_req.name; + + if(*atoms == NULL || a_strcmp(atom_req.name, (*atoms)->name) < 0) + atom_cache_list_push(atoms, atom_cache); + else { - atom = r_atom->atom; - p_delete(&r_atom); + for(atom_next = *atoms; + atom_next && atom_next->next && a_strcmp(atom_req.name, atom_next->next->name) > 0; + atom_next = atom_cache_list_next(NULL, atom_next)); + + atom_cache->prev = atom_next; + atom_cache->next = atom_next->next; + + if(atom_next->next) + atom_next->next->prev = atom_cache; + + atom_next->next = atom_cache; } - return atom; + p_delete(&atom_rep); + + return atom_cache->atom; +} + +void +xutil_atom_cache_delete(atom_cache_t **entry) +{ + p_delete(&(*entry)->name); + p_delete(entry); } class_hint_t * diff --git a/common/xutil.h b/common/xutil.h index 7c28a6c..d803c68 100644 --- a/common/xutil.h +++ b/common/xutil.h @@ -31,9 +31,7 @@ /* XCB doesn't provide keysyms definition */ #include -bool xutil_gettextprop(xcb_connection_t *, xcb_window_t, xcb_atom_t, char **); -void xutil_getlockmask(xcb_connection_t *, xcb_key_symbols_t *, - unsigned int *, unsigned int *, unsigned int *); +#include "common/list.h" /* See http://tronche.com/gui/x/xlib/appendix/b/ for values */ #define CURSOR_FLEUR 52 @@ -81,7 +79,7 @@ void xutil_getlockmask(xcb_connection_t *, xcb_key_symbols_t *, /* Common function defined in Xlib but not in XCB */ bool xutil_get_transient_for_hint(xcb_connection_t *, xcb_window_t, xcb_window_t *); -typedef struct _class_hint_t +typedef struct { char *res_name; char *res_class; @@ -97,18 +95,51 @@ typedef struct class_hint_t *xutil_get_class_hint(xcb_connection_t *, xcb_window_t); -/* Equivalent call to XInternAtom - * - * WARNING: should not be used in loop, in this case, it should send - * the queries first and then treat the answer as late as possible) - */ -xcb_atom_t xutil_intern_atom(xcb_connection_t *, const char *); +typedef struct atom_cache_t atom_cache_t; +struct atom_cache_t +{ + /** Atom X identifier */ + xcb_atom_t atom; + /** Atom name */ + char *name; + /** Next and previous atom cache entries */ + atom_cache_t *prev, *next; +}; + +typedef struct +{ + bool cache_hit; + char *name; + union + { + xcb_intern_atom_cookie_t cookie; + atom_cache_t *cache; + }; +} intern_atom_request_t; + +/* Equivalent call to XInternAtom which relies on a cache stored as a + * list ATM */ +intern_atom_request_t xutil_intern_atom(xcb_connection_t *, atom_cache_t **, + const char *); + +xcb_atom_t xutil_intern_atom_reply(xcb_connection_t *, atom_cache_t **, + intern_atom_request_t); + +void xutil_atom_cache_delete(atom_cache_t **); + +DO_SLIST(atom_cache_t, atom_cache, xutil_atom_cache_delete) + +bool xutil_gettextprop(xcb_connection_t *, xcb_window_t, atom_cache_t **, + xcb_atom_t, char **); + +void xutil_getlockmask(xcb_connection_t *, xcb_key_symbols_t *, + unsigned int *, unsigned int *, unsigned int *); /** Set the same handler for all errors */ void xutil_set_error_handler_catch_all(xcb_event_handlers_t *, xcb_generic_error_handler_t, void *); -typedef struct xutil_error_t +typedef struct { uint8_t request_code; char *request_label; diff --git a/event.c b/event.c index 6498d08..52a7e49 100644 --- a/event.c +++ b/event.c @@ -520,7 +520,10 @@ event_handle_propertynotify(void *data __attribute__ ((unused)), client_updatewmhints(c); if(ev->atom == WM_NAME - || ev->atom == xutil_intern_atom(globalconf.connection, "_NET_WM_NAME")) + || ev->atom == xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "_NET_WM_NAME"))) client_updatetitle(c); } diff --git a/rules.c b/rules.c index adca068..9ecf812 100644 --- a/rules.c +++ b/rules.c @@ -83,8 +83,12 @@ rule_matching_client(client_t *c) if(!ret && r->xprop && r->xpropval_r - && xutil_gettextprop(globalconf.connection, c->win, - xutil_intern_atom(globalconf.connection, r->xprop), + && xutil_gettextprop(globalconf.connection, c->win, globalconf.atoms, + xutil_intern_atom_reply(globalconf.connection, + globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + r->xprop)), &buf)) ret = !regexec(r->xpropval_r, buf, 1, &tmp, 0); diff --git a/structs.h b/structs.h index 8c7b428..5387cc7 100644 --- a/structs.h +++ b/structs.h @@ -380,6 +380,8 @@ struct AwesomeConf char *argv; /** Last XMotionEvent coords */ int pointer_x, pointer_y; + /** Atoms cache */ + atom_cache_t **atoms; }; #endif diff --git a/window.c b/window.c index 29a118f..8994339 100644 --- a/window.c +++ b/window.c @@ -41,11 +41,13 @@ void window_setstate(xcb_window_t win, long state) { long data[] = { state, XCB_NONE }; + const xcb_atom_t wm_state_atom = xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "WM_STATE")); xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, win, - xutil_intern_atom(globalconf.connection, "WM_STATE"), - xutil_intern_atom(globalconf.connection, "WM_STATE"), 32, - 2, data); + wm_state_atom, wm_state_atom, 32, 2, data); } /** Get a window state (WM_STATE). @@ -58,7 +60,10 @@ window_getstate(xcb_window_t w) long result = -1; unsigned char *p = NULL; xcb_get_property_cookie_t prop_c; - xcb_atom_t wm_state_atom = xutil_intern_atom(globalconf.connection, "WM_STATE"); + xcb_atom_t wm_state_atom = xutil_intern_atom_reply(globalconf.connection, globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "WM_STATE")); xcb_get_property_reply_t *prop_r; prop_c = xcb_get_property_unchecked(globalconf.connection, false, w, @@ -224,17 +229,21 @@ void window_settrans(xcb_window_t win, double opacity) { unsigned int real_opacity = 0xffffffff; + const xcb_atom_t wopacity_atom = xutil_intern_atom_reply(globalconf.connection, + globalconf.atoms, + xutil_intern_atom(globalconf.connection, + globalconf.atoms, + "_NET_WM_WINDOW_OPACITY")); if(opacity >= 0 && opacity <= 1) { real_opacity = opacity * 0xffffffff; xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, win, - xutil_intern_atom(globalconf.connection, "_NET_WM_WINDOW_OPACITY"), - CARDINAL, 32, 1L, &real_opacity); + wopacity_atom, CARDINAL, 32, 1L, &real_opacity); } else xcb_delete_property(globalconf.connection, win, - xutil_intern_atom(globalconf.connection, "_NET_WM_WINDOW_OPACITY")); + wopacity_atom); } // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80