]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/winwatch.c
abaco: cleanup, handle image/x-icon, don't use backspace as a hotkey, and remove...
[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 <= 0)
192                 rows = 1;
193         if(rows*cols < nwin || rows*cols >= nwin*2){
194                 ncols = nwin <= 0 ? 1 : (nwin+rows-1)/rows;
195                 if(ncols != cols){
196                         cols = ncols;
197                         z = 1;
198                 }
199         }
200
201         r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
202         for(i=0; i<nwin; i++)
203                 win[i].r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
204                                         MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
205
206         return z;
207 }
208
209 void
210 redraw(Image *screen, int all)
211 {
212         int i;
213
214         all |= geometry();
215         if(all)
216                 draw(screen, screen->r, lightblue, nil, ZP);
217         for(i=0; i<nwin; i++)
218                 if(all || win[i].dirty)
219                         drawwin(i);
220         if(!all)
221                 for(; i<onwin; i++)
222                         drawnowin(i);
223
224         onwin = nwin;
225 }
226
227 void
228 eresized(int new)
229 {
230         if(new && getwindow(display, Refmesg) < 0)
231                 fprint(2,"can't reattach to window");
232         geometry();
233         redraw(screen, 1);
234 }
235
236 int
237 click(Mouse m)
238 {
239         char buf[128];
240         int fd, i;      
241
242         if((m.buttons & 7) != 4)
243                 return 0;
244         for(i=0; i<nwin; i++)
245                 if(ptinrect(m.xy, win[i].r))
246                         break;
247         if(i == nwin)
248                 return 0;
249         do
250                 m = emouse();
251         while((m.buttons & 7) == 4);
252         if((m.buttons & 7) || !ptinrect(m.xy, win[i].r))
253                 return 0;
254
255         sprint(buf, "/dev/wsys/%d/wctl", win[i].n);
256         if((fd = open(buf, OWRITE)) < 0)
257                 return 0;
258         if(win[i].state == (CURRENT|VISIBLE))
259                 write(fd, "hide\n", 5);
260         else {
261                 write(fd, "unhide\n", 7);
262                 write(fd, "top\n", 4);
263                 write(fd, "current\n", 8);
264         }
265         close(fd);
266         return 1;
267 }
268
269 void
270 usage(void)
271 {
272         fprint(2, "usage: winwatch [-e exclude] [-f font]\n");
273         exits("usage");
274 }
275
276 void
277 main(int argc, char **argv)
278 {
279         char *fontname = nil;
280         int Etimer;
281         Event e;
282         int i;
283
284         ARGBEGIN{
285         case 'f':
286                 fontname = EARGF(usage());
287                 break;
288         case 'e':
289                 exclude = regcomp(EARGF(usage()));
290                 if(exclude == nil)
291                         sysfatal("Bad regexp");
292                 break;
293         default:
294                 usage();
295         }ARGEND
296
297         if(argc)
298                 usage();
299
300         if(initdraw(0, fontname, "winwatch") < 0)
301                 sysfatal("initdraw: %r");
302         lightblue = allocimagemix(display, DPalebluegreen, DWhite);
303
304         statecol[0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCFF);
305         statecol[1] = lightblue;
306         statecol[2] = lightblue;
307         statecol[3] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
308
309         for(i=0; i<nelem(statecol); i++)
310                 if(statecol[i] == nil)
311                         sysfatal("allocimage: %r");
312
313         refreshwin();
314         redraw(screen, 1);
315         einit(Emouse|Ekeyboard);
316         Etimer = etimer(0, 2500);
317
318         for(;;){
319                 switch(eread(Emouse|Ekeyboard|Etimer, &e)){
320                 case Ekeyboard:
321                         if(e.kbdc==0x7F || e.kbdc=='q')
322                                 exits(0);
323                         break;
324                 case Emouse:
325                         if(click(e.mouse) == 0)
326                                 continue;
327                         /* fall through  */
328                 default:        /* Etimer */
329                         refreshwin();
330                         redraw(screen, 0);
331                         break;
332                 }
333         }
334 }