ウィンドウを列挙する
WMのデバッグ用に、存在するウィンドウを列挙しつつ属性を確認できるとうれしいので簡単なツールを書いた。
行番号表示/非表示切替
1 #include <stdio.h>
2 #include <string.h>
3 #include <locale.h>
4 #include <X11/Xlib.h>
5 #include <X11/Xutil.h>
6 #include <X11/Xatom.h>
7
8 Display *dpy;
9 Window root;
10
11 Atom net_wm_name;
12
13 #define BUFSIZE 256
14 char buf[BUFSIZE];
15
16 #define MIN(a, b) ((a) < (b) ? (a) : (b))
17
18 #define OPT_GEOM 1
19 #define OPT_CLASS 2
20 #define OPT_OVERRIDE_REDIRECT 4
21 #define OPT_TRANSIENT_FOR 8
22 #define OPT_MAP_STATE 16
23
24 unsigned int opt = OPT_GEOM | OPT_CLASS | OPT_OVERRIDE_REDIRECT | OPT_TRANSIENT_FOR | OPT_MAP_STATE;
25
26 void get_window_title(Window w, char *title, int size)
27 {
28 XTextProperty prop;
29
30 /* try to get _NET_WM_NAME */
31 XGetTextProperty(dpy, w, &prop, net_wm_name);
32 if (prop.nitems == 0) {
33 /* fall back to WM_NAME */
34 XGetWMName(dpy, w, &prop);
35 }
36
37 title[0] = '\0';
38 if (prop.nitems > 0 && prop.value) {
39 if (prop.encoding == XA_STRING) {
40 strncpy(title, (char *)prop.value, MIN(BUFSIZE - 1, size - 1));
41 } else {
42 char **l = NULL;
43 int count;
44 XmbTextPropertyToTextList(dpy, &prop, &l, &count);
45 if (count > 0 && *l)
46 strncpy(title, *l, MIN(BUFSIZE - 1, size - 1));
47 XFreeStringList(l);
48 }
49 title[size - 1] = '\0';
50 }
51 }
52
53 #define indent(l) for (i = 0; i < (l); ++i) putchar('\t')
54 void traverse(Window w, unsigned int level, unsigned int max_level)
55 {
56 Window r, parent, *children;
57 unsigned int nchildren, i;
58 XWindowAttributes wa;
59
60 if (max_level != 0 && level > max_level)
61 return;
62
63 get_window_title(w, buf, BUFSIZE);
64 if (buf[0] == '\0')
65 strcpy(buf, "<no title>");
66 XGetWindowAttributes(dpy, w, &wa);
67
68 if (level > 0)
69 putchar('\n');
70 indent(level);
71 printf("0x%06x \"%s\"\n", w, buf);
72 if (opt & OPT_GEOM) {
73 indent(level + 1);
74 printf("geometry: %dx%d+%d+%d\n", wa.width, wa.height, wa.x, wa.y);
75 }
76 if (opt & OPT_CLASS) {
77 indent(level + 1);
78 printf("class: %s\n", wa.class == InputOutput ? "InputOutput" : "InputOnly");
79 }
80 if (opt & OPT_OVERRIDE_REDIRECT) {
81 if (wa.override_redirect) {
82 indent(level + 1);
83 puts("override_redirect");
84 }
85 }
86 if (opt & OPT_TRANSIENT_FOR) {
87 Window trans;
88 XGetTransientForHint(dpy, w, &trans);
89 if (trans != 0) {
90 indent(level + 1);
91 printf("WM_TRANSIENT_FOR: 0x%06x\n", trans);
92 }
93 }
94 if (opt & OPT_MAP_STATE) {
95 indent(level + 1);
96 printf("state: ");
97 switch (wa.map_state) {
98 case IsUnmapped: puts("Unmapped"); break;
99 case IsUnviewable: puts("Unviewable"); break;
100 case IsViewable: puts("Viewable"); break;
101 }
102 }
103
104 XQueryTree(dpy, w, &r, &parent, &children, &nchildren);
105 if (nchildren > 0) {
106 for (i = 0; i < nchildren; ++i)
107 traverse(children[i], level + 1, max_level);
108 XFree(children);
109 }
110 }
111
112 int main(int argc, char **argv)
113 {
114 if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
115 fputs("warning: no locale support\n", stderr);
116
117 dpy = XOpenDisplay(argc > 1 ? argv[1] : NULL);
118 if (!dpy) {
119 fputs("failed to open display\n", stderr);
120 return 1;
121 }
122 net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False);
123 root = RootWindow(dpy, DefaultScreen(dpy));
124 traverse(root, 0, 0);
125 XCloseDisplay(dpy);
126 return 0;
127 }