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