]> Dogcows Code - chaz/openbox/blob - tools/obxprop/obxprop.c
3.5.1 changelog
[chaz/openbox] / tools / obxprop / obxprop.c
1 #include <X11/Xlib.h>
2 #include <X11/cursorfont.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <assert.h>
7 #include <glib.h>
8
9 gint fail(const gchar *s) {
10 if (s)
11 fprintf(stderr, "%s\n", s);
12 else
13 fprintf
14 (stderr,
15 "Usage: obxprop [OPTIONS] [--] [PROPERTIES ...]\n\n"
16 "Options:\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");
21 return 1;
22 }
23
24 gint parse_hex(gchar *s) {
25 gint result = 0;
26 while (*s) {
27 gint add;
28 if (*s >= '0' && *s <='9')
29 add = *s-'0';
30 else if (*s >= 'A' && *s <='F')
31 add = *s-'A'+10;
32 else if (*s >= 'a' && *s <='f')
33 add = *s-'a'+10;
34 else
35 break;
36
37 result *= 16;
38 result += add;
39 ++s;
40 }
41 return result;
42 }
43
44 Window find_client(Display *d, Window win)
45 {
46 Window r, *children;
47 guint n, i;
48 Atom state = XInternAtom(d, "WM_STATE", True);
49 Atom ret_type;
50 gint ret_format, res;
51 gulong ret_items, ret_bytesleft, *xdata;
52
53 XQueryTree(d, win, &r, &r, &children, &n);
54 for (i = 0; i < n; ++i) {
55 Window w = find_client(d, children[i]);
56 if (w) return w;
57 }
58
59 // try me
60 res = XGetWindowProperty(d, win, state, 0, 1,
61 False, state, &ret_type, &ret_format,
62 &ret_items, &ret_bytesleft,
63 (unsigned char**) &xdata);
64 XFree(xdata);
65 if (res != Success || ret_type == None || ret_items < 1)
66 return None;
67 return win; // found it!
68 }
69
70 static gboolean get_all(Display *d, Window win, Atom prop,
71 Atom *type, gint *size,
72 guchar **data, guint *num)
73 {
74 gboolean ret = FALSE;
75 gint res;
76 guchar *xdata = NULL;
77 gulong ret_items, bytes_left;
78
79 res = XGetWindowProperty(d, win, prop, 0l, G_MAXLONG,
80 FALSE, AnyPropertyType, type, size,
81 &ret_items, &bytes_left, &xdata);
82 if (res == Success) {
83 if (ret_items > 0) {
84 guint i;
85
86 *data = g_malloc(ret_items * (*size / 8));
87 for (i = 0; i < ret_items; ++i)
88 switch (*size) {
89 case 8:
90 (*data)[i] = xdata[i];
91 break;
92 case 16:
93 ((guint16*)*data)[i] = ((gushort*)xdata)[i];
94 break;
95 case 32:
96 ((guint32*)*data)[i] = ((gulong*)xdata)[i];
97 break;
98 default:
99 g_assert_not_reached(); /* unhandled size */
100 }
101 }
102 *num = ret_items;
103 ret = TRUE;
104 XFree(xdata);
105 }
106 return ret;
107 }
108
109 gchar *append_string(gchar *before, gchar *after, gboolean quote)
110 {
111 gchar *tmp;
112 const gchar *q = quote ? "\"" : "";
113 if (before)
114 tmp = g_strdup_printf("%s, %s%s%s", before, q, after, q);
115 else
116 tmp = g_strdup_printf("%s%s%s", q, after, q);
117 g_free(before);
118 return tmp;
119 }
120
121 gchar *append_int(gchar *before, guint after)
122 {
123 gchar *tmp;
124 if (before)
125 tmp = g_strdup_printf("%s, %u", before, after);
126 else
127 tmp = g_strdup_printf("%u", after);
128 g_free(before);
129 return tmp;
130 }
131
132 gchar* read_strings(gchar *val, guint n, gboolean utf8)
133 {
134 GSList *strs = NULL, *it;
135 gchar *ret, *p;
136 guint i;
137
138 p = val;
139 while (p < val + n) {
140 strs = g_slist_append(strs, g_strndup(p, n - (p - val)));
141 p += strlen(p) + 1; /* next string */
142 }
143
144 ret = NULL;
145 for (i = 0, it = strs; it; ++i, it = g_slist_next(it)) {
146 char *data;
147
148 if (utf8) {
149 if (g_utf8_validate(it->data, -1, NULL))
150 data = g_strdup(it->data);
151 else
152 data = g_strdup("");
153 }
154 else
155 data = g_locale_to_utf8(it->data, -1, NULL, NULL, NULL);
156
157 ret = append_string(ret, data, TRUE);
158 g_free(data);
159 }
160
161 while (strs) {
162 g_free(strs->data);
163 strs = g_slist_delete_link(strs, strs);
164 }
165 return ret;
166 }
167
168 gchar* read_atoms(Display *d, guchar *val, guint n)
169 {
170 gchar *ret;
171 guint i;
172
173 ret = NULL;
174 for (i = 0; i < n; ++i)
175 ret = append_string(ret, XGetAtomName(d, ((guint32*)val)[i]), FALSE);
176 return ret;
177 }
178
179 gchar* read_numbers(guchar *val, guint n, guint size)
180 {
181 gchar *ret;
182 guint i;
183
184 ret = NULL;
185 for (i = 0; i < n; ++i)
186 switch (size) {
187 case 8:
188 ret = append_int(ret, ((guint8*)val)[i]);
189 break;
190 case 16:
191 ret = append_int(ret, ((guint16*)val)[i]);
192 break;
193 case 32:
194 ret = append_int(ret, ((guint32*)val)[i]);
195 break;
196 default:
197 g_assert_not_reached(); /* unhandled size */
198 }
199
200 return ret;
201 }
202
203 gboolean read_prop(Display *d, Window w, Atom prop, const gchar **type, gchar **val)
204 {
205 guchar *ret;
206 guint nret;
207 gint size;
208 Atom ret_type;
209
210 ret = NULL;
211 if (get_all(d, w, prop, &ret_type, &size, &ret, &nret)) {
212 *type = XGetAtomName(d, ret_type);
213
214 if (strcmp(*type, "STRING") == 0)
215 *val = read_strings((gchar*)ret, nret, FALSE);
216 else if (strcmp(*type, "UTF8_STRING") == 0)
217 *val = read_strings((gchar*)ret, nret, TRUE);
218 else if (strcmp(*type, "ATOM") == 0) {
219 g_assert(size == 32);
220 *val = read_atoms(d, ret, nret);
221 }
222 else
223 *val = read_numbers(ret, nret, size);
224
225 g_free(ret);
226 return TRUE;
227 }
228 return FALSE;
229 }
230
231 void show_properties(Display *d, Window w, int argc, char **argv)
232 {
233 Atom* props;
234 int i, n;
235
236 props = XListProperties(d, w, &n);
237
238 for (i = 0; i < n; ++i) {
239 const char *type;
240 char *name, *val;
241
242 name = XGetAtomName(d, props[i]);
243
244 if (read_prop(d, w, props[i], &type, &val)) {
245 int found = 1;
246 if (argc) {
247 int i;
248
249 found = 0;
250 for (i = 0; i < argc; i++)
251 if (!strcmp(name, argv[i])) {
252 found = 1;
253 break;
254 }
255 }
256 if (found)
257 g_print("%s(%s) = %s\n", name, type, (val ? val : ""));
258 g_free(val);
259 }
260
261 XFree(name);
262 }
263
264 XFree(props);
265 }
266
267 int main(int argc, char **argv)
268 {
269 Display *d;
270 Window id, userid = None;
271 int i;
272 char *dname = NULL;
273 gboolean root = FALSE;
274
275 for (i = 1; i < argc; ++i) {
276 if (!strcmp(argv[i], "--help")) {
277 return fail(NULL);
278 }
279 else if (!strcmp(argv[i], "--root"))
280 root = TRUE;
281 else if (!strcmp(argv[i], "--id")) {
282 if (++i == argc)
283 return fail(NULL);
284 if (argv[i][0] == '0' && argv[i][1] == 'x') {
285 /* hex */
286 userid = parse_hex(argv[i]+2);
287 }
288 else {
289 /* decimal */
290 userid = atoi(argv[i]);
291 }
292 if (!userid)
293 return fail("Unable to parse argument to --id.");
294 }
295 else if (!strcmp(argv[i], "--display")) {
296 if (++i == argc)
297 return fail(NULL);
298 dname = argv[i];
299 }
300 else if (*argv[i] != '-')
301 break;
302 else if (!strcmp(argv[i], "--")) {
303 i++;
304 break;
305 }
306 else
307 return fail(NULL);
308 }
309
310 d = XOpenDisplay(dname);
311 if (!d) {
312 return fail("Unable to find an X display. "
313 "Ensure you have permission to connect to the display.");
314 }
315
316 if (root)
317 userid = RootWindow(d, DefaultScreen(d));
318
319 if (userid == None) {
320 int j;
321 j = XGrabPointer(d, RootWindow(d, DefaultScreen(d)),
322 False, ButtonPressMask,
323 GrabModeAsync, GrabModeAsync,
324 None, XCreateFontCursor(d, XC_crosshair),
325 CurrentTime);
326 if (j != GrabSuccess)
327 return fail("Unable to grab the pointer device");
328 while (1) {
329 XEvent ev;
330
331 XNextEvent(d, &ev);
332 if (ev.type == ButtonPress) {
333 XUngrabPointer(d, CurrentTime);
334 userid = ev.xbutton.subwindow;
335 break;
336 }
337 }
338 id = find_client(d, userid);
339 }
340 else
341 id = userid; /* they picked this one */
342
343 if (id == None)
344 return fail("Unable to find window with the requested ID");
345
346 show_properties(d, id, argc - i, &argv[i]);
347
348 XCloseDisplay(d);
349
350 return 0;
351 }
This page took 0.047812 seconds and 4 git commands to generate.