]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/winwatch.c
winwatch: no more 'l' key labeling
[plan9front.git] / sys / src / cmd / winwatch.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <cursor.h>
5 #include <event.h>
6 #include <regexp.h>
7 #include <keyboard.h>
8
9 enum {
10         VISIBLE = 1,
11         CURRENT = 2,
12 };
13
14 typedef struct Win Win;
15 struct Win {
16         int n;
17         int dirty;
18         int state;
19         char *label;
20         Rectangle r;
21 };
22
23 Reprog  *exclude  = nil;
24 Win *win;
25 int nwin;
26 int mwin;
27 int onwin;
28 int rows, cols;
29 Image *lightblue;
30 Image *statecol[4];
31
32 enum {
33         PAD = 3,
34         MARGIN = 5
35 };
36
37 void*
38 erealloc(void *v, ulong n)
39 {
40         v = realloc(v, n);
41         if(v == nil)
42                 sysfatal("out of memory reallocating %lud", n);
43         return v;
44 }
45
46 void*
47 emalloc(ulong n)
48 {
49         void *v;
50
51         v = malloc(n);
52         if(v == nil)
53                 sysfatal("out of memory allocating %lud", n);
54         memset(v, 0, n);
55         return v;
56 }
57
58 char*
59 estrdup(char *s)
60 {
61         int l;
62         char *t;
63
64         if (s == nil)
65                 return nil;
66         l = strlen(s)+1;
67         t = emalloc(l);
68         memcpy(t, s, l);
69
70         return t;
71 }
72
73 int
74 readfile(char *buf, int nbuf, char *file, ...)
75 {
76         va_list arg;
77         int n, fd;
78
79         va_start(arg, file);
80         vsnprint(buf, nbuf, file, arg);
81         va_end(arg);
82
83         if((fd = open(buf, OREAD)) < 0){
84                 buf[0] = 0;
85                 return -1;
86         }
87         n = read(fd, buf, nbuf-1);
88         close(fd);
89         if(n < 0){
90                 buf[0] = 0;
91                 return -1;
92         }
93         buf[n] = 0;
94         return n;
95 }
96
97 void
98 refreshwin(void)
99 {
100         char label[128], wctl[128], *tok[8];
101         int i, fd, n, nr, nw, state;
102         static int mywinid = -1;
103         Dir *pd;
104
105         if(mywinid < 0){
106                 if(readfile(wctl, sizeof(wctl), "/dev/winid") > 0)
107                         mywinid = atoi(wctl);
108         }
109
110         if((fd = open("/dev/wsys", OREAD)) < 0)
111                 return;
112
113         nw = 0;
114 /* i'd rather read one at a time but rio won't let me */
115         while((nr=dirread(fd, &pd)) > 0){
116                 for(i=0; i<nr; i++){
117                         n = atoi(pd[i].name);
118                         if(n == mywinid)
119                                 continue;
120                         if(readfile(label, sizeof(label), "/dev/wsys/%d/label", n) <= 0)
121                                 continue;
122                         if(exclude != nil && regexec(exclude,label,nil,0))
123                                 continue;
124                         if(readfile(wctl, sizeof(wctl), "/dev/wsys/%d/wctl", n) <= 0)
125                                 continue;
126                         if(tokenize(wctl, tok, nelem(tok)) != 6)
127                                 continue;
128                         state = 0;
129                         if(strcmp(tok[4], "current") == 0)
130                                 state |= CURRENT;
131                         if(strcmp(tok[5], "visible") == 0)
132                                 state |= VISIBLE;
133                         if(nw < nwin && win[nw].n == n && win[nw].state == state && 
134                            strcmp(win[nw].label, label)==0){
135                                 nw++;
136                                 continue;
137                         }
138         
139                         if(nw < nwin){
140                                 free(win[nw].label);
141                                 win[nw].label = nil;
142                         }
143                         
144                         if(nw >= mwin){
145                                 mwin += 8;
146                                 win = erealloc(win, mwin*sizeof(win[0]));
147                         }
148                         win[nw].n = n;
149                         win[nw].label = estrdup(label);
150                         win[nw].state = state;
151                         win[nw].dirty = 1;
152                         win[nw].r = Rect(0,0,0,0);
153                         nw++;
154                 }
155                 free(pd);
156         }
157         while(nwin > nw)
158                 free(win[--nwin].label);
159         nwin = nw;
160         close(fd);
161 }
162
163 void
164 drawnowin(int i)
165 {
166         Rectangle r;
167
168         r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
169         r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
170                                 MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
171         draw(screen, insetrect(r, -1), lightblue, nil, ZP);
172 }
173
174 void
175 drawwin(int i)
176 {
177         draw(screen, win[i].r, statecol[win[i].state], nil, ZP);
178         _string(screen, addpt(win[i].r.min, Pt(2,0)), display->black, ZP,
179                 font, win[i].label, nil, strlen(win[i].label), 
180                 win[i].r, nil, ZP, SoverD);
181         border(screen, win[i].r, 1, display->black, ZP);        
182         win[i].dirty = 0;
183 }
184
185 int
186 geometry(void)
187 {
188         int i, ncols, z;
189         Rectangle r;
190
191         z = 0;
192         rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height+PAD);
193         if(rows <= 0)
194                 rows = 1;
195         if(rows*cols < nwin || rows*cols >= nwin*2){
196                 ncols = nwin <= 0 ? 1 : (nwin+rows-1)/rows;
197                 if(ncols != cols){
198                         cols = ncols;
199                         z = 1;
200                 }
201         }
202
203         r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
204         for(i=0; i<nwin; i++)
205                 win[i].r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
206                                         MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
207
208         return z;
209 }
210
211 void
212 redraw(Image *screen, int all)
213 {
214         int i;
215
216         all |= geometry();
217         if(all)
218                 draw(screen, screen->r, lightblue, nil, ZP);
219         for(i=0; i<nwin; i++)
220                 if(all || win[i].dirty)
221                         drawwin(i);
222         if(!all)
223                 for(; i<onwin; i++)
224                         drawnowin(i);
225
226         onwin = nwin;
227 }
228
229 void
230 eresized(int new)
231 {
232         if(new && getwindow(display, Refmesg) < 0)
233                 fprint(2,"can't reattach to window");
234         geometry();
235         redraw(screen, 1);
236 }
237
238 int
239 label(Win w, Mouse m)
240 {
241         char buf[512], fname[128];
242         int n, fd;
243
244         buf[0] = 0;
245         n = eenter("label?", buf, sizeof(buf), &m);
246         if(n <= 0)
247                 return 0;
248         sprint(fname, "/dev/wsys/%d/label", w.n);
249         if((fd = open(fname, OWRITE)) < 0)
250                 return 0;
251         write(fd, buf, n);
252         close(fd);
253         refreshwin();
254         redraw(screen, 1);
255         return 1;
256 }
257
258 int
259 unhide(Win w)
260 {
261         char buf[128];
262         int fd;
263
264         sprint(buf, "/dev/wsys/%d/wctl", w.n);
265         if((fd = open(buf, OWRITE)) < 0)
266                 return 0;
267         if(w.state == (CURRENT|VISIBLE))
268                 write(fd, "hide\n", 5);
269         else {
270                 write(fd, "unhide\n", 7);
271                 write(fd, "top\n", 4);
272                 write(fd, "current\n", 8);
273         }
274         close(fd);
275         return 1;
276 }
277
278 int
279 click(Mouse m)
280 {
281         int i, b;
282
283         b = m.buttons & 7;
284         if(b != 2 && b != 4)
285                 return 0;
286         for(i=0; i<nwin; i++)
287                 if(ptinrect(m.xy, win[i].r))
288                         break;
289         if(i == nwin)
290                 return 0;
291         do
292                 m = emouse();
293         while((m.buttons & 7) == b);
294         if((m.buttons & 7) || !ptinrect(m.xy, win[i].r))
295                 return 0;
296
297         switch(b) {
298         case 2:
299                 return label(win[i], m);
300         case 4:
301                 return unhide(win[i]);
302         default:
303                 return 0;
304         }
305 }
306
307 void
308 usage(void)
309 {
310         fprint(2, "usage: winwatch [-e exclude] [-f font]\n");
311         exits("usage");
312 }
313
314 void
315 main(int argc, char **argv)
316 {
317         char *fontname = nil;
318         int Etimer;
319         Event e;
320         int i;
321
322         ARGBEGIN{
323         case 'f':
324                 fontname = EARGF(usage());
325                 break;
326         case 'e':
327                 exclude = regcomp(EARGF(usage()));
328                 if(exclude == nil)
329                         sysfatal("Bad regexp");
330                 break;
331         default:
332                 usage();
333         }ARGEND
334
335         if(argc)
336                 usage();
337
338         if(initdraw(0, fontname, "winwatch") < 0)
339                 sysfatal("initdraw: %r");
340         lightblue = allocimagemix(display, DPalebluegreen, DWhite);
341
342         statecol[0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);
343         statecol[1] = lightblue;
344         statecol[2] = lightblue;
345         statecol[3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
346
347         for(i=0; i<nelem(statecol); i++)
348                 if(statecol[i] == nil)
349                         sysfatal("allocimage: %r");
350
351         refreshwin();
352         redraw(screen, 1);
353         einit(Emouse|Ekeyboard);
354         Etimer = etimer(0, 2500);
355
356         for(;;){
357                 switch(eread(Emouse|Ekeyboard|Etimer, &e)){
358                 case Ekeyboard:
359                         if(e.kbdc==Kdel || e.kbdc=='q')
360                                 exits(0);
361                         break;
362                 case Emouse:
363                         if(click(e.mouse) == 0)
364                                 continue;
365                         /* fall through  */
366                 default:        /* Etimer */
367                         refreshwin();
368                         redraw(screen, 0);
369                         break;
370                 }
371         }
372 }