xref: /plan9/sys/src/cmd/winwatch.c (revision f30ccc91ab9e7f92bd5dd82b1eebdeb503fd3465)
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