[PATCH:xwininfo] Convert from Xlib to xcb

Alan Coopersmith alan.coopersmith at oracle.com
Sun Jun 13 14:47:21 PDT 2010


Testing was done with a simple GNOME 2.28 session with a number of
applications open (gnome-terminal, VirtualBox, Firefox).

Primary test case was xwininfo -root -all, which listed 114 children of
the root window.   Output was identical to Xlib version (after applying
the fix to libxcb_icccm for always null-terminating wm_class properties).

Over a local connection on the same machine:

Xlib:	0.00u 0.01s 0:00.05 20.0%
xcb:	0.00u 0.00s 0:00.02 0.0%

(i.e. barely measurable difference - I had more variation between
 repeated runs of the command)

Introducing latency by running over ssh -X from California to Beijing
and back:

Xlib:	0.03u 0.02s 8:19.12 0.0%
xcb:	0.00u 0.00s 0:45.26 0.0%

Memory size when exit() is called:

Xlib:
 Address  Kbytes     RSS    Anon  Locked Mode   Mapped File
08043000      20      20      20       - rw---    [ stack ]
08400000     144     144     144       - rw---    [ heap ]
total Kb    8972    8640     316       -

xcb:
 Address  Kbytes     RSS    Anon  Locked Mode   Mapped File
08045000      12      12      12       - rwx--    [ stack ]
0806C000     100     100     100       - rwx--    [ heap ]
total Kb    7980    7692     288       -

Bytes sent & received (counted by proxying via xscope):

Xlib: Client --> Server: 21380 bytes   Client <-- Server:  54124 bytes
xcb:  Client --> Server: 21114 bytes   Client <-- Server:  53160 bytes

(The Xlib code didn't save any replies, so re-requested a couple of things
 when running with -all - I fixed that while porting to xcb, but the same
 could be done with Xlib easily too.)

Not yet handled: WM_NAME properties that need to be converted from another
character encoding.

Signed-off-by: Alan Coopersmith <alan.coopersmith at oracle.com>
---

I mostly did this as a way to learn more xcb, but it seems to be useful
for high-latency connections.   I would like to figure out how to handle
the property encoding conversion that XmbTextPropertyToTextList did in Xlib,
but haven't researched that yet (and with so many environments defaulting
to UTF-8 now, it's probably less useful than when it was originally done).

 COPYING      |    2 +-
 clientwin.c  |  190 +++++++-----
 clientwin.h  |    6 +-
 configure.ac |    8 +-
 dsimple.c    |  454 ++++++++++++++++-----------
 dsimple.h    |   54 +---
 xwininfo.c   | 1000 +++++++++++++++++++++++++++++++++++-----------------------
 7 files changed, 1024 insertions(+), 690 deletions(-)

diff --git a/COPYING b/COPYING
index 10b416d..687540f 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright © 1999 Sun Microsystems, Inc.  All rights reserved.
+Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
diff --git a/clientwin.c b/clientwin.c
index cce35ad..0d39fee 100644
--- a/clientwin.c
+++ b/clientwin.c
@@ -19,47 +19,57 @@
  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  * OF THIS SOFTWARE.
  */
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
+
+#include <stdlib.h>
+#include <string.h>
 
 #include "clientwin.h"
 
-static Atom atom_wm_state = None;
+static xcb_atom_t atom_wm_state = XCB_ATOM_NONE;
+typedef enum { False = 0, True } Bool;
 
 /*
  * Check if window has given property
  */
 static Bool
-Window_Has_Property(Display * dpy, Window win, Atom atom)
+Window_Has_Property(xcb_connection_t * dpy, xcb_window_t win, xcb_atom_t atom)
 {
-    Atom type_ret;
-    int format_ret;
-    unsigned char *prop_ret;
-    unsigned long bytes_after, num_ret;
-
-    type_ret = None;
-    prop_ret = NULL;
-    XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
-                       &type_ret, &format_ret, &num_ret,
-                       &bytes_after, &prop_ret);
-    if (prop_ret)
-        XFree(prop_ret);
-
-    return (type_ret != None) ? True : False;
+    xcb_get_property_cookie_t prop_cookie;
+    xcb_get_property_reply_t *prop_reply;
+
+    prop_cookie = xcb_get_property (dpy, False, win, atom,
+                                    XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
+
+    prop_reply = xcb_get_property_reply (dpy, prop_cookie, NULL);
+
+    if (prop_reply) {
+        free (prop_reply);
+        return True;
+    }
+
+    return False;
 }
 
 /*
  * Check if window is viewable
  */
 static Bool
-Window_Is_Viewable(Display * dpy, Window win)
+Window_Is_Viewable(xcb_connection_t * dpy, xcb_window_t win)
 {
-    Bool ok;
-    XWindowAttributes xwa;
+    Bool ok = False;
+    xcb_get_window_attributes_cookie_t attr_cookie;
+    xcb_get_window_attributes_reply_t *xwa;
 
-    XGetWindowAttributes(dpy, win, &xwa);
+    attr_cookie = xcb_get_window_attributes (dpy, win);
+    xwa = xcb_get_window_attributes_reply (dpy, attr_cookie, NULL);
 
-    ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable);
+    if (xwa) {
+        ok = (xwa->_class == XCB_WINDOW_CLASS_INPUT_OUTPUT) &&
+            (xwa->map_state == XCB_MAP_STATE_VIEWABLE);
+        free (xwa);
+    }
 
     return ok;
 }
@@ -70,24 +80,33 @@ Window_Is_Viewable(Display * dpy, Window win)
  * Children are searched in top-down stacking order.
  * The first matching window is returned, None if no match is found.
  */
-static Window
-Find_Client_In_Children(Display * dpy, Window win)
+static xcb_window_t
+Find_Client_In_Children(xcb_connection_t * dpy, xcb_window_t win)
 {
-    Window root, parent;
-    Window *children;
+    xcb_query_tree_cookie_t qt_cookie;
+    xcb_query_tree_reply_t *tree;
+    xcb_window_t root, parent;
+    xcb_window_t *children;
     unsigned int n_children;
     int i;
 
-    if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children))
-        return None;
-    if (!children)
-        return None;
+    qt_cookie = xcb_query_tree (dpy, win);
+    tree = xcb_query_tree_reply (dpy, qt_cookie, NULL);
+    if (!tree)
+        return XCB_WINDOW_NONE;
+    n_children = xcb_query_tree_children_length (tree);
+    if (!n_children) {
+        free (tree);
+        return XCB_WINDOW_NONE;
+    }
+    children = xcb_query_tree_children (tree);
 
     /* Check each child for WM_STATE and other validity */
-    win = None;
+    win = XCB_WINDOW_NONE;
     for (i = (int) n_children - 1; i >= 0; i--) {
         if (!Window_Is_Viewable(dpy, children[i])) {
-            children[i] = None; /* Don't bother descending into this one */
+            /* Don't bother descending into this one */
+            children[i] = XCB_WINDOW_NONE;
             continue;
         }
         if (!Window_Has_Property(dpy, children[i], atom_wm_state))
@@ -100,15 +119,15 @@ Find_Client_In_Children(Display * dpy, Window win)
 
     /* No children matched, now descend into each child */
     for (i = (int) n_children - 1; i >= 0; i--) {
-        if (children[i] == None)
+        if (children[i] == XCB_WINDOW_NONE)
             continue;
         win = Find_Client_In_Children(dpy, children[i]);
-        if (win != None)
+        if (win != XCB_WINDOW_NONE)
             break;
     }
 
   done:
-    XFree(children);
+    free (tree); /* includes children */
 
     return win;
 }
@@ -116,49 +135,68 @@ Find_Client_In_Children(Display * dpy, Window win)
 /*
  * Find virtual roots (_NET_VIRTUAL_ROOTS)
  */
-static unsigned long *
-Find_Roots(Display * dpy, Window root, unsigned int *num)
+static xcb_window_t *
+Find_Roots(xcb_connection_t * dpy, xcb_window_t root, unsigned int *num)
 {
-    Atom type_ret;
-    int format_ret;
-    unsigned char *prop_ret;
-    unsigned long bytes_after, num_ret;
-    Atom atom;
+    xcb_atom_t atom = XCB_ATOM_NONE;
+    xcb_intern_atom_cookie_t atom_cookie;
+    xcb_intern_atom_reply_t *atom_reply;
+
+    xcb_get_property_cookie_t prop_cookie;
+    xcb_get_property_reply_t *prop_reply;
+
+    xcb_window_t *prop_ret = NULL;
 
     *num = 0;
-    atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
+
+    atom_cookie = xcb_intern_atom (dpy, False, strlen("_NET_VIRTUAL_ROOTS"),
+                                   "_NET_VIRTUAL_ROOTS");
+    atom_reply = xcb_intern_atom_reply (dpy, atom_cookie, NULL);
+    if (atom_reply) {
+        atom = atom_reply->atom;
+        free (atom_reply);
+    }
     if (!atom)
         return NULL;
 
-    type_ret = None;
-    prop_ret = NULL;
-    if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False,
-                           XA_WINDOW, &type_ret, &format_ret, &num_ret,
-                           &bytes_after, &prop_ret) != Success)
+    prop_cookie = xcb_get_property (dpy, False, root, atom, XCB_ATOM_WINDOW,
+                                    0, 0x7fffffff);
+    prop_reply = xcb_get_property_reply (dpy, prop_cookie, NULL);
+    if (!prop_reply)
         return NULL;
 
-    if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) {
-        *num = num_ret;
-        return ((unsigned long *) prop_ret);
+    if ((prop_reply->value_len > 0) && (prop_reply->type == XCB_ATOM_WINDOW)
+        && (prop_reply->format == 32)) {
+        int length = xcb_get_property_value_length (prop_reply);
+        prop_ret = malloc(length);
+        if (prop_ret) {
+            memcpy (prop_ret, xcb_get_property_value(prop_reply), length);
+            *num = prop_reply->value_len;
+        }
     }
-    if (prop_ret)
-        XFree(prop_ret);
+    free (prop_reply);
 
-    return NULL;
+    return prop_ret;
 }
 
 /*
  * Find child window at pointer location
  */
-static Window
-Find_Child_At_Pointer(Display * dpy, Window win)
+static xcb_window_t
+Find_Child_At_Pointer(xcb_connection_t * dpy, xcb_window_t win)
 {
-    Window root_return, child_return;
-    int dummyi;
-    unsigned int dummyu;
+    xcb_window_t child_return = XCB_WINDOW_NONE;
+
+    xcb_query_pointer_cookie_t qp_cookie;
+    xcb_query_pointer_reply_t *qp_reply;
 
-    XQueryPointer(dpy, win, &root_return, &child_return,
-                  &dummyi, &dummyi, &dummyi, &dummyi, &dummyu);
+    qp_cookie = xcb_query_pointer (dpy, win);
+    qp_reply = xcb_query_pointer_reply (dpy, qp_cookie, NULL);
+
+    if (qp_reply) {
+        child_return = qp_reply->child;
+        free (qp_reply);
+    }
 
     return child_return;
 }
@@ -175,12 +213,12 @@ Find_Child_At_Pointer(Display * dpy, Window win)
  * This will of course work only if the virtual roots are children of the real
  * root.
  */
-Window
-Find_Client(Display * dpy, Window root, Window subwin)
+xcb_window_t
+Find_Client(xcb_connection_t * dpy, xcb_window_t root, xcb_window_t subwin)
 {
-    unsigned long *roots;
+    xcb_window_t *roots;
     unsigned int i, n_roots;
-    Window win;
+    xcb_window_t win;
 
     /* Check if subwin is a virtual root */
     roots = Find_Roots(dpy, root, &n_roots);
@@ -188,16 +226,24 @@ Find_Client(Display * dpy, Window root, Window subwin)
         if (subwin != roots[i])
             continue;
         win = Find_Child_At_Pointer(dpy, subwin);
-        if (win == None)
+        if (win == XCB_WINDOW_NONE)
             return subwin;      /* No child - Return virtual root. */
         subwin = win;
         break;
     }
-    if (roots)
-        XFree(roots);
+    free (roots);
 
-    if (atom_wm_state == None) {
-        atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
+    if (atom_wm_state == XCB_ATOM_NONE) {
+        xcb_intern_atom_cookie_t atom_cookie;
+        xcb_intern_atom_reply_t *atom_reply;
+
+        atom_cookie = xcb_intern_atom (dpy, False,
+                                       strlen("WM_STATE"), "WM_STATE");
+        atom_reply = xcb_intern_atom_reply (dpy, atom_cookie, NULL);
+        if (atom_reply) {
+            atom_wm_state = atom_reply->atom;
+            free (atom_reply);
+        }
         if (!atom_wm_state)
             return subwin;
     }
@@ -208,7 +254,7 @@ Find_Client(Display * dpy, Window root, Window subwin)
 
     /* Attempt to find a client window in subwin's children */
     win = Find_Client_In_Children(dpy, subwin);
-    if (win != None)
+    if (win != XCB_WINDOW_NONE)
         return win;             /* Found a client */
 
     /* Did not find a client */
diff --git a/clientwin.h b/clientwin.h
index 9fc59b5..05aa202 100644
--- a/clientwin.h
+++ b/clientwin.h
@@ -22,8 +22,10 @@
 #ifndef _CLIENTWIN_H_
 #define _CLIENTWIN_H_
 
-#include <X11/Xlib.h>
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
 
-extern Window Find_Client(Display * dpy, Window root, Window target_win);
+extern xcb_window_t Find_Client(xcb_connection_t * dpy, xcb_window_t root,
+				xcb_window_t target_win);
 
 #endif
diff --git a/configure.ac b/configure.ac
index 7ef640a..6da2984 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,8 +41,10 @@ XORG_DEFAULT_OPTIONS
 AC_CHECK_FUNCS([strlcat])
 
 # Checks for pkg-config packages
-PKG_CHECK_MODULES(XWININFO, xext x11 [xproto >= 7.0.17])
-AC_SUBST(XWININFO_CFLAGS)
-AC_SUBST(XWININFO_LIBS)
+PKG_CHECK_MODULES(XWININFO, [xcb >= 1.6] xcb-event xcb-icccm xcb-shape)
+# Even when using xcb, xproto is still required for Xfuncproto.h
+# and libX11 headers for cursorfont.h
+PKG_CHECK_MODULES(XLIB, x11 [xproto >= 7.0.17])
+XWININFO_CFLAGS="${XWININFO_CFLAGS} ${XLIB_CFLAGS}"
 
 AC_OUTPUT([Makefile])
diff --git a/dsimple.c b/dsimple.c
index 51df01f..b7c6048 100644
--- a/dsimple.c
+++ b/dsimple.c
@@ -1,4 +1,26 @@
 /*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+/*
 
 Copyright 1993, 1998  The Open Group
 
@@ -26,19 +48,15 @@ from The Open Group.
 
 */
 
-#include <X11/Xos.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
+#include <xcb/xcb_event.h>
+#include <xcb/xcb_icccm.h>
 #include <X11/cursorfont.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
-/*
- * Other_stuff.h: Definitions of routines in other_stuff.
- *
- * Written by Mark Lillibridge.   Last updated 7/1/87
- */
-
+#include <string.h>
 #include "clientwin.h"
 #include "dsimple.h"
 
@@ -46,72 +64,33 @@ from The Open Group.
  * Just_display: A group of routines designed to make the writing of simple
  *               X11 applications which open a display but do not open
  *               any windows much faster and easier.  Unless a routine says
- *               otherwise, it may be assumed to require program_name, dpy,
- *               and screen already defined on entry.
+ *               otherwise, it may be assumed to require program_name
+ *               to be already defined on entry.
  *
  * Written by Mark Lillibridge.   Last updated 7/1/87
  */
 
 
-/* This stuff is defined in the calling program by just_display.h */
+/* This stuff is defined in the calling program by dsimple.h */
 char    *program_name = "unknown_program";
-Display *dpy = NULL;
-int      screen = 0;
-
 
 /*
- * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obselete)
- * If found, remove it from command line.  Don't go past a lone -.
+ * Get_Display_Name (argc, argv) - return string representing display name
+ * that would be used given the specified argument (i.e. if it's NULL, check
+ * getenv("DISPLAY") - always returns a non-NULL pointer, though it may be
+ * an unwritable constant, so is safe to printf() on platforms that crash
+ * on NULL printf arguments.
  */
-char *Get_Display_Name (
-    int *pargc,  /* MODIFIED */
-    char **argv) /* MODIFIED */
+const char *Get_Display_Name (const char *display_name)
 {
-    int argc = *pargc;
-    char **pargv = argv+1;
-    char *displayname = NULL;
-    int i;
+    const char *name = display_name;
 
-    for (i = 1; i < argc; i++) {
-	char *arg = argv[i];
-
-	if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) {
-	    if (++i >= argc) usage ();
-
-	    displayname = argv[i];
-	    *pargc -= 2;
-	    continue;
-	}
-	if (!strcmp (arg,"-")) {
-	    while (i<argc)
-		*pargv++ = argv[i++];
-	    break;
-	}
-	*pargv++ = arg;
+    if (!name) {
+	name = getenv ("DISPLAY");
+	if (!name)
+	    name = "";
     }
-
-    *pargv = NULL;
-    return (displayname);
-}
-
-
-
-/*
- * Open_Display: Routine to open a display with correct error handling.
- *               Does not require dpy or screen defined on entry.
- */
-Display *Open_Display (char *display_name)
-{
-	Display *d;
-
-	d = XOpenDisplay (display_name);
-	if (d == NULL) {
-	    fprintf (stderr, "%s:  unable to open display '%s'\n",
-		     program_name, XDisplayName (display_name));
-	    exit (1);
-	}
-
-	return (d);
+    return (name);
 }
 
 
@@ -120,154 +99,116 @@ Display *Open_Display (char *display_name)
  *                           it calls Get_Display_Name) and then stores a
  *                           pointer to it in dpy.  The default screen
  *                           for this display is then stored in screen.
- *                           Does not require dpy or screen defined.
  */
 void Setup_Display_And_Screen (
-    int *argc,      /* MODIFIED */
-    char **argv)    /* MODIFIED */
+    const char *display_name,
+    xcb_connection_t **dpy,	/* MODIFIED */
+    xcb_screen_t **screen)	/* MODIFIED */
 {
-    char *displayname = NULL;
+    int screen_number, i;
 
-    displayname = Get_Display_Name (argc, argv);
-    dpy = Open_Display (displayname);
-    screen = XDefaultScreen (dpy);
-}
+    /* Open Display */
+    *dpy = xcb_connect (display_name, &screen_number);
+    if (xcb_connection_has_error (*dpy)) {
+	Fatal_Error ("unable to open display \"%s\"",
+		     Get_Display_Name(display_name) );
+    }
 
-/*
- * Close_Display: Close display
- */
-void Close_Display (void)
-{
-    if (dpy == NULL)
-      return;
+    if (screen) {
+	/* find our screen */
+	const xcb_setup_t *setup = xcb_get_setup(*dpy);
+	xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup);
 
-    XCloseDisplay (dpy);
-    dpy = NULL;
+	for (i = 0; i < screen_number; i++)
+	    xcb_screen_next(&screen_iter);
+	*screen = screen_iter.data;
+    }
 }
 
-
 /*
- * Select_Window_Args: a rountine to provide a common interface for
- *                     applications that need to allow the user to select one
- *                     window on the screen for special consideration.
- *                     This routine implements the following command line
- *                     arguments:
- *
- *                       -root            Selects the root window.
- *                       -id <id>         Selects window with id <id>. <id> may
- *                                        be either in decimal or hex.
- *                       -name <name>     Selects the window with name <name>.
- *
- *                     Call as Select_Window_Args(&argc, argv) in main before
- *                     parsing any of your program's command line arguments.
- *                     Select_Window_Args will remove its arguments so that
- *                     your program does not have to worry about them.
- *                     The window returned is the window selected or 0 if
- *                     none of the above arguments was present.  If 0 is
- *                     returned, Select_Window should probably be called after
- *                     all command line arguments, and other setup is done.
- *                     For examples of usage, see xwininfo, xwd, or xprop.
+ * xcb equivalent of XCreateFontCursor
  */
-Window Select_Window_Args (
-    int *rargc,
-    char **argv)
-#define ARGC (*rargc)
+static xcb_cursor_t
+Create_Font_Cursor (xcb_connection_t *dpy, uint16_t glyph)
 {
-    int nargc = 1;
-    int argc;
-    char **nargv;
-    Window w = 0;
-
-    nargv = argv+1; argc = ARGC;
-#define OPTION argv[0]
-#define NXTOPTP ++argv, --argc>0
-#define NXTOPT if (++argv, --argc==0) usage()
-#define COPYOPT nargv++[0]=OPTION, nargc++
-
-    while (NXTOPTP) {
-	if (!strcmp (OPTION, "-")) {
-	    COPYOPT;
-	    while (NXTOPTP)
-		COPYOPT;
-	    break;
-	}
-	if (!strcmp (OPTION, "-root")) {
-	    w = RootWindow (dpy, screen);
-	    continue;
-	}
-	if (!strcmp (OPTION, "-name")) {
-	    NXTOPT;
-	    w = Window_With_Name (dpy, RootWindow (dpy, screen), OPTION);
-	    if (!w)
-		Fatal_Error ("No window with name %s exists!", OPTION);
-	    continue;
-	}
-	if (!strcmp (OPTION, "-id")) {
-	    NXTOPT;
-	    w = 0;
-	    sscanf (OPTION, "0x%lx", &w);
-	    if (!w)
-		sscanf (OPTION, "%lu", &w);
-	    if (!w)
-		Fatal_Error ("Invalid window id format: %s.", OPTION);
-	    continue;
-	}
-	COPYOPT;
-    }
-    ARGC = nargc;
+    static xcb_font_t cursor_font;
+    xcb_cursor_t cursor;
 
-    return (w);
-}
+    if (!cursor_font) {
+	cursor_font = xcb_generate_id (dpy);
+	xcb_open_font (dpy, cursor_font, strlen ("cursor"), "cursor");
+    }
 
-/*
- * Other_stuff: A group of routines which do common X11 tasks.
- *
- * Written by Mark Lillibridge.   Last updated 7/1/87
- */
+    cursor = xcb_generate_id (dpy);
+    xcb_create_glyph_cursor (dpy, cursor, cursor_font, cursor_font,
+			     glyph, glyph + 1,
+                             0, 0, 0, 0xffff, 0xffff, 0xffff);  /* rgb, rgb */
 
+    return cursor;
+}
 
 /*
  * Routine to let user select a window using the mouse
  */
 
-Window Select_Window (Display *dpy, int descend)
+xcb_window_t Select_Window(xcb_connection_t *dpy,
+			   const xcb_screen_t *screen,
+			   int descend)
 {
     int status;
-    Cursor cursor;
-    XEvent event;
-    Window target_win = None, root = RootWindow (dpy,screen);
+    xcb_cursor_t cursor;
+    xcb_generic_event_t *event;
+    xcb_window_t target_win = XCB_WINDOW_NONE;
+    xcb_window_t root = screen->root;
     int buttons = 0;
+    xcb_generic_error_t *err;
+    xcb_grab_pointer_cookie_t grab_cookie;
+    xcb_grab_pointer_reply_t *grab_reply;
 
     /* Make the target cursor */
-    cursor = XCreateFontCursor (dpy, XC_crosshair);
+    cursor = Create_Font_Cursor (dpy, XC_crosshair);
 
     /* Grab the pointer using target cursor, letting it room all over */
-    status = XGrabPointer (dpy, root, False,
-			   ButtonPressMask|ButtonReleaseMask, GrabModeSync,
-			   GrabModeAsync, root, cursor, CurrentTime);
-    if (status != GrabSuccess) Fatal_Error ("Can't grab the mouse.");
+    grab_cookie = xcb_grab_pointer
+	(dpy, False, root,
+	 XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
+	 XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
+	 root, cursor, XCB_TIME_CURRENT_TIME);
+    grab_reply = xcb_grab_pointer_reply (dpy, grab_cookie, &err);
+    if (grab_reply->status != XCB_GRAB_STATUS_SUCCESS)
+	Fatal_Error ("Can't grab the mouse.");
 
     /* Let the user select a window... */
-    while ((target_win == None) || (buttons != 0)) {
+    while ((target_win == XCB_WINDOW_NONE) || (buttons != 0)) {
 	/* allow one more event */
-	XAllowEvents (dpy, SyncPointer, CurrentTime);
-	XWindowEvent (dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
-	switch (event.type) {
-	case ButtonPress:
-	    if (target_win == None) {
-		target_win = event.xbutton.subwindow; /* window selected */
-		if (target_win == None) target_win = root;
+	xcb_allow_events (dpy, XCB_ALLOW_SYNC_POINTER, XCB_TIME_CURRENT_TIME);
+	xcb_flush (dpy);
+	event = xcb_wait_for_event (dpy);
+	switch (XCB_EVENT_RESPONSE_TYPE(event)) {
+	case XCB_BUTTON_PRESS:
+	{
+	    xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event;
+
+	    if (target_win == XCB_WINDOW_NONE) {
+		target_win = bp->child; /* window selected */
+		if (target_win == XCB_WINDOW_NONE)
+		    target_win = root;
 	    }
 	    buttons++;
 	    break;
-	case ButtonRelease:
+	}
+	case XCB_BUTTON_RELEASE:
 	    if (buttons > 0) /* there may have been some down before we started */
 		buttons--;
 	    break;
+	default:
+	    /* just discard all other events */
+	    break;
 	}
+	free (event);
     }
 
-    XUngrabPointer (dpy, CurrentTime);      /* Done with pointer */
+    xcb_ungrab_pointer (dpy, XCB_TIME_CURRENT_TIME); /* Done with pointer */
 
     if (!descend || (target_win == root))
 	return (target_win);
@@ -285,36 +226,106 @@ Window Select_Window (Display *dpy, int descend)
  *                   one found will be returned.  Only top and its subwindows
  *                   are looked at.  Normally, top should be the RootWindow.
  */
-Window Window_With_Name (
-    Display *dpy,
-    Window top,
-    char *name)
+
+struct wininfo_cookies {
+    xcb_get_property_cookie_t get_wm_name;
+    xcb_query_tree_cookie_t query_tree;
+};
+
+static xcb_window_t
+recursive_Window_With_Name  (
+    xcb_connection_t *dpy,
+    xcb_window_t window,
+    struct wininfo_cookies *cookies,
+    const char *name)
 {
-    Window *children, dummy;
+    xcb_window_t *children;
     unsigned int nchildren;
     int i;
-    Window w=0;
+    xcb_window_t w = 0;
     char *window_name;
+    xcb_get_property_cookie_t get_wm_name_cookie;
+    xcb_generic_error_t *err;
+    xcb_get_text_property_reply_t prop;
+    xcb_query_tree_reply_t *tree;
+    struct wininfo_cookies *child_cookies;
+
+    if (xcb_get_wm_name_reply (dpy, cookies->get_wm_name, &prop, &err)) {
+	/* can't use strcmp, since prop.name is not null terminated */
+	if (strncmp (prop.name, name, prop.name_len) == 0) {
+	    w = window;
+	}
+
+	xcb_get_text_property_reply_wipe (&prop);
 
-    if (XFetchName (dpy, top, &window_name) && !strcmp (window_name, name))
-	return (top);
+	if (w)
+	{
+	    xcb_discard_reply (dpy, cookies->query_tree.sequence);
+	    return w;
+	}
+    } else if (err) {
+	if (err->response_type == 0)
+	    Print_X_Error (dpy, err);
+	return 0;
+    }
+
+    tree = xcb_query_tree_reply (dpy, cookies->query_tree, &err);
+    if (!tree) {
+	if (err->response_type == 0)
+	    Print_X_Error (dpy, err);
+	return 0;
+    }
+
+    nchildren = xcb_query_tree_children_length (tree);
+    children = xcb_query_tree_children (tree);
+    child_cookies = calloc(nchildren, sizeof(struct wininfo_cookies));
 
-    if (!XQueryTree (dpy, top, &dummy, &dummy, &children, &nchildren))
-	return (0);
+    if (child_cookies == NULL)
+	Fatal_Error("Failed to allocate memory in recursive_Window_With_Name");
 
     for (i = 0; i < nchildren; i++) {
-	w = Window_With_Name (dpy, children[i], name);
+	child_cookies[i].get_wm_name = xcb_get_wm_name (dpy, children[i]);
+	child_cookies[i].query_tree = xcb_query_tree (dpy, children[i]);
+    }
+    xcb_flush (dpy);
+
+    for (i = 0; i < nchildren; i++) {
+	w = recursive_Window_With_Name (dpy, children[i],
+					&child_cookies[i], name);
 	if (w)
 	    break;
     }
-    if (children) XFree ((char *)children);
+
+    if (w)
+    {
+	/* clean up remaining replies */
+	for (/* keep previous i */; i < nchildren; i++) {
+	    xcb_discard_reply (dpy, child_cookies[i].get_wm_name.sequence);
+	    xcb_discard_reply (dpy, child_cookies[i].query_tree.sequence);
+	}
+    }
+
+    free (child_cookies);
+    free (tree); /* includes storage for children[] */
     return (w);
 }
 
+xcb_window_t
+Window_With_Name (
+    xcb_connection_t *dpy,
+    xcb_window_t top,
+    const char *name)
+{
+    struct wininfo_cookies cookies;
+
+    cookies.get_wm_name = xcb_get_wm_name (dpy, top);
+    cookies.query_tree = xcb_query_tree (dpy, top);
+    return recursive_Window_With_Name(dpy, top, &cookies, name);
+}
+
 
 /*
  * Standard fatal error routine - call like printf
- * Does not require dpy or screen defined.
  */
 void Fatal_Error (char *msg, ...)
 {
@@ -326,6 +337,75 @@ void Fatal_Error (char *msg, ...)
     vfprintf (stderr, msg, args);
     va_end (args);
     fprintf (stderr, "\n");
-    Close_Display ();
     exit (EXIT_FAILURE);
 }
+
+/*
+ * Print X error information like the default Xlib error handler
+ */
+void
+Print_X_Error (
+    xcb_connection_t *dpy,
+    xcb_generic_error_t *err
+    )
+{
+    const char *label;
+    char buffer[256];
+
+    if ((err == NULL) || (err->response_type != 0)) /* not an error */
+	return;
+
+    label = xcb_event_get_error_label (err->error_code);
+    if (!label)
+    {
+	snprintf (buffer, sizeof(buffer), "Error code %d", err->error_code);
+	label = buffer;
+    }
+    fprintf (stderr, "X Error:  %s\n", label);
+
+    if (err->major_code < 128)
+	label = xcb_event_get_request_label (err->major_code);
+    else
+    {
+	// XXX: find extension name
+	label = NULL;
+    }
+    fprintf (stderr, "  Request Major code: %d (%s)\n", err->major_code,
+	     label ? label : "unknown");
+
+    if (err->major_code >= 128)
+    {
+	fprintf (stderr, "  Request Minor code: %d\n", err->minor_code);
+    }
+
+    if (err->error_code >= 128)
+    {
+	// XXX: find extension that defined this error
+    }
+    else
+    {
+	switch (err->error_code)
+	{
+	    case XCB_EVENT_ERROR_BAD_VALUE:
+		fprintf(stderr, "   Value: 0x%x\n", err->resource_id);
+		break;
+
+	    case XCB_EVENT_ERROR_BAD_ATOM:
+		fprintf(stderr, "   AtomID: 0x%x\n", err->resource_id);
+		break;
+
+	    case XCB_EVENT_ERROR_BAD_WINDOW:
+	    case XCB_EVENT_ERROR_BAD_PIXMAP:
+	    case XCB_EVENT_ERROR_BAD_CURSOR:
+	    case XCB_EVENT_ERROR_BAD_FONT:
+	    case XCB_EVENT_ERROR_BAD_DRAWABLE:
+	    case XCB_EVENT_ERROR_BAD_COLOR:
+	    case XCB_EVENT_ERROR_BAD_GC:
+	    case XCB_EVENT_ERROR_BAD_ID_CHOICE:
+		fprintf(stderr, "   ResourceID: 0x%x\n", err->resource_id);
+		break;
+	}
+    }
+
+    fprintf (stderr, "  Request serial number: %d\n", err->full_sequence);
+}
diff --git a/dsimple.h b/dsimple.h
index b0d76a5..677e3ca 100644
--- a/dsimple.h
+++ b/dsimple.h
@@ -27,55 +27,33 @@ from The Open Group.
 */
 
 /*
- * Just_display.h: This file contains the definitions needed to use the
- *                 functions in just_display.c.  It also declares the global
- *                 variables dpy, screen, and program_name which are needed to
- *                 use just_display.c.
+ * dsimple.h: This file contains the definitions needed to use the
+ *            functions in dsimple.c.  It also declares the global
+ *            variable program_name which is needed to use dsimple.c.
  *
- * Written by Mark Lillibridge.   Last updated 7/1/87
- *
- * Send bugs, etc. to chariot at athena.mit.edu.
+ * Written by Mark Lillibridge for Xlib.   Last updated 7/1/87
+ * Ported to XCB over two decades later.
  */
 
 #include <X11/Xfuncproto.h>
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
 
-    /* Simple helper macros */
-#ifndef MAX
-#define MAX(a,b) (((a)>(b))?(a):(b))
-#endif /* MAX */
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif /* MIN */
+typedef enum { False = 0, True } Bool;
 
     /* Global variables used by routines in dsimple.c */
 
 extern char *program_name;                   /* Name of this program */
-extern Display *dpy;                         /* The current display */
-extern int screen;                           /* The current screen */
-
-#define INIT_NAME program_name=argv[0]        /* use this in main to setup
-                                                 program_name */
 
-    /* Declaritions for functions in dsimple.c */
+    /* Declarations for functions in dsimple.c */
 
-char *Get_Display_Name(int *, char **);
-Display *Open_Display(char *);
-void Setup_Display_And_Screen(int *, char **);
-void Close_Display(void);
-Window Select_Window_Args(int *, char **);
-void usage(void);
+const char *Get_Display_Name (const char *displayname);
+void Setup_Display_And_Screen (const char *displayname,
+			       xcb_connection_t **dpy, xcb_screen_t **screen);
 
-#define X_USAGE "[host:display]"              /* X arguments handled by
-						 Get_Display_Name */
+xcb_window_t Select_Window(xcb_connection_t *, const xcb_screen_t *, int);
+xcb_window_t Window_With_Name(xcb_connection_t *, xcb_window_t, const char *);
 
-/*
- * Other_stuff.h: Definitions of routines in other_stuff.
- *
- * Written by Mark Lillibridge.   Last updated 7/1/87
- *
- * Send bugs, etc. to chariot at athena.mit.edu.
- */
+void Fatal_Error(char *, ...) _X_NORETURN;
 
-Window Select_Window(Display *, int);
-Window Window_With_Name(Display *, Window, char *);
-void Fatal_Error(char *, ...) _X_NORETURN _X_ATTRIBUTE_PRINTF(1, 2);
+void Print_X_Error (xcb_connection_t *, xcb_generic_error_t *);
diff --git a/xwininfo.c b/xwininfo.c
index 6b2f728..7d395df 100644
--- a/xwininfo.c
+++ b/xwininfo.c
@@ -1,5 +1,5 @@
 /*
- * Copyright © 1999 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -64,14 +64,16 @@ of the copyright holder.
  */
 
 #include "config.h"
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <X11/Xos.h>
-#include <X11/extensions/shape.h>
-#include <X11/Xlocale.h>
+
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
+#include <xcb/xcb_icccm.h>
+#include <xcb/shape.h>
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <locale.h>
 
 /* Include routines to handle parsing defaults */
 #include "dsimple.h"
@@ -81,29 +83,54 @@ typedef struct {
     const char *name;
 } binding;
 
-static void scale_init (void);
+/* Information we keep track of for each window to allow prefetching/reusing */
+struct wininfo {
+    xcb_window_t			window;
+
+    /* cookies for requests we've sent */
+    xcb_get_geometry_cookie_t		geometry_cookie;
+    xcb_get_property_cookie_t		wm_name_cookie;
+    xcb_get_property_cookie_t		wm_class_cookie;
+    xcb_translate_coordinates_cookie_t	trans_coords_cookie;
+    xcb_query_tree_cookie_t		tree_cookie;
+    xcb_get_window_attributes_cookie_t	attr_cookie;
+    xcb_get_property_cookie_t		normal_hints_cookie;
+    xcb_get_property_cookie_t		hints_cookie;
+    xcb_get_property_cookie_t		zoom_cookie;
+
+    /* cached results from previous requests */
+    xcb_get_geometry_reply_t *		geometry;
+    xcb_get_window_attributes_reply_t *	win_attributes;
+    xcb_size_hints_t *			normal_hints;
+};
+
+static void scale_init (xcb_screen_t *scrn);
 static char *nscale (int, int, int, char *, size_t);
 static char *xscale (int);
 static char *yscale (int);
 static char *bscale (int);
-static int bad_window_handler (Display *, XErrorEvent *);
 int main (int, char **);
 static const char *LookupL (long, const binding *);
 static const char *Lookup (int, const binding *);
-static void Display_Window_Id (Window, int);
-static void Display_Stats_Info (Window);
-static void Display_Bits_Info (Window);
+static void Display_Window_Id (struct wininfo *, Bool);
+static void Display_Stats_Info (struct wininfo *);
+static void Display_Bits_Info (struct wininfo *);
 static void Display_Event_Mask (long);
-static void Display_Events_Info (Window);
-static void Display_Tree_Info (Window, int);
-static void display_tree_info_1 (Window, int, int);
-static void Display_Hints (XSizeHints *);
-static void Display_Size_Hints (Window);
-static void Display_Window_Shape (Window);
-static void Display_WM_Info (Window);
+static void Display_Events_Info (struct wininfo *);
+static void Display_Tree_Info (struct wininfo *, int);
+static void display_tree_info_1 (struct wininfo *, int, int);
+static void Display_Hints (xcb_size_hints_t *);
+static void Display_Size_Hints (struct wininfo *);
+static void Display_Window_Shape (xcb_window_t);
+static void Display_WM_Info (struct wininfo *);
+static void wininfo_wipe (struct wininfo *);
 
 static const char *window_id_format = "0x%lx";
 
+static xcb_connection_t *dpy;
+static xcb_screen_t *screen;
+static xcb_generic_error_t *err;
+
 #ifndef HAVE_STRLCAT
 static size_t strlcat (char *dst, const char *src, size_t dstsize)
 {
@@ -164,19 +191,18 @@ usage (void)
  *
  */
 
-#define getdsp(var,fn) var = fn (dpy, DefaultScreen (dpy))
 static int xp = 0, xmm = 0;
 static int yp = 0, ymm = 0;
 static int bp = 0, bmm = 0;
 static int english = 0, metric = 0;
 
 static void
-scale_init (void)
+scale_init (xcb_screen_t *screen)
 {
-    getdsp (yp,  DisplayHeight);
-    getdsp (ymm, DisplayHeightMM);
-    getdsp (xp,  DisplayWidth);
-    getdsp (xmm, DisplayWidthMM);
+    xp = screen->width_in_pixels;
+    yp = screen->height_in_pixels;
+    xmm = screen->width_in_millimeters;
+    ymm = screen->height_in_millimeters;
     bp  = xp  + yp;
     bmm = xmm + ymm;
 }
@@ -250,9 +276,6 @@ static char xbuf[BUFSIZ];
 static char *
 xscale (int x)
 {
-    if (!xp) {
-	scale_init ();
-    }
     return (nscale (x, xp, xmm, xbuf, sizeof(xbuf)));
 }
 
@@ -260,9 +283,6 @@ static char ybuf[BUFSIZ];
 static char *
 yscale (int y)
 {
-    if (!yp) {
-	scale_init ();
-    }
     return (nscale (y, yp, ymm, ybuf, sizeof(ybuf)));
 }
 
@@ -270,53 +290,57 @@ static char bbuf[BUFSIZ];
 static char *
 bscale (int b)
 {
-    if (!bp) {
-	scale_init ();
-    }
     return (nscale (b, bp, bmm, bbuf, sizeof(bbuf)));
 }
 
 /* end of pixel to inch, metric converter */
 
-/* This handler is enabled when we are checking
-   to see if the -id the user specified is valid. */
-
-/* ARGSUSED */
-static int
-bad_window_handler (Display *disp, XErrorEvent *err)
-{
-    char badid[20];
-
-    snprintf (badid, sizeof(badid), window_id_format, err->resourceid);
-    Fatal_Error ("No such window with id %s.", badid);
-    exit (1);
-    return 0;
-}
-
-
 int
 main (int argc, char **argv)
 {
     register int i;
     int tree = 0, stats = 0, bits = 0, events = 0, wm = 0, size = 0, shape = 0;
     int frame = 0, children = 0;
-    Window window;
+    int use_root = 0;
+    xcb_window_t window = 0;
+    char *display_name = NULL;
+    const char *window_name = NULL;
+    struct wininfo wininfo;
+    struct wininfo *w = &wininfo;
 
-    INIT_NAME;
+    program_name = argv[0];
 
     if (!setlocale (LC_ALL, ""))
 	fprintf (stderr, "%s: can not set locale properly\n", program_name);
 
-    /* Open display, handle command line arguments */
-    Setup_Display_And_Screen (&argc, argv);
-
-    /* Get window selected on command line, if any */
-    window = Select_Window_Args (&argc, argv);
+    memset (w, 0, sizeof(struct wininfo));
 
     /* Handle our command line arguments */
     for (i = 1; i < argc; i++) {
 	if (!strcmp (argv[i], "-help"))
 	    usage ();
+	if (!strcmp (argv[i], "-display") || !strcmp (argv[i], "-d")) {
+	    if (++i >= argc)
+		Fatal_Error("-display requires argument");
+	    display_name = argv[i];
+	    continue;
+	}
+	if (!strcmp (argv[i], "-root")) {
+	    use_root = 1;
+	    continue;
+	}
+	if (!strcmp (argv[i], "-id")) {
+	    if (++i >= argc)
+		Fatal_Error("-id requires argument");
+	    window = strtoul(argv[i], NULL, 0);
+	    continue;
+	}
+	if (!strcmp (argv[i], "-name")) {
+	    if (++i >= argc)
+		Fatal_Error("-name requires argument");
+	    window_name = argv[i];
+	    continue;
+	}
 	if (!strcmp (argv[i], "-int")) {
 	    window_id_format = "%ld";
 	    continue;
@@ -372,13 +396,26 @@ main (int argc, char **argv)
 	usage ();
     }
 
+    Setup_Display_And_Screen (display_name, &dpy, &screen);
+
+    /* initialize scaling data */
+    scale_init(screen);
+
+    if (use_root)
+	window = screen->root;
+    else if (window_name) {
+	window = Window_With_Name (dpy, screen->root, window_name);
+	if (!window)
+	    Fatal_Error ("No window with name \"%s\" exists!", window_name);
+    }
+
     /* If no window selected on command line, let user pick one the hard way */
     if (!window) {
 	printf ("\n"
 		"xwininfo: Please select the window about which you\n"
 		"          would like information by clicking the\n"
 		"          mouse in that window.\n");
-	window = Select_Window (dpy, !frame);
+	window = Select_Window (dpy, screen, !frame);
     }
 
     /*
@@ -391,37 +428,102 @@ main (int argc, char **argv)
      * make sure that the window is valid
      */
     {
-	Window root;
-	int x, y;
-	unsigned width, height, bw, depth;
-	XErrorHandler old_handler;
-
-	old_handler = XSetErrorHandler (bad_window_handler);
-	XGetGeometry (dpy, window, &root, &x, &y, &width, &height, &bw, &depth);
-	XSync (dpy, False);
-	(void) XSetErrorHandler (old_handler);
+	xcb_get_geometry_cookie_t gg_cookie =
+	    xcb_get_geometry (dpy, window);
+
+	w->geometry = xcb_get_geometry_reply(dpy, gg_cookie, &err);
+
+	if (!w->geometry) {
+	    char badid[20];
+
+	    if (err)
+		Print_X_Error (dpy, err);
+
+	    snprintf (badid, sizeof(badid), window_id_format, window);
+	    Fatal_Error ("No such window with id 0x%x.", badid);
+	}
     }
 
+    /* Send requests to prefetch data we'll need */
+    w->window = window;
+    w->wm_name_cookie = xcb_get_wm_name (dpy, window);
+    if (children || tree)
+	w->tree_cookie = xcb_query_tree (dpy, window);
+    if (stats) {
+	w->trans_coords_cookie =
+	    xcb_translate_coordinates (dpy, window, w->geometry->root,
+				       -(w->geometry->border_width),
+				       -(w->geometry->border_width));
+    }
+    if (stats || bits || events)
+	w->attr_cookie = xcb_get_window_attributes (dpy, window);
+    if (stats || size)
+	w->normal_hints_cookie = xcb_get_wm_normal_hints (dpy, window);
+    if (wm)
+	w->hints_cookie = xcb_get_wm_hints(dpy, window);
+    if (size)
+	w->zoom_cookie = xcb_get_wm_size_hints (dpy, window,
+						XCB_ATOM_WM_ZOOM_HINTS);
+    xcb_flush (dpy);
+
     printf ("\nxwininfo: Window id: ");
-    Display_Window_Id (window, True);
+    Display_Window_Id (w, True);
     if (children || tree)
-	Display_Tree_Info (window, tree);
+	Display_Tree_Info (w, tree);
     if (stats)
-	Display_Stats_Info (window);
+	Display_Stats_Info (w);
     if (bits)
-	Display_Bits_Info (window);
+	Display_Bits_Info (w);
     if (events)
-	Display_Events_Info (window);
+	Display_Events_Info (w);
     if (wm)
-	Display_WM_Info (window);
+	Display_WM_Info (w);
     if (size)
-	Display_Size_Hints (window);
+	Display_Size_Hints (w);
     if (shape)
 	Display_Window_Shape (window);
     printf ("\n");
+
+    wininfo_wipe (w);
+    xcb_disconnect (dpy);
     exit (0);
 }
 
+/* Ensure win_attributes field is filled in */
+static xcb_get_window_attributes_reply_t *
+fetch_win_attributes (struct wininfo *w)
+{
+    if (!w->win_attributes) {
+	w->win_attributes =
+	    xcb_get_window_attributes_reply (dpy, w->attr_cookie, &err);
+
+	if (!w->win_attributes) {
+	    Print_X_Error (dpy, err);
+	    Fatal_Error ("Can't get window attributes.");
+	}
+    }
+    return w->win_attributes;
+}
+
+/* Ensure normal_hints field is filled in */
+static xcb_size_hints_t *
+fetch_normal_hints (struct wininfo *w, xcb_size_hints_t *hints_return)
+{
+    xcb_size_hints_t hints;
+
+    if (!w->normal_hints) {
+	if (xcb_get_wm_normal_hints_reply (dpy, w->normal_hints_cookie,
+					   &hints, NULL)) {
+	    w->normal_hints = malloc (sizeof(xcb_size_hints_t));
+	    if (w->normal_hints)
+		memcpy(w->normal_hints, &hints, sizeof(xcb_size_hints_t));
+	}
+    }
+    if (hints_return && w->normal_hints)
+	memcpy(hints_return, w->normal_hints, sizeof(xcb_size_hints_t));
+    return w->normal_hints;
+}
+
 
 /*
  * Lookup: lookup a code in a table.
@@ -458,41 +560,37 @@ Lookup (int code, const binding *table)
 
 /*
  * Routine to display a window id in dec/hex with name if window has one
+ *
+ * Requires wininfo members initialized: window, wm_name_cookie
  */
 
 static void
-Display_Window_Id (Window window, Bool newline_wanted)
+Display_Window_Id (struct wininfo *w, Bool newline_wanted)
 {
-    XTextProperty tp;
+    xcb_get_text_property_reply_t prop;
+    uint8_t got_reply;
 
-    printf (window_id_format, window);         /* print id # in hex/dec */
+    printf (window_id_format, w->window);      /* print id # in hex/dec */
 
-    if (!window) {
+    if (!w->window) {
 	printf (" (none)");
     } else {
-	if (window == RootWindow (dpy, screen)) {
+	if (w->window == screen->root) {
 	    printf (" (the root window)");
 	}
-	if (!XGetWMName (dpy, window, &tp)) { /* Get window name if any */
+	/* Get window name if any */
+	got_reply = xcb_get_wm_name_reply (dpy, w->wm_name_cookie,
+					   &prop, NULL);
+	if (!got_reply || prop.name_len == 0) {
 	    printf (" (has no name)");
-        } else if (tp.nitems > 0) {
+        } else {
             printf (" \"");
-            {
-                int count = 0, i, ret;
-                char **list = NULL;
-                ret = XmbTextPropertyToTextList (dpy, &tp, &list, &count);
-                if ((ret == Success || ret > 0) && list != NULL){
-                    for (i = 0; i < count; i++)
-                        printf ("%s", list[i]);
-                    XFreeStringList (list);
-                } else {
-                    printf ("%s", tp.value);
-                }
-            }
+	    /* XXX: need to handle encoding */
+	    printf ("%.*s", prop.name_len, prop.name);
             printf ("\"");
 	}
-	else
-	    printf (" (has no name)");
+	if (got_reply)
+	    xcb_get_text_property_reply_wipe (&prop);
     }
 
     if (newline_wanted)
@@ -506,211 +604,244 @@ Display_Window_Id (Window window, Bool newline_wanted)
  * Display Stats on window
  */
 static const binding _window_classes[] = {
-	{ InputOutput, "InputOutput" },
-	{ InputOnly, "InputOnly" },
+	{ XCB_WINDOW_CLASS_INPUT_OUTPUT, "InputOutput" },
+	{ XCB_WINDOW_CLASS_INPUT_ONLY, "InputOnly" },
         { 0, NULL } };
 
 static const binding _map_states[] = {
-	{ IsUnmapped, "IsUnMapped" },
-	{ IsUnviewable, "IsUnviewable" },
-	{ IsViewable, "IsViewable" },
+	{ XCB_MAP_STATE_UNMAPPED,	"IsUnMapped" },
+	{ XCB_MAP_STATE_UNVIEWABLE,	"IsUnviewable" },
+	{ XCB_MAP_STATE_VIEWABLE,	"IsViewable" },
 	{ 0, NULL } };
 
 static const binding _backing_store_states[] = {
-	{ NotUseful, "NotUseful" },
-	{ WhenMapped, "WhenMapped" },
-	{ Always, "Always" },
+	{ XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
+	{ XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
+	{ XCB_BACKING_STORE_ALWAYS,	"Always" },
 	{ 0, NULL } };
 
 static const binding _bit_gravity_states[] = {
-	{ ForgetGravity, "ForgetGravity" },
-	{ NorthWestGravity, "NorthWestGravity" },
-	{ NorthGravity, "NorthGravity" },
-	{ NorthEastGravity, "NorthEastGravity" },
-	{ WestGravity, "WestGravity" },
-	{ CenterGravity, "CenterGravity" },
-	{ EastGravity, "EastGravity" },
-	{ SouthWestGravity, "SouthWestGravity" },
-	{ SouthGravity, "SouthGravity" },
-	{ SouthEastGravity, "SouthEastGravity" },
-	{ StaticGravity, "StaticGravity" },
+	{ XCB_GRAVITY_BIT_FORGET,	"ForgetGravity" },
+	{ XCB_GRAVITY_NORTH_WEST,	"NorthWestGravity" },
+	{ XCB_GRAVITY_NORTH,		"NorthGravity" },
+	{ XCB_GRAVITY_NORTH_EAST,	"NorthEastGravity" },
+	{ XCB_GRAVITY_WEST,		"WestGravity" },
+	{ XCB_GRAVITY_CENTER,		"CenterGravity" },
+	{ XCB_GRAVITY_EAST,		"EastGravity" },
+	{ XCB_GRAVITY_SOUTH_WEST,	"SouthWestGravity" },
+	{ XCB_GRAVITY_SOUTH,		"SouthGravity" },
+	{ XCB_GRAVITY_SOUTH_EAST,	"SouthEastGravity" },
+	{ XCB_GRAVITY_STATIC,		"StaticGravity" },
 	{ 0, NULL }};
 
 static const binding _window_gravity_states[] = {
-	{ UnmapGravity, "UnmapGravity" },
-	{ NorthWestGravity, "NorthWestGravity" },
-	{ NorthGravity, "NorthGravity" },
-	{ NorthEastGravity, "NorthEastGravity" },
-	{ WestGravity, "WestGravity" },
-	{ CenterGravity, "CenterGravity" },
-	{ EastGravity, "EastGravity" },
-	{ SouthWestGravity, "SouthWestGravity" },
-	{ SouthGravity, "SouthGravity" },
-	{ SouthEastGravity, "SouthEastGravity" },
-	{ StaticGravity, "StaticGravity" },
+	{ XCB_GRAVITY_WIN_UNMAP,	"UnmapGravity" },
+	{ XCB_GRAVITY_NORTH_WEST,	"NorthWestGravity" },
+	{ XCB_GRAVITY_NORTH,		"NorthGravity" },
+	{ XCB_GRAVITY_NORTH_EAST,	"NorthEastGravity" },
+	{ XCB_GRAVITY_WEST,		"WestGravity" },
+	{ XCB_GRAVITY_CENTER,		"CenterGravity" },
+	{ XCB_GRAVITY_EAST,		"EastGravity" },
+	{ XCB_GRAVITY_SOUTH_WEST,	"SouthWestGravity" },
+	{ XCB_GRAVITY_SOUTH,		"SouthGravity" },
+	{ XCB_GRAVITY_SOUTH_EAST,	"SouthEastGravity" },
+	{ XCB_GRAVITY_STATIC,		"StaticGravity" },
 	{ 0, NULL }};
 
 static const binding _visual_classes[] = {
-	{ StaticGray, "StaticGray" },
-	{ GrayScale, "GrayScale" },
-	{ StaticColor, "StaticColor" },
-	{ PseudoColor, "PseudoColor" },
-	{ TrueColor, "TrueColor" },
-	{ DirectColor, "DirectColor" },
+	{ XCB_VISUAL_CLASS_STATIC_GRAY,	"StaticGray" },
+	{ XCB_VISUAL_CLASS_GRAY_SCALE,	"GrayScale" },
+	{ XCB_VISUAL_CLASS_STATIC_COLOR,"StaticColor" },
+	{ XCB_VISUAL_CLASS_PSEUDO_COLOR,"PseudoColor" },
+	{ XCB_VISUAL_CLASS_TRUE_COLOR,	"TrueColor" },
+	{ XCB_VISUAL_CLASS_DIRECT_COLOR,"DirectColor" },
 	{ 0, NULL }};
 
+/*
+ * Requires wininfo members initialized:
+ *   window, geometry, attr_cookie, trans_coords_cookie, normal_hints_cookie
+ */
 static void
-Display_Stats_Info (Window window)
+Display_Stats_Info (struct wininfo *w)
 {
-    XWindowAttributes win_attributes;
-    XVisualInfo vistemplate, *vinfo;
-    XSizeHints hints;
-    int dw = DisplayWidth (dpy, screen), dh = DisplayHeight (dpy, screen);
+    xcb_translate_coordinates_reply_t *trans_coords;
+    xcb_get_window_attributes_reply_t *win_attributes;
+    xcb_size_hints_t hints;
+
+    int dw = screen->width_in_pixels, dh = screen->height_in_pixels;
     int rx, ry, xright, ybelow;
     int showright = 0, showbelow = 0;
-    Status status;
-    Window wmframe;
-    int junk;
-    long longjunk;
-    Window junkwin;
-
-    if (!XGetWindowAttributes (dpy, window, &win_attributes))
-	Fatal_Error ("Can't get window attributes.");
-    vistemplate.visualid = XVisualIDFromVisual (win_attributes.visual);
-    vinfo = XGetVisualInfo (dpy, VisualIDMask, &vistemplate, &junk);
-
-    (void) XTranslateCoordinates (dpy, window, win_attributes.root,
-				  -win_attributes.border_width,
-				  -win_attributes.border_width,
-				  &rx, &ry, &junkwin);
-
-    xright = (dw - rx - win_attributes.border_width * 2 -
-	      win_attributes.width);
-    ybelow = (dh - ry - win_attributes.border_width * 2 -
-	      win_attributes.height);
+    xcb_window_t wmframe, parent;
+
+    trans_coords =
+	xcb_translate_coordinates_reply (dpy, w->trans_coords_cookie, NULL);
+    if (!trans_coords)
+	Fatal_Error ("Can't get translated coordinates.");
+
+    rx = trans_coords->dst_x;
+    ry = trans_coords->dst_y;
+    free (trans_coords);
+
+    xright = (dw - rx - w->geometry->border_width * 2 -
+	      w->geometry->width);
+    ybelow = (dh - ry - w->geometry->border_width * 2 -
+	      w->geometry->height);
+
 
     printf ("\n");
     printf ("  Absolute upper-left X:  %s\n", xscale (rx));
     printf ("  Absolute upper-left Y:  %s\n", yscale (ry));
-    printf ("  Relative upper-left X:  %s\n", xscale (win_attributes.x));
-    printf ("  Relative upper-left Y:  %s\n", yscale (win_attributes.y));
-    printf ("  Width: %s\n", xscale (win_attributes.width));
-    printf ("  Height: %s\n", yscale (win_attributes.height));
-    printf ("  Depth: %d\n", win_attributes.depth);
-    printf ("  Visual: 0x%lx\n", vinfo->visualid);
-    printf ("  Visual Class: %s\n", Lookup (vinfo->class, _visual_classes));
-    printf ("  Border width: %s\n", bscale (win_attributes.border_width));
+    printf ("  Relative upper-left X:  %s\n", xscale (w->geometry->x));
+    printf ("  Relative upper-left Y:  %s\n", yscale (w->geometry->y));
+    printf ("  Width: %s\n", xscale (w->geometry->width));
+    printf ("  Height: %s\n", yscale (w->geometry->height));
+    printf ("  Depth: %d\n", w->geometry->depth);
+
+    win_attributes = fetch_win_attributes (w);
+
+    printf ("  Visual: 0x%lx\n", win_attributes->visual);
+    if (screen)
+    {
+	xcb_depth_iterator_t depth_iter;
+	xcb_visualtype_t  *visual_type = NULL;
+
+	depth_iter = xcb_screen_allowed_depths_iterator (screen);
+	for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
+	    xcb_visualtype_iterator_t visual_iter;
+
+	    visual_iter = xcb_depth_visuals_iterator (depth_iter.data);
+	    for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
+		if (screen->root_visual == visual_iter.data->visual_id) {
+		    visual_type = visual_iter.data;
+		    break;
+		}
+	    }
+	}
+	if (visual_type)
+	    printf ("  Visual Class: %s\n", Lookup (visual_type->_class,
+						    _visual_classes));
+    }
+
+    printf ("  Border width: %s\n", bscale (w->geometry->border_width));
     printf ("  Class: %s\n",
-	    Lookup (win_attributes.class, _window_classes));
+	    Lookup (win_attributes->_class, _window_classes));
     printf ("  Colormap: 0x%lx (%sinstalled)\n",
-	    win_attributes.colormap,
-	    win_attributes.map_installed ? "" : "not ");
+	    win_attributes->colormap,
+	    win_attributes->map_is_installed ? "" : "not ");
     printf ("  Bit Gravity State: %s\n",
-	    Lookup (win_attributes.bit_gravity, _bit_gravity_states));
+	    Lookup (win_attributes->bit_gravity, _bit_gravity_states));
     printf ("  Window Gravity State: %s\n",
-	    Lookup (win_attributes.win_gravity, _window_gravity_states));
+	    Lookup (win_attributes->win_gravity, _window_gravity_states));
     printf ("  Backing Store State: %s\n",
-	    Lookup (win_attributes.backing_store, _backing_store_states));
+	    Lookup (win_attributes->backing_store, _backing_store_states));
     printf ("  Save Under State: %s\n",
-	    win_attributes.save_under ? "yes" : "no");
+	    win_attributes->save_under ? "yes" : "no");
     printf ("  Map State: %s\n",
-	    Lookup (win_attributes.map_state, _map_states));
+	    Lookup (win_attributes->map_state, _map_states));
     printf ("  Override Redirect State: %s\n",
-	    win_attributes.override_redirect ? "yes" : "no");
+	    win_attributes->override_redirect ? "yes" : "no");
     printf ("  Corners:  +%d+%d  -%d+%d  -%d-%d  +%d-%d\n",
 	    rx, ry, xright, ry, xright, ybelow, rx, ybelow);
 
-    XFree (vinfo);
-
     /*
      * compute geometry string that would recreate window
      */
     printf ("  -geometry ");
 
     /* compute size in appropriate units */
-    status = XGetWMNormalHints (dpy, window, &hints, &longjunk);
-    if (status  &&  hints.flags & PResizeInc  &&
-	hints.width_inc != 0  &&  hints.height_inc != 0) {
-	if (hints.flags & (PBaseSize|PMinSize)) {
-	    if (hints.flags & PBaseSize) {
-		win_attributes.width -= hints.base_width;
-		win_attributes.height -= hints.base_height;
+    if (!fetch_normal_hints (w, &hints))
+	hints.flags = 0;
+
+    if ((hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)  &&
+	(hints.width_inc != 0)  && (hints.height_inc != 0)) {
+	if (hints.flags & (XCB_SIZE_HINT_BASE_SIZE|XCB_SIZE_HINT_P_MIN_SIZE)) {
+	    if (hints.flags & XCB_SIZE_HINT_BASE_SIZE) {
+		w->geometry->width -= hints.base_width;
+		w->geometry->height -= hints.base_height;
 	    } else {
 		/* ICCCM says MinSize is default for BaseSize */
-		win_attributes.width -= hints.min_width;
-		win_attributes.height -= hints.min_height;
+		w->geometry->width -= hints.min_width;
+		w->geometry->height -= hints.min_height;
 	    }
 	}
-	printf ("%dx%d", win_attributes.width/hints.width_inc,
-		win_attributes.height/hints.height_inc);
+	printf ("%dx%d", w->geometry->width/hints.width_inc,
+		w->geometry->height/hints.height_inc);
     } else
-	printf ("%dx%d", win_attributes.width, win_attributes.height);
+	printf ("%dx%d", w->geometry->width, w->geometry->height);
 
-    if (!(hints.flags&PWinGravity))
-	hints.win_gravity = NorthWestGravity; /* per ICCCM */
+    if (!(hints.flags & XCB_SIZE_HINT_P_WIN_GRAVITY))
+	hints.win_gravity = XCB_GRAVITY_NORTH_WEST; /* per ICCCM */
     /* find our window manager frame, if any */
-    wmframe = window;
-    while (True) {
-	Window root, parent;
-	Window *childlist;
-	unsigned int ujunk;
-
-	status = XQueryTree (dpy, wmframe, &root, &parent, &childlist, &ujunk);
-	if (parent == root || !parent || !status)
+    for (wmframe = parent = w->window; parent != 0 ; wmframe = parent) {
+	xcb_query_tree_cookie_t qt_cookie;
+	xcb_query_tree_reply_t *tree;
+
+	qt_cookie = xcb_query_tree (dpy, wmframe);
+	tree = xcb_query_tree_reply (dpy, qt_cookie, &err);
+	if (!tree) {
+	    Print_X_Error (dpy, err);
+	    Fatal_Error ("Can't query window tree.");
+	}
+	parent = tree->parent;
+	free (tree);
+	if (parent == w->geometry->root || !parent)
 	    break;
-	wmframe = parent;
-	if (status && childlist)
-	    XFree ((char *)childlist);
     }
-    if (wmframe != window) {
+    if (wmframe != w->window) {
 	/* WM reparented, so find edges of the frame */
 	/* Only works for ICCCM-compliant WMs, and then only if the
 	   window has corner gravity.  We would need to know the original width
 	   of the window to correctly handle the other gravities. */
+	xcb_get_geometry_cookie_t geom_cookie;
+	xcb_get_geometry_reply_t *frame_geometry;
 
-	XWindowAttributes frame_attr;
+	geom_cookie = xcb_get_geometry (dpy, wmframe);
+	frame_geometry = xcb_get_geometry_reply (dpy, geom_cookie, &err);
 
-	if (!XGetWindowAttributes (dpy, wmframe, &frame_attr))
-	    Fatal_Error ("Can't get frame attributes.");
+	if (!frame_geometry) {
+	    Print_X_Error (dpy, err);
+	    Fatal_Error ("Can't get frame geometry.");
+	}
 	switch (hints.win_gravity) {
-	    case NorthWestGravity: case SouthWestGravity:
-	    case NorthEastGravity: case SouthEastGravity:
-	    case WestGravity:
-		rx = frame_attr.x;
+	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+	    case XCB_GRAVITY_WEST:
+		rx = frame_geometry->x;
 	}
 	switch (hints.win_gravity) {
-	    case NorthWestGravity: case SouthWestGravity:
-	    case NorthEastGravity: case SouthEastGravity:
-	    case EastGravity:
-		xright = dw - frame_attr.x - frame_attr.width -
-		    2*frame_attr.border_width;
+	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+	    case XCB_GRAVITY_EAST:
+		xright = dw - frame_geometry->x - frame_geometry->width -
+		    (2 * frame_geometry->border_width);
 	}
 	switch (hints.win_gravity) {
-	    case NorthWestGravity: case SouthWestGravity:
-	    case NorthEastGravity: case SouthEastGravity:
-	    case NorthGravity:
-		ry = frame_attr.y;
+	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+	    case XCB_GRAVITY_NORTH:
+		ry = frame_geometry->y;
 	}
 	switch (hints.win_gravity) {
-	    case NorthWestGravity: case SouthWestGravity:
-	    case NorthEastGravity: case SouthEastGravity:
-	    case SouthGravity:
-		ybelow = dh - frame_attr.y - frame_attr.height -
-		    2*frame_attr.border_width;
+	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+	    case XCB_GRAVITY_SOUTH:
+		ybelow = dh - frame_geometry->y - frame_geometry->height -
+		    (2 * frame_geometry->border_width);
 	}
+	free (frame_geometry);
     }
     /* If edge gravity, offer a corner on that edge (because the application
        programmer cares about that edge), otherwise offer upper left unless
        some other corner is close to an edge of the screen.
        (For corner gravity, assume gravity was set by XWMGeometry.
        For CenterGravity, it doesn't matter.) */
-    if (hints.win_gravity == EastGravity  ||
+    if (hints.win_gravity == XCB_GRAVITY_EAST  ||
 	(abs (xright) <= 100  &&  abs (xright) < abs (rx)
-	 &&  hints.win_gravity != WestGravity))
+	 &&  hints.win_gravity != XCB_GRAVITY_WEST))
 	showright = 1;
-    if (hints.win_gravity == SouthGravity  ||
+    if (hints.win_gravity == XCB_GRAVITY_SOUTH  ||
 	(abs (ybelow) <= 100  &&  abs (ybelow) < abs (ry)
-	 &&  hints.win_gravity != NorthGravity))
+	 &&  hints.win_gravity != XCB_GRAVITY_NORTH))
 	showbelow = 1;
 
     if (showright)
@@ -729,24 +860,25 @@ Display_Stats_Info (Window window)
  * Display bits info:
  */
 static const binding _gravities[] = {
-	{ UnmapGravity, "UnMapGravity" },      /* WARNING: both of these have*/
-	{ ForgetGravity, "ForgetGravity" },    /* the same value - see code */
-	{ NorthWestGravity, "NorthWestGravity" },
-	{ NorthGravity, "NorthGravity" },
-	{ NorthEastGravity, "NorthEastGravity" },
-	{ WestGravity, "WestGravity" },
-	{ CenterGravity, "CenterGravity" },
-	{ EastGravity, "EastGravity" },
-	{ SouthWestGravity, "SouthWestGravity" },
-	{ SouthGravity, "SouthGravity" },
-	{ SouthEastGravity, "SouthEastGravity" },
-	{ StaticGravity, "StaticGravity" },
+    /* WARNING: the first two of these have the same value - see code */
+	{ XCB_GRAVITY_WIN_UNMAP,	"UnMapGravity" },
+	{ XCB_GRAVITY_BIT_FORGET,	"ForgetGravity" },
+	{ XCB_GRAVITY_NORTH_WEST,	"NorthWestGravity" },
+	{ XCB_GRAVITY_NORTH,		"NorthGravity" },
+	{ XCB_GRAVITY_NORTH_EAST,	"NorthEastGravity" },
+	{ XCB_GRAVITY_WEST,		"WestGravity" },
+	{ XCB_GRAVITY_CENTER,		"CenterGravity" },
+	{ XCB_GRAVITY_EAST,		"EastGravity" },
+	{ XCB_GRAVITY_SOUTH_WEST,	"SouthWestGravity" },
+	{ XCB_GRAVITY_SOUTH,		"SouthGravity" },
+	{ XCB_GRAVITY_SOUTH_EAST,	"SouthEastGravity" },
+	{ XCB_GRAVITY_STATIC,		"StaticGravity" },
 	{ 0, NULL } };
 
 static const binding _backing_store_hint[] = {
-	{ NotUseful, "NotUseful" },
-	{ WhenMapped, "WhenMapped" },
-	{ Always, "Always" },
+	{ XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
+	{ XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
+	{ XCB_BACKING_STORE_ALWAYS,	"Always" },
 	{ 0, NULL } };
 
 static const binding _bool[] = {
@@ -754,26 +886,28 @@ static const binding _bool[] = {
 	{ 1, "Yes" },
 	{ 0, NULL } };
 
+/*
+ * Requires wininfo members initialized:
+ *   window, attr_cookie (or win_attributes)
+ */
 static void
-Display_Bits_Info (Window window)
+Display_Bits_Info (struct wininfo * w)
 {
-    XWindowAttributes win_attributes;
-
-    if (!XGetWindowAttributes (dpy, window, &win_attributes))
-	Fatal_Error ("Can't get window attributes.");
+    xcb_get_window_attributes_reply_t *win_attributes
+	= fetch_win_attributes (w);
 
     printf ("\n");
     printf ("  Bit gravity: %s\n",
-	    Lookup (win_attributes.bit_gravity, _gravities+1));
+	    Lookup (win_attributes->bit_gravity, _gravities+1));
     printf ("  Window gravity: %s\n",
-	    Lookup (win_attributes.win_gravity, _gravities));
+	    Lookup (win_attributes->win_gravity, _gravities));
     printf ("  Backing-store hint: %s\n",
-	    Lookup (win_attributes.backing_store, _backing_store_hint));
+	    Lookup (win_attributes->backing_store, _backing_store_hint));
     printf ("  Backing-planes to be preserved: 0x%lx\n",
-	    win_attributes.backing_planes);
-    printf ("  Backing pixel: %ld\n", win_attributes.backing_pixel);
+	    win_attributes->backing_planes);
+    printf ("  Backing pixel: %ld\n", win_attributes->backing_pixel);
     printf ("  Save-unders: %s\n",
-	    Lookup (win_attributes.save_under, _bool));
+	    Lookup (win_attributes->save_under, _bool));
 }
 
 
@@ -781,31 +915,31 @@ Display_Bits_Info (Window window)
  * Routine to display all events in an event mask
  */
 static const binding _event_mask_names[] = {
-	{ KeyPressMask, "KeyPress" },
-	{ KeyReleaseMask, "KeyRelease" },
-	{ ButtonPressMask, "ButtonPress" },
-	{ ButtonReleaseMask, "ButtonRelease" },
-	{ EnterWindowMask, "EnterWindow" },
-	{ LeaveWindowMask, "LeaveWindow" },
-	{ PointerMotionMask, "PointerMotion" },
-	{ PointerMotionHintMask, "PointerMotionHint" },
-	{ Button1MotionMask, "Button1Motion" },
-	{ Button2MotionMask, "Button2Motion" },
-	{ Button3MotionMask, "Button3Motion" },
-	{ Button4MotionMask, "Button4Motion" },
-	{ Button5MotionMask, "Button5Motion" },
-	{ ButtonMotionMask, "ButtonMotion" },
-	{ KeymapStateMask, "KeymapState" },
-	{ ExposureMask, "Exposure" },
-	{ VisibilityChangeMask, "VisibilityChange" },
-	{ StructureNotifyMask, "StructureNotify" },
-	{ ResizeRedirectMask, "ResizeRedirect" },
-	{ SubstructureNotifyMask, "SubstructureNotify" },
-	{ SubstructureRedirectMask, "SubstructureRedirect" },
-	{ FocusChangeMask, "FocusChange" },
-	{ PropertyChangeMask, "PropertyChange" },
-	{ ColormapChangeMask, "ColormapChange" },
-	{ OwnerGrabButtonMask, "OwnerGrabButton" },
+	{ XCB_EVENT_MASK_KEY_PRESS,		"KeyPress" },
+	{ XCB_EVENT_MASK_KEY_RELEASE,		"KeyRelease" },
+	{ XCB_EVENT_MASK_BUTTON_PRESS,		"ButtonPress" },
+	{ XCB_EVENT_MASK_BUTTON_RELEASE,	"ButtonRelease" },
+	{ XCB_EVENT_MASK_ENTER_WINDOW,		"EnterWindow" },
+	{ XCB_EVENT_MASK_LEAVE_WINDOW,		"LeaveWindow" },
+	{ XCB_EVENT_MASK_POINTER_MOTION,	"PointerMotion" },
+	{ XCB_EVENT_MASK_POINTER_MOTION_HINT,	"PointerMotionHint" },
+	{ XCB_EVENT_MASK_BUTTON_1_MOTION,	"Button1Motion" },
+	{ XCB_EVENT_MASK_BUTTON_2_MOTION,	"Button2Motion" },
+	{ XCB_EVENT_MASK_BUTTON_3_MOTION,	"Button3Motion" },
+	{ XCB_EVENT_MASK_BUTTON_4_MOTION,	"Button4Motion" },
+	{ XCB_EVENT_MASK_BUTTON_5_MOTION,	"Button5Motion" },
+	{ XCB_EVENT_MASK_BUTTON_MOTION,		"ButtonMotion" },
+	{ XCB_EVENT_MASK_KEYMAP_STATE,		"KeymapState" },
+	{ XCB_EVENT_MASK_EXPOSURE,		"Exposure" },
+	{ XCB_EVENT_MASK_VISIBILITY_CHANGE,	"VisibilityChange" },
+	{ XCB_EVENT_MASK_STRUCTURE_NOTIFY,	"StructureNotify" },
+	{ XCB_EVENT_MASK_RESIZE_REDIRECT,	"ResizeRedirect" },
+	{ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,	"SubstructureNotify" },
+	{ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,	"SubstructureRedirect" },
+	{ XCB_EVENT_MASK_FOCUS_CHANGE,		"FocusChange" },
+	{ XCB_EVENT_MASK_PROPERTY_CHANGE,	"PropertyChange" },
+	{ XCB_EVENT_MASK_COLOR_MAP_CHANGE,	"ColormapChange" },
+	{ XCB_EVENT_MASK_OWNER_GRAB_BUTTON,	"OwnerGrabButton" },
 	{ 0, NULL } };
 
 static void
@@ -822,24 +956,25 @@ Display_Event_Mask (long mask)
 
 /*
  * Display info on events
+ *
+ * Requires wininfo members initialized:
+ *   window, attr_cookie (or win_attributes)
  */
 static void
-Display_Events_Info (Window window)
+Display_Events_Info (struct wininfo *w)
 {
-    XWindowAttributes win_attributes;
-
-    if (!XGetWindowAttributes (dpy, window, &win_attributes))
-	Fatal_Error ("Can't get window attributes.");
+    xcb_get_window_attributes_reply_t *win_attributes
+	= fetch_win_attributes (w);
 
     printf ("\n");
     printf ("  Someone wants these events:\n");
-    Display_Event_Mask (win_attributes.all_event_masks);
+    Display_Event_Mask (win_attributes->all_event_masks);
 
     printf ("  Do not propagate these events:\n");
-    Display_Event_Mask (win_attributes.do_not_propagate_mask);
+    Display_Event_Mask (win_attributes->do_not_propagate_mask);
 
     printf ("  Override redirection?: %s\n",
-	    Lookup (win_attributes.override_redirect, _bool));
+	    Lookup (win_attributes->override_redirect, _bool));
 }
 
 
@@ -851,39 +986,48 @@ Display_Events_Info (Window window)
 /*
  * Display root, parent, and (recursively) children information
  * recurse - true to show children information
+ *
+ * Requires wininfo members initialized: window, tree_cookie
  */
 static void
-Display_Tree_Info (Window window, int recurse)
+Display_Tree_Info (struct wininfo *w, int recurse)
 {
-    display_tree_info_1 (window, recurse, 0);
+    display_tree_info_1 (w, recurse, 0);
 }
 
 /*
  * level - recursion level
  */
 static void
-display_tree_info_1 (Window window, int recurse, int level)
+display_tree_info_1 (struct wininfo *w, int recurse, int level)
 {
     int i, j;
-    int rel_x, rel_y, abs_x, abs_y;
-    unsigned int width, height, border, depth;
-    Window root_win, parent_win;
     unsigned int num_children;
-    Window *child_list;
-    XClassHint classhint;
+    xcb_query_tree_reply_t *tree;
 
-    if (!XQueryTree (dpy, window, &root_win, &parent_win, &child_list,
-		     &num_children))
+    tree = xcb_query_tree_reply (dpy, w->tree_cookie, &err);
+    if (!tree) {
+	Print_X_Error (dpy, err);
 	Fatal_Error ("Can't query window tree.");
+    }
 
     if (level == 0) {
+	struct wininfo rw, pw;
+	rw.window = tree->root;
+	rw.wm_name_cookie = xcb_get_wm_name (dpy, rw.window);
+	pw.window = tree->parent;
+	pw.wm_name_cookie = xcb_get_wm_name (dpy, pw.window);
+	xcb_flush (dpy);
+
 	printf ("\n");
 	printf ("  Root window id: ");
-	Display_Window_Id (root_win, True);
+	Display_Window_Id (&rw, True);
 	printf ("  Parent window id: ");
-	Display_Window_Id (parent_win, True);
+	Display_Window_Id (&pw, True);
     }
 
+    num_children = xcb_query_tree_children_length (tree);
+
     if (level == 0  ||  num_children > 0) {
 	printf ("     ");
 	for (j = 0; j < level; j++) printf ("   ");
@@ -891,42 +1035,90 @@ display_tree_info_1 (Window window, int recurse, int level)
 		num_children ? ":" : ".");
     }
 
-    for (i = (int)num_children - 1; i >= 0; i--) {
-	printf ("     ");
-	for (j = 0; j < level; j++) printf ("   ");
-	Display_Window_Id (child_list[i], False);
-	printf (": (");
-	if (XGetClassHint (dpy, child_list[i], &classhint)) {
-	    if (classhint.res_name) {
-		printf ("\"%s\" ", classhint.res_name);
-		XFree (classhint.res_name);
-	    } else
-		printf ("(none) ");
-	    if (classhint.res_class) {
-		printf ("\"%s\") ", classhint.res_class);
-		XFree (classhint.res_class);
+    if (num_children > 0) {
+	xcb_window_t *child_list = xcb_query_tree_children (tree);
+	struct wininfo *children
+	    = calloc (num_children, sizeof(struct wininfo));
+
+	if (children == NULL)
+	    Fatal_Error ("Failed to allocate memory in display_tree_info");
+
+	for (i = (int)num_children - 1; i >= 0; i--) {
+	    struct wininfo *cw = &children[i];
+
+	    cw->window = child_list[i];
+	    cw->wm_name_cookie = xcb_get_wm_name (dpy, child_list[i]);
+	    cw->wm_class_cookie = xcb_get_wm_class (dpy, child_list[i]);
+	    cw->geometry_cookie = xcb_get_geometry (dpy, child_list[i]);
+	    cw->trans_coords_cookie = xcb_translate_coordinates
+		(dpy, child_list[i], tree->root, 0, 0);
+	    if (recurse)
+		cw->tree_cookie = xcb_query_tree (dpy, child_list[i]);
+	}
+	xcb_flush (dpy);
+
+	for (i = (int)num_children - 1; i >= 0; i--) {
+	    struct wininfo *cw = &children[i];
+	    xcb_get_wm_class_reply_t classhint;
+	    xcb_get_geometry_reply_t *geometry;
+
+	    printf ("     ");
+	    for (j = 0; j < level; j++) printf ("   ");
+	    Display_Window_Id (cw, False);
+	    printf (": (");
+
+	    if (xcb_get_wm_class_reply (dpy, cw->wm_class_cookie,
+					&classhint, NULL)) {
+		if (classhint.instance_name)
+		    printf ("\"%s\" ", classhint.instance_name);
+		else
+		    printf ("(none) ");
+
+		if (classhint.class_name)
+		    printf ("\"%s\") ", classhint.class_name);
+		else
+		    printf ("(none)) ");
+
+		xcb_get_wm_class_reply_wipe (&classhint);
 	    } else
-		printf ("(none)) ");
-	} else
-	    printf (") ");
-
-	if (XGetGeometry (dpy, child_list[i], &root_win,
-			  &rel_x, &rel_y, &width, &height, &border, &depth)) {
-	    Window child;
-
-	    printf (" %ux%u+%d+%d", width, height, rel_x, rel_y);
-	    if (XTranslateCoordinates (dpy, child_list[i], root_win,
-				       0 ,0, &abs_x, &abs_y, &child)) {
-		printf ("  +%d+%d", abs_x - border, abs_y - border);
+		printf (") ");
+
+	    geometry = xcb_get_geometry_reply(dpy, cw->geometry_cookie, &err);
+	    if (geometry) {
+		xcb_translate_coordinates_reply_t *trans_coords;
+
+		printf (" %ux%u+%d+%d", geometry->width, geometry->height,
+					geometry->x, geometry->y);
+
+		trans_coords = xcb_translate_coordinates_reply
+		    (dpy, cw->trans_coords_cookie, &err);
+
+		if (trans_coords) {
+		    int16_t abs_x = (int16_t) trans_coords->dst_x;
+		    int16_t abs_y = (int16_t) trans_coords->dst_y;
+		    int border = geometry->border_width;
+
+		    printf ("  +%d+%d", abs_x - border, abs_y - border);
+		    free (trans_coords);
+		} else if (err) {
+		    Print_X_Error (dpy, err);
+		}
+
+		free (geometry);
+	    } else if (err) {
+		Print_X_Error (dpy, err);
 	    }
-	}
-	printf ("\n");
+	    printf ("\n");
 
-	if (recurse)
-	    display_tree_info_1 (child_list[i], 1, level+1);
+	    if (recurse)
+		display_tree_info_1 (cw, 1, level+1);
+
+	    wininfo_wipe (cw);
+	}
+	free (children);
     }
 
-    if (child_list) XFree ((char *)child_list);
+    free (tree); /* includes storage for child_list[] */
 }
 
 
@@ -934,74 +1126,74 @@ display_tree_info_1 (Window window, int recurse, int level)
  * Display a set of size hints
  */
 static void
-Display_Hints (XSizeHints *hints)
+Display_Hints (xcb_size_hints_t *hints)
 {
     long flags;
 
     flags = hints->flags;
 
-    if (flags & USPosition)
+    if (flags & XCB_SIZE_HINT_US_POSITION)
 	printf ("      User supplied location: %s, %s\n",
 		xscale (hints->x), yscale (hints->y));
 
-    if (flags & PPosition)
+    if (flags & XCB_SIZE_HINT_P_POSITION)
 	printf ("      Program supplied location: %s, %s\n",
 		xscale (hints->x), yscale (hints->y));
 
-    if (flags & USSize) {
+    if (flags & XCB_SIZE_HINT_US_SIZE) {
 	printf ("      User supplied size: %s by %s\n",
 		xscale (hints->width), yscale (hints->height));
     }
 
-    if (flags & PSize)
+    if (flags & XCB_SIZE_HINT_P_SIZE)
 	printf ("      Program supplied size: %s by %s\n",
 		xscale (hints->width), yscale (hints->height));
 
-    if (flags & PMinSize)
+    if (flags & XCB_SIZE_HINT_P_MIN_SIZE)
 	printf ("      Program supplied minimum size: %s by %s\n",
 		xscale (hints->min_width), yscale (hints->min_height));
 
-    if (flags & PMaxSize)
+    if (flags & XCB_SIZE_HINT_P_MAX_SIZE)
 	printf ("      Program supplied maximum size: %s by %s\n",
 		xscale (hints->max_width), yscale (hints->max_height));
 
-    if (flags & PBaseSize) {
+    if (flags & XCB_SIZE_HINT_BASE_SIZE) {
 	printf ("      Program supplied base size: %s by %s\n",
 		xscale (hints->base_width), yscale (hints->base_height));
     }
 
-    if (flags & PResizeInc) {
+    if (flags & XCB_SIZE_HINT_P_RESIZE_INC) {
 	printf ("      Program supplied x resize increment: %s\n",
 		xscale (hints->width_inc));
 	printf ("      Program supplied y resize increment: %s\n",
 		yscale (hints->height_inc));
 	if (hints->width_inc != 0 && hints->height_inc != 0) {
-	    if (flags & USSize)
+	    if (flags & XCB_SIZE_HINT_US_SIZE)
 		printf ("      User supplied size in resize increments:  %s by %s\n",
 			(xscale (hints->width / hints->width_inc)),
 			(yscale (hints->height / hints->height_inc)));
-	    if (flags & PSize)
+	    if (flags & XCB_SIZE_HINT_P_SIZE)
 		printf ("      Program supplied size in resize increments:  %s by %s\n",
 			(xscale (hints->width / hints->width_inc)),
 			(yscale (hints->height / hints->height_inc)));
-	    if (flags & PMinSize)
+	    if (flags & XCB_SIZE_HINT_P_MIN_SIZE)
 		printf ("      Program supplied minimum size in resize increments: %s by %s\n",
 			xscale (hints->min_width / hints->width_inc), yscale (hints->min_height / hints->height_inc));
-	    if (flags & PBaseSize)
+	    if (flags & XCB_SIZE_HINT_BASE_SIZE)
 		printf ("      Program supplied base size in resize increments:  %s by %s\n",
 			(xscale (hints->base_width / hints->width_inc)),
 			(yscale (hints->base_height / hints->height_inc)));
 	}
     }
 
-    if (flags & PAspect) {
+    if (flags & XCB_SIZE_HINT_P_ASPECT) {
 	printf ("      Program supplied min aspect ratio: %s/%s\n",
-		xscale (hints->min_aspect.x), yscale (hints->min_aspect.y));
+		xscale (hints->min_aspect_num), yscale (hints->min_aspect_den));
 	printf ("      Program supplied max aspect ratio: %s/%s\n",
-		xscale (hints->max_aspect.x), yscale (hints->max_aspect.y));
+		xscale (hints->max_aspect_num), yscale (hints->max_aspect_den));
     }
 
-    if (flags & PWinGravity) {
+    if (flags & XCB_SIZE_HINT_P_WIN_GRAVITY) {
 	printf ("      Program supplied window gravity: %s\n",
 		Lookup (hints->win_gravity, _gravities));
     }
@@ -1012,103 +1204,137 @@ Display_Hints (XSizeHints *hints)
  * Display Size Hints info
  */
 static void
-Display_Size_Hints (Window window)
+Display_Size_Hints (struct wininfo *w)
 {
-    XSizeHints *hints = XAllocSizeHints ();
-    long supplied;
+    xcb_size_hints_t hints;
 
     printf ("\n");
-    if (!XGetWMNormalHints (dpy, window, hints, &supplied))
+    if (!fetch_normal_hints (w, &hints))
 	printf ("  No normal window size hints defined\n");
     else {
 	printf ("  Normal window size hints:\n");
-	hints->flags &= supplied;
-	Display_Hints (hints);
+	Display_Hints (&hints);
     }
 
-    if (!XGetWMSizeHints (dpy, window, hints, &supplied, XA_WM_ZOOM_HINTS))
+    if (!xcb_get_wm_size_hints_reply (dpy, w->zoom_cookie, &hints, NULL))
 	printf ("  No zoom window size hints defined\n");
     else {
 	printf ("  Zoom window size hints:\n");
-	hints->flags &= supplied;
-	Display_Hints (hints);
+	Display_Hints (&hints);
     }
-    XFree ((char *)hints);
 }
 
 
 static void
-Display_Window_Shape (Window window)
+Display_Window_Shape (xcb_window_t window)
 {
-    Bool    ws, bs;
-    int	    xws, yws, xbs, ybs;
-    unsigned int wws, hws, wbs, hbs;
+    const xcb_query_extension_reply_t *shape_query;
+    xcb_shape_query_extents_cookie_t extents_cookie;
+    xcb_shape_query_extents_reply_t *extents;
 
-    if (!XShapeQueryExtension (dpy, &bs, &ws))
+    shape_query = xcb_get_extension_data (dpy, &xcb_shape_id);
+    if (!shape_query->present)
 	return;
 
     printf ("\n");
-    XShapeQueryExtents (dpy, window, &ws, &xws, &yws, &wws, &hws,
-				     &bs, &xbs, &ybs, &wbs, &hbs);
-    if (!ws)
+
+    extents_cookie = xcb_shape_query_extents (dpy, window);
+    extents = xcb_shape_query_extents_reply (dpy, extents_cookie, &err);
+
+    if (!extents) {
+	if (err)
+	    Print_X_Error (dpy, err);
+	else
+	{
+	    printf ("  No window shape defined\n");
+	    printf ("  No border shape defined\n");
+	}
+	return;
+    }
+
+    if (!extents->bounding_shaped)
 	printf ("  No window shape defined\n");
     else {
 	printf ("  Window shape extents:  %sx%s",
-		xscale (wws), yscale (hws));
-	printf ("+%s+%s\n", xscale (xws), yscale (yws));
+		xscale (extents->bounding_shape_extents_width),
+		yscale (extents->bounding_shape_extents_height));
+	printf ("+%s+%s\n",
+		xscale (extents->bounding_shape_extents_x),
+		yscale (extents->bounding_shape_extents_y));
     }
-    if (!bs)
+    if (!extents->clip_shaped)
 	printf ("  No border shape defined\n");
     else {
 	printf ("  Border shape extents:  %sx%s",
-		xscale (wbs), yscale (hbs));
-	printf ("+%s+%s\n", xscale (xbs), yscale (ybs));
+		xscale (extents->clip_shape_extents_width),
+		yscale (extents->clip_shape_extents_height));
+	printf ("+%s+%s\n",
+		xscale (extents->clip_shape_extents_x),
+		yscale (extents->clip_shape_extents_y));
     }
+
+    free (extents);
 }
 
 /*
  * Display Window Manager Info
+ *
+ * Requires wininfo members initialized:
+ *   window, hints_cookie
  */
 static const binding _state_hints[] = {
-	{ DontCareState, "Don't Care State" },
-	{ NormalState, "Normal State" },
-	{ ZoomState, "Zoomed State" },
-	{ IconicState, "Iconic State" },
-	{ InactiveState, "Inactive State" },
+	{ XCB_WM_STATE_WITHDRAWN, "Withdrawn State" },
+	{ XCB_WM_STATE_NORMAL, "Normal State" },
+	{ XCB_WM_STATE_ICONIC, "Iconic State" },
+/* xwininfo previously also reported the ZoomState & InactiveState,
+   but ICCCM declared those obsolete long ago */
 	{ 0, NULL } };
 
 static void
-Display_WM_Info (Window window)
+Display_WM_Info (struct wininfo *w)
 {
-    XWMHints *wmhints;
+    xcb_wm_hints_t wmhints;
     long flags;
 
-    wmhints = XGetWMHints (dpy, window);
     printf ("\n");
-    if (!wmhints) {
+    if (!xcb_get_wm_hints_reply(dpy, w->hints_cookie, &wmhints, &err))
+    {
 	printf ("  No window manager hints defined\n");
+	if (err)
+	    Print_X_Error (dpy, err);
 	return;
     }
-    flags = wmhints->flags;
+    flags = wmhints.flags;
 
     printf ("  Window manager hints:\n");
 
-    if (flags & InputHint)
+    if (flags & XCB_WM_HINT_INPUT)
 	printf ("      Client accepts input or input focus: %s\n",
-		Lookup (wmhints->input, _bool));
+		Lookup (wmhints.input, _bool));
+
+    if (flags & XCB_WM_HINT_ICON_WINDOW) {
+	struct wininfo iw;
+	iw.window = wmhints.icon_window;
+	iw.wm_name_cookie = xcb_get_wm_name (dpy, iw.window);
 
-    if (flags & IconWindowHint) {
 	printf ("      Icon window id: ");
-	Display_Window_Id (wmhints->icon_window, True);
+	Display_Window_Id (&iw, True);
     }
 
-    if (flags & IconPositionHint)
+    if (flags & XCB_WM_HINT_ICON_POSITION)
 	printf ("      Initial icon position: %s, %s\n",
-		xscale (wmhints->icon_x), yscale (wmhints->icon_y));
+		xscale (wmhints.icon_x), yscale (wmhints.icon_y));
 
-    if (flags & StateHint)
+    if (flags & XCB_WM_HINT_STATE)
 	printf ("      Initial state is %s\n",
-		Lookup (wmhints->initial_state, _state_hints));
+		Lookup (wmhints.initial_state, _state_hints));
+}
 
-    XFree (wmhints);
+/* Frees all members of a wininfo struct, but not the struct itself */
+static void
+wininfo_wipe (struct wininfo *w)
+{
+    free (w->geometry);
+    free (w->win_attributes);
+    free (w->normal_hints);
 }
-- 
1.5.6.5



More information about the xorg-devel mailing list