[all] Implement an atom cache in xutil as an ordered linked-list

This commit is contained in:
Arnaud Fontaine 2008-05-10 23:30:20 +01:00 committed by Julien Danjou
parent 6a06e44461
commit 162b8a690c
8 changed files with 219 additions and 50 deletions

View File

@ -386,7 +386,8 @@ main(int argc, char **argv)
xutil_getlockmask(globalconf.connection, globalconf.keysyms, &globalconf.numlockmask, xutil_getlockmask(globalconf.connection, globalconf.keysyms, &globalconf.numlockmask,
&globalconf.shiftlockmask, &globalconf.capslockmask); &globalconf.shiftlockmask, &globalconf.capslockmask);
/* init EWMH atoms */ /* init Atoms cache and then EWMH atoms */
atom_cache_list_init(&globalconf.atoms);
ewmh_init_atoms(); ewmh_init_atoms();
/* init screens struct */ /* init screens struct */

View File

@ -60,8 +60,11 @@ client_loadprops(client_t * c, int screen)
for(tag = globalconf.screens[screen].tags; tag; tag = tag->next) for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
ntags++; ntags++;
if(xutil_gettextprop(globalconf.connection, c->win, if(xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms,
xutil_intern_atom(globalconf.connection, "_AWESOME_PROPERTIES"), xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms,
xutil_intern_atom(globalconf.connection,
&globalconf.atoms,
"_AWESOME_PROPERTIES")),
&prop)) &prop))
{ {
for(i = 0, tag = globalconf.screens[screen].tags; tag && i < ntags && prop[i]; i++, tag = tag->next) 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) client_isprotodel(xcb_window_t win)
{ {
uint32_t i, n; uint32_t i, n;
xcb_atom_t wm_delete_win_atom;
xcb_atom_t *protocols; xcb_atom_t *protocols;
bool ret = false; bool ret = false;
if(xcb_get_wm_protocols(globalconf.connection, win, &n, &protocols)) 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++) 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; ret = true;
p_delete(&protocols); p_delete(&protocols);
} }
@ -188,11 +197,18 @@ client_updatetitle(client_t *c)
{ {
char *name; char *name;
if(!xutil_gettextprop(globalconf.connection, c->win, if(!xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms,
xutil_intern_atom(globalconf.connection, "_NET_WM_NAME"), xutil_intern_atom_reply(globalconf.connection, &globalconf.atoms,
xutil_intern_atom(globalconf.connection,
&globalconf.atoms,
"_NET_WM_NAME")),
&name)) &name))
if(!xutil_gettextprop(globalconf.connection, c->win, if(!xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms,
xutil_intern_atom(globalconf.connection, "WM_NAME"), xutil_intern_atom_reply(globalconf.connection,
&globalconf.atoms,
xutil_intern_atom(globalconf.connection,
&globalconf.atoms,
"WM_NAME")),
&name)) &name))
return; return;
@ -687,7 +703,10 @@ client_saveprops(client_t *c)
prop[++i] = '\0'; prop[++i] = '\0';
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, c->win, 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); STRING, 8, i, (unsigned char *) prop);
p_delete(&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, prop_r = xcb_get_property_reply(globalconf.connection,
xcb_get_property_unchecked(globalconf.connection, xcb_get_property_unchecked(globalconf.connection,
false, sel->win, 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, CARDINAL,
0, 1), 0, 1),
NULL); NULL);
@ -1048,10 +1071,16 @@ client_kill(client_t *c)
ev.response_type = XCB_CLIENT_MESSAGE; ev.response_type = XCB_CLIENT_MESSAGE;
ev.window = c->win; 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.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; ev.data.data32[1] = XCB_CURRENT_TIME;
xcb_send_event(globalconf.connection, false, c->win, xcb_send_event(globalconf.connection, false, c->win,

View File

@ -33,13 +33,14 @@
/** Get the string value of an atom. /** Get the string value of an atom.
* \param conn X connection * \param conn X connection
* \param w window * \param w window
* \param atoms atoms cache
* \param atom the atom * \param atom the atom
* \param text buffer to fill * \param text buffer to fill
* \return true on sucess, falsse on failure * \return true on sucess, falsse on failure
*/ */
bool bool
xutil_gettextprop(xcb_connection_t *conn, xcb_window_t w, xcb_atom_t atom, xutil_gettextprop(xcb_connection_t *conn, xcb_window_t w, xutil_atom_cache_t **atoms,
char **text) xcb_atom_t atom, char **text)
{ {
xcb_get_property_cookie_t prop_c; xcb_get_property_cookie_t prop_c;
xcb_get_property_reply_t *prop_r; xcb_get_property_reply_t *prop_r;
@ -67,7 +68,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 * string or utf8 string. At the moment it doesn't handle
* COMPOUND_TEXT and multibyte but it's not needed... */ * COMPOUND_TEXT and multibyte but it's not needed... */
if(prop_r->type == STRING || 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); *text = p_new(char, prop_r->value_len + 1);
/* use memcpy() because prop_val may not be \0 terminated */ /* use memcpy() because prop_val may not be \0 terminated */
@ -152,29 +155,106 @@ xutil_get_transient_for_hint(xcb_connection_t *c, xcb_window_t win,
return true; return true;
} }
/** Get an internal atom. /** Send an unchecked InternAtom request if it is not already in the
* cache, in the second case it stores the cache entry (an ordered
* linked-list)
* \param c X connection * \param c X connection
* \param atoms atoms cache
* \param property atom name * \param property atom name
* \return an brand new xcb_atom_t * \return a request structure
*/ */
xcb_atom_t xutil_intern_atom_request_t
xutil_intern_atom(xcb_connection_t *c, const char *property) xutil_intern_atom(xcb_connection_t *c, xutil_atom_cache_t **atoms,
const char *name)
{ {
xcb_atom_t atom = 0; xutil_intern_atom_request_t atom_req;
xcb_intern_atom_reply_t *r_atom; xutil_atom_cache_t *atom_next;
int cmp_cache;
if((r_atom = xcb_intern_atom_reply(c, atom_req.name = strdup(name);
xcb_intern_atom_unchecked(c,
false, /* Check if this atom is present in the cache ordered
a_strlen(property), * linked-list */
property), for(atom_next = *atoms;
NULL))) 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 = r_atom->atom; atom_req.cache_hit = true;
p_delete(&r_atom); atom_req.cache = atom_next;
return atom_req;
} }
return atom; /* Otherwise send an InternAtom request to the server */
atom_req.cache_hit = false;
atom_req.cookie = xcb_intern_atom_unchecked(c, false, a_strlen(name),
name);
return atom_req;
}
/** Treat the reply which may be a cache entry or a reply from
* InternAtom request (cookie), in the second case, add the atom to
* the cache
* \param c X connection
* \param atoms atoms cache
* \param atom_req atom request
* \return a brand new xcb_atom_t
*/
xcb_atom_t
xutil_intern_atom_reply(xcb_connection_t *c, xutil_atom_cache_t **atoms,
xutil_intern_atom_request_t atom_req)
{
xcb_intern_atom_reply_t *atom_rep;
xutil_atom_cache_t *atom_cache, *atom_next;
/* If the atom is present in the cache, just returns the
* atom... */
if(atom_req.cache_hit)
return atom_req.cache->atom;
/* Get the reply from InternAtom request */
if((atom_rep = xcb_intern_atom_reply(c, atom_req.cookie, NULL)) == NULL)
return 0;
/* Create a new atom cache entry */
atom_cache = p_new(xutil_atom_cache_t, 1);
atom_cache->atom = atom_rep->atom;
atom_cache->name = atom_req.name;
/* Add the entry in the list at the beginning of the cache list */
if(*atoms == NULL || a_strcmp(atom_req.name, (*atoms)->name) < 0)
atom_cache_list_push(atoms, atom_cache);
/* Otherwise insert it at the proper position in the cache list
* according to its name */
else
{
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;
}
p_delete(&atom_rep);
return atom_cache->atom;
}
/* Delete a cache entry
* \param entry cache entry
*/
void
xutil_atom_cache_delete(xutil_atom_cache_t **entry)
{
p_delete(&(*entry)->name);
p_delete(entry);
} }
class_hint_t * class_hint_t *

View File

@ -31,9 +31,7 @@
/* XCB doesn't provide keysyms definition */ /* XCB doesn't provide keysyms definition */
#include <X11/keysym.h> #include <X11/keysym.h>
bool xutil_gettextprop(xcb_connection_t *, xcb_window_t, xcb_atom_t, char **); #include "common/list.h"
void xutil_getlockmask(xcb_connection_t *, xcb_key_symbols_t *,
unsigned int *, unsigned int *, unsigned int *);
/* See http://tronche.com/gui/x/xlib/appendix/b/ for values */ /* See http://tronche.com/gui/x/xlib/appendix/b/ for values */
#define CURSOR_FLEUR 52 #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 */ /* Common function defined in Xlib but not in XCB */
bool xutil_get_transient_for_hint(xcb_connection_t *, xcb_window_t, xcb_window_t *); 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_name;
char *res_class; char *res_class;
@ -97,18 +95,61 @@ typedef struct
class_hint_t *xutil_get_class_hint(xcb_connection_t *, xcb_window_t); class_hint_t *xutil_get_class_hint(xcb_connection_t *, xcb_window_t);
/* Equivalent call to XInternAtom /** Cache entry */
* typedef struct xutil_atom_cache_t xutil_atom_cache_t;
* WARNING: should not be used in loop, in this case, it should send struct xutil_atom_cache_t
* the queries first and then treat the answer as late as possible) {
*/ /** Atom X identifier */
xcb_atom_t xutil_intern_atom(xcb_connection_t *, const char *); xcb_atom_t atom;
/** Atom name */
char *name;
/** Next and previous atom cache entries */
xutil_atom_cache_t *prev, *next;
};
/** InternAtom request data structure which may hold the cookie if the
* atom is not already present in the cache */
typedef struct
{
/* Cache hit */
bool cache_hit;
/* Atom string name */
char *name;
union
{
/* Cookie of the InternAtom request */
xcb_intern_atom_cookie_t cookie;
/* Cache entry */
xutil_atom_cache_t *cache;
};
} xutil_intern_atom_request_t;
/* InternATom request which relies on a cache stored as a ordered
* linked-list */
xutil_intern_atom_request_t xutil_intern_atom(xcb_connection_t *, xutil_atom_cache_t **,
const char *);
/** Treat reply from InternAtom request */
xcb_atom_t xutil_intern_atom_reply(xcb_connection_t *, xutil_atom_cache_t **,
xutil_intern_atom_request_t);
/** Delete a entry in the cache */
void xutil_atom_cache_delete(xutil_atom_cache_t **);
/** Cache list utils functions */
DO_SLIST(xutil_atom_cache_t, atom_cache, xutil_atom_cache_delete)
bool xutil_gettextprop(xcb_connection_t *, xcb_window_t, xutil_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 */ /** Set the same handler for all errors */
void xutil_set_error_handler_catch_all(xcb_event_handlers_t *, void xutil_set_error_handler_catch_all(xcb_event_handlers_t *,
xcb_generic_error_handler_t, void *); xcb_generic_error_handler_t, void *);
typedef struct xutil_error_t typedef struct
{ {
uint8_t request_code; uint8_t request_code;
char *request_label; char *request_label;

View File

@ -520,7 +520,10 @@ event_handle_propertynotify(void *data __attribute__ ((unused)),
client_updatewmhints(c); client_updatewmhints(c);
if(ev->atom == WM_NAME 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); client_updatetitle(c);
} }

View File

@ -83,8 +83,12 @@ rule_matching_client(client_t *c)
if(!ret if(!ret
&& r->xprop && r->xprop
&& r->xpropval_r && r->xpropval_r
&& xutil_gettextprop(globalconf.connection, c->win, && xutil_gettextprop(globalconf.connection, c->win, &globalconf.atoms,
xutil_intern_atom(globalconf.connection, r->xprop), xutil_intern_atom_reply(globalconf.connection,
&globalconf.atoms,
xutil_intern_atom(globalconf.connection,
&globalconf.atoms,
r->xprop)),
&buf)) &buf))
ret = !regexec(r->xpropval_r, buf, 1, &tmp, 0); ret = !regexec(r->xpropval_r, buf, 1, &tmp, 0);

View File

@ -380,6 +380,8 @@ struct AwesomeConf
char *argv; char *argv;
/** Last XMotionEvent coords */ /** Last XMotionEvent coords */
int pointer_x, pointer_y; int pointer_x, pointer_y;
/** Atoms cache */
xutil_atom_cache_t *atoms;
}; };
#endif #endif

View File

@ -41,11 +41,13 @@ void
window_setstate(xcb_window_t win, long state) window_setstate(xcb_window_t win, long state)
{ {
long data[] = { state, XCB_NONE }; 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, xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, win,
xutil_intern_atom(globalconf.connection, "WM_STATE"), wm_state_atom, wm_state_atom, 32, 2, data);
xutil_intern_atom(globalconf.connection, "WM_STATE"), 32,
2, data);
} }
/** Get a window state (WM_STATE). /** Get a window state (WM_STATE).
@ -58,7 +60,10 @@ window_getstate(xcb_window_t w)
long result = -1; long result = -1;
unsigned char *p = NULL; unsigned char *p = NULL;
xcb_get_property_cookie_t prop_c; 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; xcb_get_property_reply_t *prop_r;
prop_c = xcb_get_property_unchecked(globalconf.connection, false, w, prop_c = xcb_get_property_unchecked(globalconf.connection, false, w,
@ -224,17 +229,21 @@ void
window_settrans(xcb_window_t win, double opacity) window_settrans(xcb_window_t win, double opacity)
{ {
unsigned int real_opacity = 0xffffffff; 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) if(opacity >= 0 && opacity <= 1)
{ {
real_opacity = opacity * 0xffffffff; real_opacity = opacity * 0xffffffff;
xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, win, xcb_change_property(globalconf.connection, XCB_PROP_MODE_REPLACE, win,
xutil_intern_atom(globalconf.connection, "_NET_WM_WINDOW_OPACITY"), wopacity_atom, CARDINAL, 32, 1L, &real_opacity);
CARDINAL, 32, 1L, &real_opacity);
} }
else else
xcb_delete_property(globalconf.connection, win, 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 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80