#include #include #include #include #include static Display *dpy; static GHashTable *atom_name_hash; static Atom XA_UTF8_STRING; /* TODO: have a version which takes an array of atoms */ static const char * atom_name (Atom atom) { char *name; name = g_hash_table_lookup (atom_name_hash, GINT_TO_POINTER (atom)); if (name) return name; name = XGetAtomName (dpy, atom); g_hash_table_insert (atom_name_hash, GINT_TO_POINTER (atom), name); return name; } static void dump_name (const char *indent, Window window) { char *name; XFetchName (dpy, window, &name); if (name) { printf ("%s%s\n", indent, name); XFree (name); } else { printf ("%s[unnamed]\n", indent); } } static void dump_size (const char *indent, Window window) { Window ignore; int x, y; unsigned int width, height, border, depth; XGetGeometry (dpy, window, &ignore, &x, &y, &width, &height, &border, &depth); printf ("%s%dx%d+%u+%u (border %u)\n", indent, width, height, x, y, border); } static void dump_properties (const char *indent, Window window) { Atom *atoms; int i, n_atoms; atoms = XListProperties (dpy, window, &n_atoms); if (n_atoms == 0) return; for (i = 0; i < n_atoms; i++) { Atom real_type; int real_format; unsigned long nitems, bytes_after; unsigned char *prop; XGetWindowProperty (dpy, window, atoms[i], 0, G_MAXLONG, False, AnyPropertyType, &real_type, &real_format, &nitems, &bytes_after, &prop); if (real_type == XA_STRING && real_format == 8) { /* TODO: convert to locale */ printf ("%sAtom STRING %s \"%s\"\n", indent, atom_name (atoms[i]), prop); XFree (prop); } else if (real_type == XA_UTF8_STRING && real_format == 8) { if (g_utf8_validate ((char*)prop, -1, NULL)) { printf ("%sAtom UTF-8 %s \"%s\"\n", indent, atom_name (atoms[i]), prop); } else { /* TODO: dump bytes */ printf ("%sAtom UTF-8 %s (invalid UTF-8)\n", indent, atom_name (atoms[i])); } XFree (prop); } else if (real_type == XA_CARDINAL) { unsigned int j, *cardinals; printf ("%sAtom %s %d\n", indent, atom_name (atoms[i]), real_format); if (real_format == 32) { cardinals = (unsigned int *)prop; for (j = 0; j < nitems; j++) { printf ("%s%u\n", indent, cardinals[j]); } } XFree (prop); } else { printf ("%sAtom %s [%s]\n", indent, atom_name (atoms[i]), atom_name (real_type)); } } XFree (atoms); } static void examine (Window window, int indent_size) { char *indent; Window *children, ignore; unsigned int i, n_children; indent = g_strnfill (indent_size, ' '); dump_name (indent, window); dump_size (indent, window); dump_properties (indent, window); XQueryTree (dpy, window, &ignore, &ignore, &children, &n_children); printf ("%s%d children\n", indent, n_children); for (i = 0; i < n_children; i++) { examine (children[i], indent_size + 1); } XFree (children); free (indent); } int main (int argc, char **argv) { dpy = XOpenDisplay (NULL); if (!dpy) return EXIT_FAILURE; /* TODO: handle many screens somehow */ XA_UTF8_STRING = XInternAtom (dpy, "UTF8_STRING", False); atom_name_hash = g_hash_table_new (NULL, NULL); examine (DefaultRootWindow (dpy), 0); return EXIT_SUCCESS; }