xref: /plan9/sys/src/cmd/winwatch.c (revision f30ccc91ab9e7f92bd5dd82b1eebdeb503fd3465)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <draw.h>
49a747e4fSDavid du Colombier #include <event.h>
513ec2712SDavid du Colombier #include <regexp.h>
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier typedef struct Win Win;
89a747e4fSDavid du Colombier struct Win {
99a747e4fSDavid du Colombier 	int n;
109a747e4fSDavid du Colombier 	int dirty;
119a747e4fSDavid du Colombier 	char *label;
129a747e4fSDavid du Colombier 	Rectangle r;
139a747e4fSDavid du Colombier };
149a747e4fSDavid du Colombier 
1513ec2712SDavid du Colombier 
1613ec2712SDavid du Colombier 
1713ec2712SDavid du Colombier Reprog  *exclude  = nil;
189a747e4fSDavid du Colombier Win *win;
199a747e4fSDavid du Colombier int nwin;
209a747e4fSDavid du Colombier int mwin;
219a747e4fSDavid du Colombier int onwin;
229a747e4fSDavid du Colombier int rows, cols;
239a747e4fSDavid du Colombier Font *font;
249a747e4fSDavid du Colombier Image *lightblue;
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier enum {
279a747e4fSDavid du Colombier 	PAD = 3,
289a747e4fSDavid du Colombier 	MARGIN = 5
299a747e4fSDavid du Colombier };
309a747e4fSDavid du Colombier 
319a747e4fSDavid du Colombier void*
erealloc(void * v,ulong n)329a747e4fSDavid du Colombier erealloc(void *v, ulong n)
339a747e4fSDavid du Colombier {
349a747e4fSDavid du Colombier 	v = realloc(v, n);
359a747e4fSDavid du Colombier 	if(v == nil)
369a747e4fSDavid du Colombier 		sysfatal("out of memory reallocating %lud", n);
379a747e4fSDavid du Colombier 	return v;
389a747e4fSDavid du Colombier }
399a747e4fSDavid du Colombier 
409a747e4fSDavid du Colombier void*
emalloc(ulong n)419a747e4fSDavid du Colombier emalloc(ulong n)
429a747e4fSDavid du Colombier {
439a747e4fSDavid du Colombier 	void *v;
449a747e4fSDavid du Colombier 
459a747e4fSDavid du Colombier 	v = malloc(n);
469a747e4fSDavid du Colombier 	if(v == nil)
479a747e4fSDavid du Colombier 		sysfatal("out of memory allocating %lud", n);
489a747e4fSDavid du Colombier 	memset(v, 0, n);
499a747e4fSDavid du Colombier 	return v;
509a747e4fSDavid du Colombier }
519a747e4fSDavid du Colombier 
529a747e4fSDavid du Colombier char*
estrdup(char * s)539a747e4fSDavid du Colombier estrdup(char *s)
549a747e4fSDavid du Colombier {
559a747e4fSDavid du Colombier 	int l;
569a747e4fSDavid du Colombier 	char *t;
579a747e4fSDavid du Colombier 
589a747e4fSDavid du Colombier 	if (s == nil)
599a747e4fSDavid du Colombier 		return nil;
609a747e4fSDavid du Colombier 	l = strlen(s)+1;
619a747e4fSDavid du Colombier 	t = emalloc(l);
629a747e4fSDavid du Colombier 	memcpy(t, s, l);
639a747e4fSDavid du Colombier 
649a747e4fSDavid du Colombier 	return t;
659a747e4fSDavid du Colombier }
669a747e4fSDavid du Colombier 
6713ec2712SDavid du Colombier 
689a747e4fSDavid du Colombier void
refreshwin(void)699a747e4fSDavid du Colombier refreshwin(void)
709a747e4fSDavid du Colombier {
719a747e4fSDavid du Colombier 	char label[128];
729a747e4fSDavid du Colombier 	int i, fd, lfd, n, nr, nw, m;
739a747e4fSDavid du Colombier 	Dir *pd;
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier 	if((fd = open("/dev/wsys", OREAD)) < 0)
769a747e4fSDavid du Colombier 		return;
779a747e4fSDavid du Colombier 
789a747e4fSDavid du Colombier 	nw = 0;
799a747e4fSDavid du Colombier /* i'd rather read one at a time but rio won't let me */
809a747e4fSDavid du Colombier 	while((nr=dirread(fd, &pd)) > 0){
819a747e4fSDavid du Colombier 		for(i=0; i<nr; i++){
829a747e4fSDavid du Colombier 			n = atoi(pd[i].name);
839a747e4fSDavid du Colombier 			sprint(label, "/dev/wsys/%d/label", n);
849a747e4fSDavid du Colombier 			if((lfd = open(label, OREAD)) < 0)
859a747e4fSDavid du Colombier 				continue;
869a747e4fSDavid du Colombier 			m = read(lfd, label, sizeof(label)-1);
879a747e4fSDavid du Colombier 			close(lfd);
889a747e4fSDavid du Colombier 			if(m < 0)
899a747e4fSDavid du Colombier 				continue;
909a747e4fSDavid du Colombier 			label[m] = '\0';
9113ec2712SDavid du Colombier 			if(exclude != nil && regexec(exclude,label,nil,0))
9213ec2712SDavid du Colombier 				continue;
9313ec2712SDavid du Colombier 
949a747e4fSDavid du Colombier 			if(nw < nwin && win[nw].n == n && strcmp(win[nw].label, label)==0){
959a747e4fSDavid du Colombier 				nw++;
969a747e4fSDavid du Colombier 				continue;
979a747e4fSDavid du Colombier 			}
989a747e4fSDavid du Colombier 
999a747e4fSDavid du Colombier 			if(nw < nwin){
1009a747e4fSDavid du Colombier 				free(win[nw].label);
1019a747e4fSDavid du Colombier 				win[nw].label = nil;
1029a747e4fSDavid du Colombier 			}
10313ec2712SDavid du Colombier 
1049a747e4fSDavid du Colombier 			if(nw >= mwin){
1059a747e4fSDavid du Colombier 				mwin += 8;
1069a747e4fSDavid du Colombier 				win = erealloc(win, mwin*sizeof(win[0]));
1079a747e4fSDavid du Colombier 			}
1089a747e4fSDavid du Colombier 			win[nw].n = n;
1099a747e4fSDavid du Colombier 			win[nw].label = estrdup(label);
1109a747e4fSDavid du Colombier 			win[nw].dirty = 1;
1119a747e4fSDavid du Colombier 			win[nw].r = Rect(0,0,0,0);
1129a747e4fSDavid du Colombier 			nw++;
1139a747e4fSDavid du Colombier 		}
1149a747e4fSDavid du Colombier 		free(pd);
1159a747e4fSDavid du Colombier 	}
1169a747e4fSDavid du Colombier 	while(nwin > nw)
1179a747e4fSDavid du Colombier 		free(win[--nwin].label);
1189a747e4fSDavid du Colombier 	nwin = nw;
1199a747e4fSDavid du Colombier 	close(fd);
1209a747e4fSDavid du Colombier }
1219a747e4fSDavid du Colombier 
1229a747e4fSDavid du Colombier void
drawnowin(int i)1239a747e4fSDavid du Colombier drawnowin(int i)
1249a747e4fSDavid du Colombier {
1259a747e4fSDavid du Colombier 	Rectangle r;
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier 	r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
1289a747e4fSDavid du Colombier 	r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
1299a747e4fSDavid du Colombier 				MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
1309a747e4fSDavid du Colombier 	draw(screen, insetrect(r, -1), lightblue, nil, ZP);
1319a747e4fSDavid du Colombier }
1329a747e4fSDavid du Colombier 
1339a747e4fSDavid du Colombier void
drawwin(int i)1349a747e4fSDavid du Colombier drawwin(int i)
1359a747e4fSDavid du Colombier {
1369a747e4fSDavid du Colombier 	draw(screen, win[i].r, lightblue, nil, ZP);
1379a747e4fSDavid du Colombier 	_string(screen, addpt(win[i].r.min, Pt(2,0)), display->black, ZP,
1389a747e4fSDavid du Colombier 		font, win[i].label, nil, strlen(win[i].label),
139ac57dd0bSDavid du Colombier 		win[i].r, nil, ZP, SoverD);
1409a747e4fSDavid du Colombier 	border(screen, win[i].r, 1, display->black, ZP);
1419a747e4fSDavid du Colombier 	win[i].dirty = 0;
1429a747e4fSDavid du Colombier }
1439a747e4fSDavid du Colombier 
1449a747e4fSDavid du Colombier int
geometry(void)1459a747e4fSDavid du Colombier geometry(void)
1469a747e4fSDavid du Colombier {
1479a747e4fSDavid du Colombier 	int i, ncols, z;
1489a747e4fSDavid du Colombier 	Rectangle r;
1499a747e4fSDavid du Colombier 
1509a747e4fSDavid du Colombier 	z = 0;
1519a747e4fSDavid du Colombier 	rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height+PAD);
1529a747e4fSDavid du Colombier 	if(rows*cols < nwin || rows*cols >= nwin*2){
1539552e201SDavid du Colombier 		ncols = nwin <= 0 ? 1 : (nwin+rows-1)/rows;
1549a747e4fSDavid du Colombier 		if(ncols != cols){
1559a747e4fSDavid du Colombier 			cols = ncols;
1569a747e4fSDavid du Colombier 			z = 1;
1579a747e4fSDavid du Colombier 		}
1589a747e4fSDavid du Colombier 	}
1599a747e4fSDavid du Colombier 
1609a747e4fSDavid du Colombier 	r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
1619a747e4fSDavid du Colombier 	for(i=0; i<nwin; i++)
1629a747e4fSDavid du Colombier 		win[i].r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
1639a747e4fSDavid du Colombier 					MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
1649a747e4fSDavid du Colombier 
1659a747e4fSDavid du Colombier 	return z;
1669a747e4fSDavid du Colombier }
1679a747e4fSDavid du Colombier 
1689a747e4fSDavid du Colombier void
redraw(Image * screen,int all)1699a747e4fSDavid du Colombier redraw(Image *screen, int all)
1709a747e4fSDavid du Colombier {
1719a747e4fSDavid du Colombier 	int i;
1729a747e4fSDavid du Colombier 
1739a747e4fSDavid du Colombier 	all |= geometry();
1749a747e4fSDavid du Colombier 	if(all)
1759a747e4fSDavid du Colombier 		draw(screen, screen->r, lightblue, nil, ZP);
1769a747e4fSDavid du Colombier 	for(i=0; i<nwin; i++)
1779a747e4fSDavid du Colombier 		if(all || win[i].dirty)
1789a747e4fSDavid du Colombier 			drawwin(i);
1799a747e4fSDavid du Colombier 	if(!all)
1809a747e4fSDavid du Colombier 		for(; i<onwin; i++)
1819a747e4fSDavid du Colombier 			drawnowin(i);
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	onwin = nwin;
1849a747e4fSDavid du Colombier }
1859a747e4fSDavid du Colombier 
1869a747e4fSDavid du Colombier void
eresized(int new)1879a747e4fSDavid du Colombier eresized(int new)
1889a747e4fSDavid du Colombier {
1899a747e4fSDavid du Colombier 	if(new && getwindow(display, Refmesg) < 0)
1909a747e4fSDavid du Colombier 		fprint(2,"can't reattach to window");
1919a747e4fSDavid du Colombier 	geometry();
1929a747e4fSDavid du Colombier 	redraw(screen, 1);
1939a747e4fSDavid du Colombier }
1949a747e4fSDavid du Colombier 
1959a747e4fSDavid du Colombier void
click(Mouse m)1969a747e4fSDavid du Colombier click(Mouse m)
1979a747e4fSDavid du Colombier {
1989a747e4fSDavid du Colombier 	int fd, i, j;
1999a747e4fSDavid du Colombier 	char buf[128];
2009a747e4fSDavid du Colombier 
2019a747e4fSDavid du Colombier 	if(m.buttons == 0 || (m.buttons & ~4))
2029a747e4fSDavid du Colombier 		return;
2039a747e4fSDavid du Colombier 
2049a747e4fSDavid du Colombier 	for(i=0; i<nwin; i++)
2059a747e4fSDavid du Colombier 		if(ptinrect(m.xy, win[i].r))
2069a747e4fSDavid du Colombier 			break;
2079a747e4fSDavid du Colombier 	if(i == nwin)
2089a747e4fSDavid du Colombier 		return;
2099a747e4fSDavid du Colombier 
2109a747e4fSDavid du Colombier 	do
2119a747e4fSDavid du Colombier 		m = emouse();
2129a747e4fSDavid du Colombier 	while(m.buttons == 4);
2139a747e4fSDavid du Colombier 
2149a747e4fSDavid du Colombier 	if(m.buttons != 0){
2159a747e4fSDavid du Colombier 		do
2169a747e4fSDavid du Colombier 			m = emouse();
2179a747e4fSDavid du Colombier 		while(m.buttons);
2189a747e4fSDavid du Colombier 		return;
2199a747e4fSDavid du Colombier 	}
2209a747e4fSDavid du Colombier 
2219a747e4fSDavid du Colombier 	for(j=0; j<nwin; j++)
2229a747e4fSDavid du Colombier 		if(ptinrect(m.xy, win[j].r))
2239a747e4fSDavid du Colombier 			break;
2249a747e4fSDavid du Colombier 	if(j != i)
2259a747e4fSDavid du Colombier 		return;
2269a747e4fSDavid du Colombier 
2279a747e4fSDavid du Colombier 	sprint(buf, "/dev/wsys/%d/wctl", win[i].n);
2289a747e4fSDavid du Colombier 	if((fd = open(buf, OWRITE)) < 0)
2299a747e4fSDavid du Colombier 		return;
230ac57dd0bSDavid du Colombier 	write(fd, "unhide\n", 7);
2319a747e4fSDavid du Colombier 	write(fd, "top\n", 4);
2329a747e4fSDavid du Colombier 	write(fd, "current\n", 8);
2339a747e4fSDavid du Colombier 	close(fd);
2349a747e4fSDavid du Colombier }
2359a747e4fSDavid du Colombier 
2369a747e4fSDavid du Colombier void
usage(void)2379a747e4fSDavid du Colombier usage(void)
2389a747e4fSDavid du Colombier {
23913ec2712SDavid du Colombier 	fprint(2, "usage: winwatch [-e exclude] [-f font]\n");
2409a747e4fSDavid du Colombier 	exits("usage");
2419a747e4fSDavid du Colombier }
2429a747e4fSDavid du Colombier 
2439a747e4fSDavid du Colombier void
main(int argc,char ** argv)2449a747e4fSDavid du Colombier main(int argc, char **argv)
2459a747e4fSDavid du Colombier {
2469a747e4fSDavid du Colombier 	char *fontname;
2479a747e4fSDavid du Colombier 	int Etimer;
2489a747e4fSDavid du Colombier 	Event e;
2499a747e4fSDavid du Colombier 
2509a747e4fSDavid du Colombier 	fontname = "/lib/font/bit/lucidasans/unicode.8.font";
2519a747e4fSDavid du Colombier 	ARGBEGIN{
2529a747e4fSDavid du Colombier 	case 'f':
2539a747e4fSDavid du Colombier 		fontname = EARGF(usage());
2549a747e4fSDavid du Colombier 		break;
25513ec2712SDavid du Colombier 	case 'e':
25613ec2712SDavid du Colombier 		exclude = regcomp(EARGF(usage()));
25713ec2712SDavid du Colombier 		if(exclude == nil)
25813ec2712SDavid du Colombier 			sysfatal("Bad regexp");
25913ec2712SDavid du Colombier 		break;
260a22b0629SDavid du Colombier 	default:
261a22b0629SDavid du Colombier 		usage();
2629a747e4fSDavid du Colombier 	}ARGEND
2639a747e4fSDavid du Colombier 
2649a747e4fSDavid du Colombier 	if(argc)
2659a747e4fSDavid du Colombier 		usage();
2669a747e4fSDavid du Colombier 
2679a747e4fSDavid du Colombier 	initdraw(0, 0, "winwatch");
2689a747e4fSDavid du Colombier 	lightblue = allocimagemix(display, DPalebluegreen, DWhite);
2699a747e4fSDavid du Colombier 	if(lightblue == nil)
2709a747e4fSDavid du Colombier 		sysfatal("allocimagemix: %r");
2719a747e4fSDavid du Colombier 	if((font = openfont(display, fontname)) == nil)
2729a747e4fSDavid du Colombier 		sysfatal("font '%s' not found", fontname);
2739a747e4fSDavid du Colombier 
2749a747e4fSDavid du Colombier 	refreshwin();
2759a747e4fSDavid du Colombier 	redraw(screen, 1);
2769a747e4fSDavid du Colombier 	einit(Emouse|Ekeyboard);
277*f30ccc91SDavid du Colombier 	Etimer = etimer(0, 2500);
2789a747e4fSDavid du Colombier 
2799a747e4fSDavid du Colombier 	for(;;){
2809a747e4fSDavid du Colombier 		switch(eread(Emouse|Ekeyboard|Etimer, &e)){
2819a747e4fSDavid du Colombier 		case Ekeyboard:
2829a747e4fSDavid du Colombier 			if(e.kbdc==0x7F || e.kbdc=='q')
2839a747e4fSDavid du Colombier 				exits(0);
2849a747e4fSDavid du Colombier 			break;
2859a747e4fSDavid du Colombier 		case Emouse:
2869a747e4fSDavid du Colombier 			if(e.mouse.buttons)
2879a747e4fSDavid du Colombier 				click(e.mouse);
288*f30ccc91SDavid du Colombier 			/* fall through  */
2899a747e4fSDavid du Colombier 		default:	/* Etimer */
2909a747e4fSDavid du Colombier 			refreshwin();
2919a747e4fSDavid du Colombier 			redraw(screen, 0);
2929a747e4fSDavid du Colombier 			break;
2939a747e4fSDavid du Colombier 		}
2949a747e4fSDavid du Colombier 	}
2959a747e4fSDavid du Colombier }
296