[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,
&globalconf.shiftlockmask, &globalconf.capslockmask);
/* init EWMH atoms */
/* init Atoms cache and then EWMH atoms */
atom_cache_list_init(&globalconf.atoms);
ewmh_init_atoms();
/* 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)
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,

View File

@ -33,13 +33,14 @@
/** Get the string value of an atom.
* \param conn X connection
* \param w window
* \param atoms atoms cache
* \param atom the atom
* \param text buffer to fill
* \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, xutil_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 +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
* 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 */
@ -152,29 +155,106 @@ xutil_get_transient_for_hint(xcb_connection_t *c, xcb_window_t win,
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 atoms atoms cache
* \param property atom name
* \return an brand new xcb_atom_t
* \return a request structure
*/
xcb_atom_t
xutil_intern_atom(xcb_connection_t *c, const char *property)
xutil_intern_atom_request_t
xutil_intern_atom(xcb_connection_t *c, xutil_atom_cache_t **atoms,
const char *name)
{
xcb_atom_t atom = 0;
xcb_intern_atom_reply_t *r_atom;
xutil_intern_atom_request_t atom_req;
xutil_atom_cache_t *atom_next;
int cmp_cache;
if((r_atom = xcb_intern_atom_reply(c,
xcb_intern_atom_unchecked(c,
false,
a_strlen(property),
property),
NULL)))
atom_req.name = strdup(name);
/* Check if this atom is present in the cache ordered
* linked-list */
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 = r_atom->atom;
p_delete(&r_atom);
atom_req.cache_hit = true;
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 *

View File

@ -31,9 +31,7 @@
/* XCB doesn't provide keysyms definition */
#include <X11/keysym.h>
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,61 @@ 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 *);
/** Cache entry */
typedef struct xutil_atom_cache_t xutil_atom_cache_t;
struct xutil_atom_cache_t
{
/** Atom X identifier */
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 */
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;

View File

@ -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);
}

View File

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

View File

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

View File

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