2 #include <X11/cursorfont.h>
9 gint fail(const gchar *s) {
11 fprintf(stderr, "%s\n", s);
15 "Usage: obxprop [OPTIONS] [--] [PROPERTIES ...]\n\n"
17 " --help Display this help and exit\n"
18 " --display DISPLAY Connect to this X display\n"
19 " --id ID Show the properties for this window\n"
20 " --root Show the properties for the root window\n");
24 gint parse_hex(gchar *s) {
28 if (*s >= '0' && *s <='9')
30 else if (*s >= 'A' && *s <='F')
32 else if (*s >= 'a' && *s <='f')
44 Window find_client(Display *d, Window win)
48 Atom state = XInternAtom(d, "WM_STATE", True);
51 gulong ret_items, ret_bytesleft, *xdata;
53 XQueryTree(d, win, &r, &r, &children, &n);
54 for (i = 0; i < n; ++i) {
55 Window w = find_client(d, children[i]);
60 res = XGetWindowProperty(d, win, state, 0, 1,
61 False, state, &ret_type, &ret_format,
62 &ret_items, &ret_bytesleft,
63 (unsigned char**) &xdata);
65 if (res != Success || ret_type == None || ret_items < 1)
67 return win; // found it!
70 static gboolean get_all(Display *d, Window win, Atom prop,
71 Atom *type, gint *size,
72 guchar **data, guint *num)
77 gulong ret_items, bytes_left;
79 res = XGetWindowProperty(d, win, prop, 0l, G_MAXLONG,
80 FALSE, AnyPropertyType, type, size,
81 &ret_items, &bytes_left, &xdata);
86 *data = g_malloc(ret_items * (*size / 8));
87 for (i = 0; i < ret_items; ++i)
90 (*data)[i] = xdata[i];
93 ((guint16*)*data)[i] = ((gushort*)xdata)[i];
96 ((guint32*)*data)[i] = ((gulong*)xdata)[i];
99 g_assert_not_reached(); /* unhandled size */
109 GString *append_string(GString *before, gchar *after, gboolean quote)
111 const gchar *q = quote ? "\"" : "";
113 g_string_append_printf(before, ", %s%s%s", q, after, q);
115 g_string_append_printf(before = g_string_new(NULL), "%s%s%s", q, after, q);
119 GString *append_int(GString *before, guint after)
122 g_string_append_printf(before, ", %u", after);
124 g_string_append_printf(before = g_string_new(NULL), "%u", after);
128 gchar* read_strings(gchar *val, guint n, gboolean utf8)
130 GSList *strs = NULL, *it;
136 while (p < val + n) {
137 strs = g_slist_append(strs, g_strndup(p, n - (p - val)));
138 p += strlen(p) + 1; /* next string */
142 for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
146 if (g_utf8_validate(it->data, -1, NULL))
147 data = g_strdup(it->data);
152 data = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
154 ret = append_string(ret, data, TRUE);
160 strs = g_slist_delete_link(strs, strs);
163 return g_string_free(ret, FALSE);
167 gchar* read_atoms(Display *d, guchar *val, guint n)
173 for (i = 0; i < n; ++i)
174 ret = append_string(ret, XGetAtomName(d, ((guint32*)val)[i]), FALSE);
176 return g_string_free(ret, FALSE);
180 gchar* read_numbers(guchar *val, guint n, guint size)
186 for (i = 0; i < n; ++i)
189 ret = append_int(ret, ((guint8*)val)[i]);
192 ret = append_int(ret, ((guint16*)val)[i]);
195 ret = append_int(ret, ((guint32*)val)[i]);
198 g_assert_not_reached(); /* unhandled size */
202 return g_string_free(ret, FALSE);
206 gboolean read_prop(Display *d, Window w, Atom prop, const gchar **type, gchar **val)
214 if (get_all(d, w, prop, &ret_type, &size, &ret, &nret)) {
215 *type = XGetAtomName(d, ret_type);
217 if (strcmp(*type, "STRING") == 0)
218 *val = read_strings((gchar*)ret, nret, FALSE);
219 else if (strcmp(*type, "UTF8_STRING") == 0)
220 *val = read_strings((gchar*)ret, nret, TRUE);
221 else if (strcmp(*type, "ATOM") == 0) {
222 g_assert(size == 32);
223 *val = read_atoms(d, ret, nret);
226 *val = read_numbers(ret, nret, size);
234 void show_properties(Display *d, Window w, int argc, char **argv)
239 props = XListProperties(d, w, &n);
241 for (i = 0; i < n; ++i) {
245 name = XGetAtomName(d, props[i]);
247 if (read_prop(d, w, props[i], &type, &val)) {
253 for (i = 0; i < argc; i++)
254 if (!strcmp(name, argv[i])) {
260 g_print("%s(%s) = %s\n", name, type, (val ? val : ""));
270 int main(int argc, char **argv)
273 Window id, userid = None;
276 gboolean root = FALSE;
278 for (i = 1; i < argc; ++i) {
279 if (!strcmp(argv[i], "--help")) {
282 else if (!strcmp(argv[i], "--root"))
284 else if (!strcmp(argv[i], "--id")) {
287 if (argv[i][0] == '0' && argv[i][1] == 'x') {
289 userid = parse_hex(argv[i]+2);
293 userid = atoi(argv[i]);
296 return fail("Unable to parse argument to --id.");
298 else if (!strcmp(argv[i], "--display")) {
303 else if (*argv[i] != '-')
305 else if (!strcmp(argv[i], "--")) {
313 d = XOpenDisplay(dname);
315 return fail("Unable to find an X display. "
316 "Ensure you have permission to connect to the display.");
320 userid = RootWindow(d, DefaultScreen(d));
322 if (userid == None) {
324 j = XGrabPointer(d, RootWindow(d, DefaultScreen(d)),
325 False, ButtonPressMask,
326 GrabModeAsync, GrabModeAsync,
327 None, XCreateFontCursor(d, XC_crosshair),
329 if (j != GrabSuccess)
330 return fail("Unable to grab the pointer device");
335 if (ev.type == ButtonPress) {
336 XUngrabPointer(d, CurrentTime);
337 userid = ev.xbutton.subwindow;
341 id = find_client(d, userid);
344 id = userid; /* they picked this one */
347 return fail("Unable to find window with the requested ID");
349 show_properties(d, id, argc - i, &argv[i]);