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

