diff --git a/lib/modules/Protocols.pmod/X.pmod/Atom.pmod b/lib/modules/Protocols.pmod/X.pmod/Atom.pmod
new file mode 100644
index 0000000000000000000000000000000000000000..f941a22f366525ba070bd1f8a6a2d3c082feab6b
--- /dev/null
+++ b/lib/modules/Protocols.pmod/X.pmod/Atom.pmod
@@ -0,0 +1,142 @@
+/* Atom.pmod
+ *
+ * X Atoms
+ *
+ */
+
+class Atom
+{
+  object display;
+  string name;
+  int id;
+
+  void create(object d /*, int i, string|void n */)
+  {
+    display = d;
+    // id = i;
+    // name = n;
+  }
+}
+
+class pending_request
+{
+  object display;
+  object atom;
+  function callback;
+
+  void create(object d, object a, function|void c)
+  {
+    display = d;
+    atom = a;
+    callback = c;
+  }
+}
+
+class pending_intern
+{
+  inherit pending_request;
+  
+  void handle_reply(int success, mixed reply)
+  {
+    if (!success)
+      {
+	throw( ({ "Atom.pending_intern->handle_reply: InternAtom failed!\n",
+		    backtrace() })  );
+      }
+    atom->id = reply;
+    display->remember_atom(atom);
+    if (callback)
+      callback(atom);
+  }
+}
+
+class pending_name_lookup
+{
+  inherit pending_request;
+  
+  void handle_reply(int success, mixed reply)
+  {
+    if (!success)
+      {
+	throw( ({ "Atom.pending_intern->handle_reply: InternAtom failed!\n",
+		    backtrace() })  );
+      }
+    atom->name = reply;
+    display->remember_atom(atom);
+    if (callback)
+      callback(atom);
+  }
+}
+
+/* Keeps track of known atoms. *
+ * Is inherited into Xlib.Display */
+class atom_manager
+{
+  mapping(int:object) atoms = ([ ]);
+  mapping(string:object) atom_table = ([ ]);
+
+  /* Defined in Xlib.display */
+  void send_async_request(object req, function callback);
+  array blocking_request(object req);
+  
+  void remember_atom(object atom)
+  {
+    atoms[atom->id] = atom;
+    atom_table[atom->name] = atom;
+  }
+
+  object InternAtom_req(string name)
+  {
+    object req = Requests.InternAtom();
+    req->name = name;
+    return req;
+  }
+
+  /* Looks up the atom in local cache. If it is not present,
+   * issue an asyncronous InternAtom request, and return 0 */
+  object InternAtom(string name, function|void callback)
+  {
+    if (atom_table[name])
+      return atom_table[name];
+
+    object atom = Atom(this_object());
+    atom->name = name;
+
+    object req = Requests.InternAtom();
+    req->name = name;
+    send_async_request(req, pending_intern(this_object(), atom,
+					   callback)->handle_reply);
+    return 0;
+  }
+
+  object GetAtomName_req(object atom)
+  {
+    object req = Requests.GetAtomName();
+    req->atom = atom->id;
+    return req;
+  }
+  
+  object lookup_atom(int id, function|void callback)
+  {
+    if (atoms[id])
+      return atoms[id];
+    object atom = Atom(this_object());
+    atom->id = id;
+    object req = GetAtomName_req(atom);
+    if (callback)
+      {
+	send_async_request(req, pending_name_lookup(this_object(), atom,
+						  callback)->handle_reply);
+	return 0;
+      } else {
+	array a = blocking_request(req);
+	if (!a[0])
+	  return 0;
+	atom->name = a[1];
+	remember_atom(atom);
+	return atom;
+      }
+  }
+
+  void create() { }
+}