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