Blame


1 6510a2d3 2020-01-15 crossd /*
2 6510a2d3 2020-01-15 crossd * slightly modified from
3 6510a2d3 2020-01-15 crossd * https://github.com/fhs/misc/blob/master/cmd/winwatch/winwatch.c
4 6510a2d3 2020-01-15 crossd * so as to deal with memory leaks and certain X errors
5 6510a2d3 2020-01-15 crossd */
6 a9b46206 2020-01-15 crossd
7 a9b46206 2020-01-15 crossd #include <u.h>
8 a9b46206 2020-01-15 crossd #include <libc.h>
9 a9b46206 2020-01-15 crossd #include <draw.h>
10 a9b46206 2020-01-15 crossd #include <event.h>
11 a9b46206 2020-01-15 crossd #include <regexp.h>
12 6510a2d3 2020-01-15 crossd #include <fmt.h>
13 a9b46206 2020-01-15 crossd #include "../devdraw/x11-inc.h"
14 a9b46206 2020-01-15 crossd
15 a9b46206 2020-01-15 crossd AUTOLIB(X11);
16 a9b46206 2020-01-15 crossd
17 a9b46206 2020-01-15 crossd typedef struct Win Win;
18 a9b46206 2020-01-15 crossd struct Win {
19 6510a2d3 2020-01-15 crossd XWindow n;
20 6510a2d3 2020-01-15 crossd int dirty;
21 6510a2d3 2020-01-15 crossd char *label;
22 6510a2d3 2020-01-15 crossd Rectangle r;
23 a9b46206 2020-01-15 crossd };
24 a9b46206 2020-01-15 crossd
25 a9b46206 2020-01-15 crossd XDisplay *dpy;
26 a9b46206 2020-01-15 crossd XWindow root;
27 a9b46206 2020-01-15 crossd Atom net_active_window;
28 a9b46206 2020-01-15 crossd Reprog *exclude = nil;
29 a9b46206 2020-01-15 crossd Win *win;
30 a9b46206 2020-01-15 crossd int nwin;
31 a9b46206 2020-01-15 crossd int mwin;
32 a9b46206 2020-01-15 crossd int onwin;
33 a9b46206 2020-01-15 crossd int rows, cols;
34 a9b46206 2020-01-15 crossd int sortlabels;
35 a9b46206 2020-01-15 crossd int showwmnames;
36 a9b46206 2020-01-15 crossd Font *font;
37 a9b46206 2020-01-15 crossd Image *lightblue;
38 a9b46206 2020-01-15 crossd
39 a9b46206 2020-01-15 crossd XErrorHandler oldxerrorhandler;
40 a9b46206 2020-01-15 crossd
41 a9b46206 2020-01-15 crossd enum {
42 6510a2d3 2020-01-15 crossd PAD = 3,
43 6510a2d3 2020-01-15 crossd MARGIN = 5
44 a9b46206 2020-01-15 crossd };
45 a9b46206 2020-01-15 crossd
46 a9b46206 2020-01-15 crossd static jmp_buf savebuf;
47 a9b46206 2020-01-15 crossd
48 6510a2d3 2020-01-15 crossd int
49 a9b46206 2020-01-15 crossd winwatchxerrorhandler(XDisplay *disp, XErrorEvent *xe)
50 a9b46206 2020-01-15 crossd {
51 6510a2d3 2020-01-15 crossd char buf[100];
52 a9b46206 2020-01-15 crossd
53 6510a2d3 2020-01-15 crossd XGetErrorText(disp, xe->error_code, buf, 100);
54 6510a2d3 2020-01-15 crossd fprint(2, "winwatch: X error %s, request code %d\n",
55 6510a2d3 2020-01-15 crossd buf, xe->request_code);
56 6510a2d3 2020-01-15 crossd XFlush(disp);
57 6510a2d3 2020-01-15 crossd XSync(disp, False);
58 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
59 6510a2d3 2020-01-15 crossd longjmp(savebuf, 1);
60 6510a2d3 2020-01-15 crossd return(0); /* Not reached */
61 a9b46206 2020-01-15 crossd }
62 a9b46206 2020-01-15 crossd
63 a9b46206 2020-01-15 crossd void*
64 a9b46206 2020-01-15 crossd erealloc(void *v, ulong n)
65 a9b46206 2020-01-15 crossd {
66 6510a2d3 2020-01-15 crossd v = realloc(v, n);
67 6510a2d3 2020-01-15 crossd if(v==nil)
68 6510a2d3 2020-01-15 crossd sysfatal("out of memory reallocating");
69 6510a2d3 2020-01-15 crossd return v;
70 a9b46206 2020-01-15 crossd }
71 a9b46206 2020-01-15 crossd
72 a9b46206 2020-01-15 crossd char*
73 a9b46206 2020-01-15 crossd estrdup(char *s)
74 a9b46206 2020-01-15 crossd {
75 6510a2d3 2020-01-15 crossd s = strdup(s);
76 6510a2d3 2020-01-15 crossd if(s==nil)
77 6510a2d3 2020-01-15 crossd sysfatal("out of memory allocating");
78 6510a2d3 2020-01-15 crossd return(s);
79 a9b46206 2020-01-15 crossd }
80 a9b46206 2020-01-15 crossd
81 a9b46206 2020-01-15 crossd char*
82 a9b46206 2020-01-15 crossd getproperty(XWindow w, Atom a)
83 a9b46206 2020-01-15 crossd {
84 6510a2d3 2020-01-15 crossd uchar *p;
85 6510a2d3 2020-01-15 crossd int fmt;
86 6510a2d3 2020-01-15 crossd Atom type;
87 6510a2d3 2020-01-15 crossd ulong n, dummy;
88 6510a2d3 2020-01-15 crossd int s;
89 a9b46206 2020-01-15 crossd
90 6510a2d3 2020-01-15 crossd n = 100;
91 6510a2d3 2020-01-15 crossd p = nil;
92 6510a2d3 2020-01-15 crossd oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
93 6510a2d3 2020-01-15 crossd s = XGetWindowProperty(dpy, w, a, 0, 100L, 0,
94 6510a2d3 2020-01-15 crossd AnyPropertyType, &type, &fmt, &n, &dummy, &p);
95 6510a2d3 2020-01-15 crossd XFlush(dpy);
96 6510a2d3 2020-01-15 crossd XSync(dpy, False);
97 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
98 6510a2d3 2020-01-15 crossd if(s!=0){
99 6510a2d3 2020-01-15 crossd XFree(p);
100 6510a2d3 2020-01-15 crossd return(nil);
101 6510a2d3 2020-01-15 crossd }
102 a9b46206 2020-01-15 crossd
103 6510a2d3 2020-01-15 crossd return((char*)p);
104 a9b46206 2020-01-15 crossd }
105 a9b46206 2020-01-15 crossd
106 6510a2d3 2020-01-15 crossd XWindow
107 a9b46206 2020-01-15 crossd findname(XWindow w)
108 a9b46206 2020-01-15 crossd {
109 6510a2d3 2020-01-15 crossd int i;
110 6510a2d3 2020-01-15 crossd uint nxwin;
111 6510a2d3 2020-01-15 crossd XWindow dw1, dw2, *xwin;
112 6510a2d3 2020-01-15 crossd char *p;
113 6510a2d3 2020-01-15 crossd int s;
114 6510a2d3 2020-01-15 crossd Atom net_wm_name;
115 a9b46206 2020-01-15 crossd
116 6510a2d3 2020-01-15 crossd p = getproperty(w, XA_WM_NAME);
117 6510a2d3 2020-01-15 crossd if(p){
118 6510a2d3 2020-01-15 crossd free(p);
119 6510a2d3 2020-01-15 crossd return(w);
120 6510a2d3 2020-01-15 crossd }
121 a9b46206 2020-01-15 crossd
122 6510a2d3 2020-01-15 crossd net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", FALSE);
123 6510a2d3 2020-01-15 crossd p = getproperty(w, net_wm_name);
124 6510a2d3 2020-01-15 crossd if(p){
125 6510a2d3 2020-01-15 crossd free(p);
126 6510a2d3 2020-01-15 crossd return(w);
127 6510a2d3 2020-01-15 crossd }
128 a9b46206 2020-01-15 crossd
129 6510a2d3 2020-01-15 crossd oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
130 6510a2d3 2020-01-15 crossd s = XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin);
131 6510a2d3 2020-01-15 crossd XFlush(dpy);
132 6510a2d3 2020-01-15 crossd XSync(dpy, False);
133 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
134 6510a2d3 2020-01-15 crossd if(s == 0) {
135 6510a2d3 2020-01-15 crossd if (xwin != NULL)
136 6510a2d3 2020-01-15 crossd XFree(xwin);
137 6510a2d3 2020-01-15 crossd return 0;
138 6510a2d3 2020-01-15 crossd }
139 a9b46206 2020-01-15 crossd
140 6510a2d3 2020-01-15 crossd for (i = 0; i < nxwin; i++) {
141 6510a2d3 2020-01-15 crossd w = findname(xwin[i]);
142 6510a2d3 2020-01-15 crossd if (w != 0) {
143 6510a2d3 2020-01-15 crossd XFree(xwin);
144 6510a2d3 2020-01-15 crossd return w;
145 6510a2d3 2020-01-15 crossd }
146 6510a2d3 2020-01-15 crossd }
147 6510a2d3 2020-01-15 crossd XFree(xwin);
148 a9b46206 2020-01-15 crossd
149 6510a2d3 2020-01-15 crossd return 0;
150 a9b46206 2020-01-15 crossd }
151 a9b46206 2020-01-15 crossd
152 6510a2d3 2020-01-15 crossd int
153 a9b46206 2020-01-15 crossd wcmp(const void *w1, const void *w2)
154 a9b46206 2020-01-15 crossd {
155 6510a2d3 2020-01-15 crossd return *(XWindow *) w1 - *(XWindow *) w2;
156 a9b46206 2020-01-15 crossd }
157 a9b46206 2020-01-15 crossd
158 a9b46206 2020-01-15 crossd /* unicode-aware case-insensitive strcmp, taken from golang’s gc/subr.c */
159 a9b46206 2020-01-15 crossd
160 6510a2d3 2020-01-15 crossd int
161 a9b46206 2020-01-15 crossd _cistrcmp(char *p, char *q)
162 a9b46206 2020-01-15 crossd {
163 6510a2d3 2020-01-15 crossd Rune rp, rq;
164 a9b46206 2020-01-15 crossd
165 6510a2d3 2020-01-15 crossd while(*p || *q) {
166 6510a2d3 2020-01-15 crossd if(*p == 0)
167 6510a2d3 2020-01-15 crossd return +1;
168 6510a2d3 2020-01-15 crossd if(*q == 0)
169 6510a2d3 2020-01-15 crossd return -1;
170 6510a2d3 2020-01-15 crossd p += chartorune(&rp, p);
171 6510a2d3 2020-01-15 crossd q += chartorune(&rq, q);
172 6510a2d3 2020-01-15 crossd rp = tolowerrune(rp);
173 6510a2d3 2020-01-15 crossd rq = tolowerrune(rq);
174 6510a2d3 2020-01-15 crossd if(rp < rq)
175 6510a2d3 2020-01-15 crossd return -1;
176 6510a2d3 2020-01-15 crossd if(rp > rq)
177 6510a2d3 2020-01-15 crossd return +1;
178 6510a2d3 2020-01-15 crossd }
179 6510a2d3 2020-01-15 crossd return 0;
180 a9b46206 2020-01-15 crossd }
181 a9b46206 2020-01-15 crossd
182 6510a2d3 2020-01-15 crossd int
183 a9b46206 2020-01-15 crossd winlabelcmp(const void *w1, const void *w2)
184 a9b46206 2020-01-15 crossd {
185 6510a2d3 2020-01-15 crossd const Win *p1 = (Win *) w1;
186 6510a2d3 2020-01-15 crossd const Win *p2 = (Win *) w2;
187 6510a2d3 2020-01-15 crossd return _cistrcmp(p1->label, p2->label);
188 a9b46206 2020-01-15 crossd }
189 a9b46206 2020-01-15 crossd
190 6510a2d3 2020-01-15 crossd void
191 a9b46206 2020-01-15 crossd refreshwin(void)
192 a9b46206 2020-01-15 crossd {
193 6510a2d3 2020-01-15 crossd XWindow dw1, dw2, *xwin;
194 6510a2d3 2020-01-15 crossd XClassHint class;
195 6510a2d3 2020-01-15 crossd XWindowAttributes attr;
196 6510a2d3 2020-01-15 crossd char *label;
197 6510a2d3 2020-01-15 crossd char *wmname;
198 6510a2d3 2020-01-15 crossd int i, nw;
199 6510a2d3 2020-01-15 crossd uint nxwin;
200 6510a2d3 2020-01-15 crossd Status s;
201 6510a2d3 2020-01-15 crossd Atom net_wm_name;
202 a9b46206 2020-01-15 crossd
203 a9b46206 2020-01-15 crossd
204 6510a2d3 2020-01-15 crossd oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
205 6510a2d3 2020-01-15 crossd s = XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin);
206 6510a2d3 2020-01-15 crossd XFlush(dpy);
207 6510a2d3 2020-01-15 crossd XSync(dpy, False);
208 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
209 6510a2d3 2020-01-15 crossd if(s==0){
210 6510a2d3 2020-01-15 crossd if(xwin!=NULL)
211 6510a2d3 2020-01-15 crossd XFree(xwin);
212 6510a2d3 2020-01-15 crossd return;
213 6510a2d3 2020-01-15 crossd }
214 6510a2d3 2020-01-15 crossd qsort(xwin, nxwin, sizeof(xwin[0]), wcmp);
215 a9b46206 2020-01-15 crossd
216 6510a2d3 2020-01-15 crossd nw = 0;
217 6510a2d3 2020-01-15 crossd for(i=0; i<nxwin; i++){
218 6510a2d3 2020-01-15 crossd memset(&attr, 0, sizeof attr);
219 6510a2d3 2020-01-15 crossd xwin[i] = findname(xwin[i]);
220 6510a2d3 2020-01-15 crossd if(xwin[i]==0)
221 6510a2d3 2020-01-15 crossd continue;
222 a9b46206 2020-01-15 crossd
223 6510a2d3 2020-01-15 crossd oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
224 6510a2d3 2020-01-15 crossd s = XGetWindowAttributes(dpy, xwin[i], &attr);
225 6510a2d3 2020-01-15 crossd XFlush(dpy);
226 6510a2d3 2020-01-15 crossd XSync(dpy, False);
227 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
228 6510a2d3 2020-01-15 crossd if(s==0)
229 6510a2d3 2020-01-15 crossd continue;
230 6510a2d3 2020-01-15 crossd if (attr.width <= 0 ||
231 6510a2d3 2020-01-15 crossd attr.override_redirect ||
232 6510a2d3 2020-01-15 crossd attr.map_state != IsViewable)
233 6510a2d3 2020-01-15 crossd continue;
234 a9b46206 2020-01-15 crossd
235 6510a2d3 2020-01-15 crossd oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
236 6510a2d3 2020-01-15 crossd s = XGetClassHint(dpy, xwin[i], &class);
237 6510a2d3 2020-01-15 crossd XFlush(dpy);
238 6510a2d3 2020-01-15 crossd XSync(dpy, False);
239 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
240 a9b46206 2020-01-15 crossd
241 6510a2d3 2020-01-15 crossd if(s==0)
242 6510a2d3 2020-01-15 crossd continue;
243 a9b46206 2020-01-15 crossd
244 6510a2d3 2020-01-15 crossd if (exclude!=nil && regexec(exclude, class.res_name, nil, 0)) {
245 6510a2d3 2020-01-15 crossd free(class.res_name);
246 6510a2d3 2020-01-15 crossd free(class.res_class);
247 6510a2d3 2020-01-15 crossd continue;
248 6510a2d3 2020-01-15 crossd }
249 a9b46206 2020-01-15 crossd
250 6510a2d3 2020-01-15 crossd net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", FALSE);
251 6510a2d3 2020-01-15 crossd wmname = getproperty(xwin[i], net_wm_name);
252 a9b46206 2020-01-15 crossd
253 6510a2d3 2020-01-15 crossd if(wmname==nil){
254 6510a2d3 2020-01-15 crossd wmname = getproperty(xwin[i], XA_WM_NAME);
255 6510a2d3 2020-01-15 crossd if(wmname==nil){
256 6510a2d3 2020-01-15 crossd free(class.res_name);
257 6510a2d3 2020-01-15 crossd free(class.res_class);
258 6510a2d3 2020-01-15 crossd continue;
259 6510a2d3 2020-01-15 crossd }
260 6510a2d3 2020-01-15 crossd }
261 a9b46206 2020-01-15 crossd
262 6510a2d3 2020-01-15 crossd label = class.res_name;
263 6510a2d3 2020-01-15 crossd if(showwmnames==1)
264 6510a2d3 2020-01-15 crossd label = wmname;
265 a9b46206 2020-01-15 crossd
266 6510a2d3 2020-01-15 crossd if(nw<nwin && win[nw].n==xwin[i] && strcmp(win[nw].label, label)==0) {
267 6510a2d3 2020-01-15 crossd nw++;
268 6510a2d3 2020-01-15 crossd free(wmname);
269 6510a2d3 2020-01-15 crossd free(class.res_name);
270 6510a2d3 2020-01-15 crossd free(class.res_class);
271 6510a2d3 2020-01-15 crossd continue;
272 6510a2d3 2020-01-15 crossd }
273 a9b46206 2020-01-15 crossd
274 6510a2d3 2020-01-15 crossd if(nw<nwin){
275 6510a2d3 2020-01-15 crossd free(win[nw].label);
276 6510a2d3 2020-01-15 crossd win[nw].label = nil;
277 6510a2d3 2020-01-15 crossd }
278 a9b46206 2020-01-15 crossd
279 6510a2d3 2020-01-15 crossd if(nw>=mwin){
280 6510a2d3 2020-01-15 crossd mwin += 8;
281 6510a2d3 2020-01-15 crossd win = erealloc(win, mwin * sizeof(win[0]));
282 6510a2d3 2020-01-15 crossd }
283 6510a2d3 2020-01-15 crossd win[nw].n = xwin[i];
284 6510a2d3 2020-01-15 crossd win[nw].label = estrdup(label);
285 6510a2d3 2020-01-15 crossd win[nw].dirty = 1;
286 6510a2d3 2020-01-15 crossd win[nw].r = Rect(0, 0, 0, 0);
287 6510a2d3 2020-01-15 crossd free(wmname);
288 6510a2d3 2020-01-15 crossd free(class.res_name);
289 6510a2d3 2020-01-15 crossd free(class.res_class);
290 6510a2d3 2020-01-15 crossd nw++;
291 6510a2d3 2020-01-15 crossd }
292 a9b46206 2020-01-15 crossd
293 6510a2d3 2020-01-15 crossd oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
294 6510a2d3 2020-01-15 crossd XFree(xwin);
295 6510a2d3 2020-01-15 crossd XFlush(dpy);
296 6510a2d3 2020-01-15 crossd XSync(dpy, False);
297 6510a2d3 2020-01-15 crossd XSetErrorHandler(oldxerrorhandler);
298 a9b46206 2020-01-15 crossd
299 6510a2d3 2020-01-15 crossd while(nwin>nw)
300 6510a2d3 2020-01-15 crossd free(win[--nwin].label);
301 6510a2d3 2020-01-15 crossd nwin = nw;
302 a9b46206 2020-01-15 crossd
303 6510a2d3 2020-01-15 crossd if(sortlabels==1)
304 6510a2d3 2020-01-15 crossd qsort(win, nwin, sizeof(struct Win), winlabelcmp);
305 a9b46206 2020-01-15 crossd }
306 a9b46206 2020-01-15 crossd
307 6510a2d3 2020-01-15 crossd void
308 a9b46206 2020-01-15 crossd drawnowin(int i)
309 a9b46206 2020-01-15 crossd {
310 6510a2d3 2020-01-15 crossd Rectangle r;
311 a9b46206 2020-01-15 crossd
312 6510a2d3 2020-01-15 crossd r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, font->height);
313 6510a2d3 2020-01-15 crossd r = rectaddpt(
314 6510a2d3 2020-01-15 crossd rectaddpt(r,
315 6510a2d3 2020-01-15 crossd Pt(MARGIN + (PAD + Dx(r)) * (i / rows),
316 6510a2d3 2020-01-15 crossd MARGIN + (PAD + Dy(r)) * (i % rows))),
317 6510a2d3 2020-01-15 crossd screen->r.min);
318 6510a2d3 2020-01-15 crossd draw(screen, insetrect(r, -1), lightblue, nil, ZP);
319 a9b46206 2020-01-15 crossd }
320 a9b46206 2020-01-15 crossd
321 6510a2d3 2020-01-15 crossd void
322 a9b46206 2020-01-15 crossd drawwin(int i)
323 a9b46206 2020-01-15 crossd {
324 6510a2d3 2020-01-15 crossd draw(screen, win[i].r, lightblue, nil, ZP);
325 6510a2d3 2020-01-15 crossd _string(screen, addpt(win[i].r.min, Pt(2, 0)), display->black, ZP,
326 6510a2d3 2020-01-15 crossd font, win[i].label, nil, strlen(win[i].label),
327 6510a2d3 2020-01-15 crossd win[i].r, nil, ZP, SoverD);
328 6510a2d3 2020-01-15 crossd border(screen, win[i].r, 1, display->black, ZP);
329 6510a2d3 2020-01-15 crossd win[i].dirty = 0;
330 a9b46206 2020-01-15 crossd }
331 a9b46206 2020-01-15 crossd
332 6510a2d3 2020-01-15 crossd int
333 a9b46206 2020-01-15 crossd geometry(void)
334 a9b46206 2020-01-15 crossd {
335 6510a2d3 2020-01-15 crossd int i, ncols, z;
336 6510a2d3 2020-01-15 crossd Rectangle r;
337 a9b46206 2020-01-15 crossd
338 6510a2d3 2020-01-15 crossd z = 0;
339 6510a2d3 2020-01-15 crossd rows = (Dy(screen->r) - 2 * MARGIN + PAD) / (font->height + PAD);
340 6510a2d3 2020-01-15 crossd if(rows*cols<nwin || rows*cols>=nwin*2){
341 6510a2d3 2020-01-15 crossd ncols = 1;
342 6510a2d3 2020-01-15 crossd if(nwin>0)
343 6510a2d3 2020-01-15 crossd ncols = (nwin + rows - 1) / rows;
344 6510a2d3 2020-01-15 crossd if(ncols!=cols){
345 6510a2d3 2020-01-15 crossd cols = ncols;
346 6510a2d3 2020-01-15 crossd z = 1;
347 6510a2d3 2020-01-15 crossd }
348 6510a2d3 2020-01-15 crossd }
349 a9b46206 2020-01-15 crossd
350 6510a2d3 2020-01-15 crossd r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, font->height);
351 6510a2d3 2020-01-15 crossd for(i=0; i<nwin; i++)
352 6510a2d3 2020-01-15 crossd win[i].r =
353 6510a2d3 2020-01-15 crossd rectaddpt(
354 6510a2d3 2020-01-15 crossd rectaddpt(r,
355 6510a2d3 2020-01-15 crossd Pt(MARGIN + (PAD + Dx(r)) * (i / rows),
356 6510a2d3 2020-01-15 crossd MARGIN + (PAD + Dy(r)) * (i % rows))),
357 6510a2d3 2020-01-15 crossd screen->r.min);
358 a9b46206 2020-01-15 crossd
359 6510a2d3 2020-01-15 crossd return z;
360 a9b46206 2020-01-15 crossd }
361 a9b46206 2020-01-15 crossd
362 6510a2d3 2020-01-15 crossd void
363 a9b46206 2020-01-15 crossd redraw(Image *screen, int all)
364 a9b46206 2020-01-15 crossd {
365 6510a2d3 2020-01-15 crossd int i;
366 a9b46206 2020-01-15 crossd
367 6510a2d3 2020-01-15 crossd all |= geometry();
368 6510a2d3 2020-01-15 crossd if(all)
369 6510a2d3 2020-01-15 crossd draw(screen, screen->r, lightblue, nil, ZP);
370 6510a2d3 2020-01-15 crossd for(i=0; i<nwin; i++)
371 6510a2d3 2020-01-15 crossd if(all || win[i].dirty)
372 6510a2d3 2020-01-15 crossd drawwin(i);
373 6510a2d3 2020-01-15 crossd if(!all)
374 6510a2d3 2020-01-15 crossd for (; i<onwin; i++)
375 6510a2d3 2020-01-15 crossd drawnowin(i);
376 6510a2d3 2020-01-15 crossd onwin = nwin;
377 a9b46206 2020-01-15 crossd }
378 a9b46206 2020-01-15 crossd
379 6510a2d3 2020-01-15 crossd void
380 a9b46206 2020-01-15 crossd eresized(int new)
381 a9b46206 2020-01-15 crossd {
382 6510a2d3 2020-01-15 crossd if(new && getwindow(display, Refmesg)<0)
383 6510a2d3 2020-01-15 crossd fprint(2, "can't reattach to window");
384 6510a2d3 2020-01-15 crossd geometry();
385 6510a2d3 2020-01-15 crossd redraw(screen, 1);
386 a9b46206 2020-01-15 crossd }
387 a9b46206 2020-01-15 crossd
388 a9b46206 2020-01-15 crossd
389 6510a2d3 2020-01-15 crossd void
390 a9b46206 2020-01-15 crossd selectwin(XWindow win)
391 a9b46206 2020-01-15 crossd {
392 6510a2d3 2020-01-15 crossd XEvent ev;
393 6510a2d3 2020-01-15 crossd long mask;
394 a9b46206 2020-01-15 crossd
395 6510a2d3 2020-01-15 crossd memset(&ev, 0, sizeof ev);
396 6510a2d3 2020-01-15 crossd ev.xclient.type = ClientMessage;
397 6510a2d3 2020-01-15 crossd ev.xclient.serial = 0;
398 6510a2d3 2020-01-15 crossd ev.xclient.send_event = True;
399 6510a2d3 2020-01-15 crossd ev.xclient.message_type = net_active_window;
400 6510a2d3 2020-01-15 crossd ev.xclient.window = win;
401 6510a2d3 2020-01-15 crossd ev.xclient.format = 32;
402 6510a2d3 2020-01-15 crossd mask = SubstructureRedirectMask | SubstructureNotifyMask;
403 a9b46206 2020-01-15 crossd
404 6510a2d3 2020-01-15 crossd XSendEvent(dpy, root, False, mask, &ev);
405 6510a2d3 2020-01-15 crossd XMapRaised(dpy, win);
406 6510a2d3 2020-01-15 crossd XSync(dpy, False);
407 a9b46206 2020-01-15 crossd }
408 a9b46206 2020-01-15 crossd
409 6510a2d3 2020-01-15 crossd void
410 a9b46206 2020-01-15 crossd click(Mouse m)
411 a9b46206 2020-01-15 crossd {
412 6510a2d3 2020-01-15 crossd int i, j;
413 a9b46206 2020-01-15 crossd
414 6510a2d3 2020-01-15 crossd if(m.buttons==0 || (m.buttons&~4))
415 6510a2d3 2020-01-15 crossd return;
416 a9b46206 2020-01-15 crossd
417 6510a2d3 2020-01-15 crossd for(i=0; i<nwin; i++)
418 6510a2d3 2020-01-15 crossd if(ptinrect(m.xy, win[i].r))
419 6510a2d3 2020-01-15 crossd break;
420 6510a2d3 2020-01-15 crossd if(i==nwin)
421 6510a2d3 2020-01-15 crossd return;
422 a9b46206 2020-01-15 crossd
423 6510a2d3 2020-01-15 crossd do
424 6510a2d3 2020-01-15 crossd m = emouse();
425 6510a2d3 2020-01-15 crossd while(m.buttons==4);
426 a9b46206 2020-01-15 crossd
427 6510a2d3 2020-01-15 crossd if(m.buttons!=0){
428 6510a2d3 2020-01-15 crossd do
429 6510a2d3 2020-01-15 crossd m = emouse();
430 6510a2d3 2020-01-15 crossd while(m.buttons);
431 6510a2d3 2020-01-15 crossd return;
432 6510a2d3 2020-01-15 crossd }
433 6510a2d3 2020-01-15 crossd for(j=0; j<nwin; j++)
434 6510a2d3 2020-01-15 crossd if(ptinrect(m.xy, win[j].r))
435 6510a2d3 2020-01-15 crossd break;
436 6510a2d3 2020-01-15 crossd if(j==i)
437 6510a2d3 2020-01-15 crossd selectwin(win[i].n);
438 a9b46206 2020-01-15 crossd }
439 a9b46206 2020-01-15 crossd
440 6510a2d3 2020-01-15 crossd void
441 a9b46206 2020-01-15 crossd usage(void)
442 a9b46206 2020-01-15 crossd {
443 6510a2d3 2020-01-15 crossd fprint(2,
444 6510a2d3 2020-01-15 crossd "usage: winwatch [-e exclude] [-W winsize] [-f font] [-n] [-s]\n");
445 6510a2d3 2020-01-15 crossd exits("usage");
446 a9b46206 2020-01-15 crossd }
447 a9b46206 2020-01-15 crossd
448 6510a2d3 2020-01-15 crossd void
449 a9b46206 2020-01-15 crossd main(int argc, char **argv)
450 a9b46206 2020-01-15 crossd {
451 6510a2d3 2020-01-15 crossd char *fontname;
452 6510a2d3 2020-01-15 crossd int Etimer;
453 6510a2d3 2020-01-15 crossd Event e;
454 a9b46206 2020-01-15 crossd
455 6510a2d3 2020-01-15 crossd sortlabels = 0;
456 6510a2d3 2020-01-15 crossd showwmnames = 0;
457 6510a2d3 2020-01-15 crossd fontname = "/lib/font/bit/lucsans/unicode.8.font";
458 a9b46206 2020-01-15 crossd
459 6510a2d3 2020-01-15 crossd ARGBEGIN {
460 6510a2d3 2020-01-15 crossd case 'W':
461 6510a2d3 2020-01-15 crossd winsize = EARGF(usage());
462 6510a2d3 2020-01-15 crossd break;
463 6510a2d3 2020-01-15 crossd case 'f':
464 6510a2d3 2020-01-15 crossd fontname = EARGF(usage());
465 6510a2d3 2020-01-15 crossd break;
466 6510a2d3 2020-01-15 crossd case 'e':
467 6510a2d3 2020-01-15 crossd exclude = regcomp(EARGF(usage()));
468 6510a2d3 2020-01-15 crossd if(exclude==nil)
469 6510a2d3 2020-01-15 crossd sysfatal("Bad regexp");
470 6510a2d3 2020-01-15 crossd break;
471 6510a2d3 2020-01-15 crossd case 's':
472 6510a2d3 2020-01-15 crossd sortlabels = 1;
473 6510a2d3 2020-01-15 crossd break;
474 6510a2d3 2020-01-15 crossd case 'n':
475 6510a2d3 2020-01-15 crossd showwmnames = 1;
476 6510a2d3 2020-01-15 crossd break;
477 6510a2d3 2020-01-15 crossd default:
478 6510a2d3 2020-01-15 crossd usage();
479 6510a2d3 2020-01-15 crossd } ARGEND;
480 a9b46206 2020-01-15 crossd
481 6510a2d3 2020-01-15 crossd if(argc)
482 6510a2d3 2020-01-15 crossd usage();
483 a9b46206 2020-01-15 crossd
484 6510a2d3 2020-01-15 crossd /* moved up from original winwatch.c for p9p because there can be only one but we want to restart when needed */
485 6510a2d3 2020-01-15 crossd einit(Emouse | Ekeyboard);
486 6510a2d3 2020-01-15 crossd Etimer = etimer(0, 1000);
487 a9b46206 2020-01-15 crossd
488 6510a2d3 2020-01-15 crossd dpy = XOpenDisplay("");
489 6510a2d3 2020-01-15 crossd if(dpy==nil)
490 6510a2d3 2020-01-15 crossd sysfatal("open display: %r");
491 a9b46206 2020-01-15 crossd
492 6510a2d3 2020-01-15 crossd root = DefaultRootWindow(dpy);
493 6510a2d3 2020-01-15 crossd net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
494 a9b46206 2020-01-15 crossd
495 6510a2d3 2020-01-15 crossd initdraw(0, 0, "winwatch");
496 6510a2d3 2020-01-15 crossd lightblue = allocimagemix(display, DPalebluegreen, DWhite);
497 6510a2d3 2020-01-15 crossd if(lightblue==nil)
498 6510a2d3 2020-01-15 crossd sysfatal("allocimagemix: %r");
499 6510a2d3 2020-01-15 crossd font = openfont(display, fontname);
500 6510a2d3 2020-01-15 crossd if(font==nil)
501 6510a2d3 2020-01-15 crossd sysfatal("font '%s' not found", fontname);
502 a9b46206 2020-01-15 crossd
503 6510a2d3 2020-01-15 crossd /* reentry point upon X server errors */
504 6510a2d3 2020-01-15 crossd setjmp(savebuf);
505 a9b46206 2020-01-15 crossd
506 6510a2d3 2020-01-15 crossd refreshwin();
507 6510a2d3 2020-01-15 crossd redraw(screen, 1);
508 6510a2d3 2020-01-15 crossd for(;;){
509 6510a2d3 2020-01-15 crossd switch(eread(Emouse|Ekeyboard|Etimer, &e)){
510 6510a2d3 2020-01-15 crossd case Ekeyboard:
511 6510a2d3 2020-01-15 crossd if(e.kbdc==0x7F || e.kbdc=='q')
512 6510a2d3 2020-01-15 crossd exits(0);
513 6510a2d3 2020-01-15 crossd break;
514 6510a2d3 2020-01-15 crossd case Emouse:
515 6510a2d3 2020-01-15 crossd if(e.mouse.buttons)
516 6510a2d3 2020-01-15 crossd click(e.mouse);
517 6510a2d3 2020-01-15 crossd /* fall through */
518 6510a2d3 2020-01-15 crossd default: /* Etimer */
519 6510a2d3 2020-01-15 crossd refreshwin();
520 6510a2d3 2020-01-15 crossd redraw(screen, 0);
521 6510a2d3 2020-01-15 crossd break;
522 6510a2d3 2020-01-15 crossd }
523 6510a2d3 2020-01-15 crossd }
524 a9b46206 2020-01-15 crossd }