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