xref: /plan9/sys/src/cmd/faces/main.c (revision d9d5974c9cc932150e07925488df051092dba4ce)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <plumb.h>
57dd7cddfSDavid du Colombier #include <regexp.h>
67dd7cddfSDavid du Colombier #include <event.h>	/* for support routines only */
77dd7cddfSDavid du Colombier #include <bio.h>
87dd7cddfSDavid du Colombier #include "faces.h"
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier int	history = 0;	/* use old interface, showing history of mailbox rather than current state */
117dd7cddfSDavid du Colombier int	initload = 0;	/* initialize program with contents of mail box */
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier enum
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier 	Facesep = 6,	/* must be even to avoid damaging background stipple */
167dd7cddfSDavid du Colombier 	Infolines = 9,
17d3c05884SDavid du Colombier 
18d3c05884SDavid du Colombier 	HhmmTime = 18*60*60,	/* max age of face to display hh:mm time */
197dd7cddfSDavid du Colombier };
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier enum
227dd7cddfSDavid du Colombier {
237dd7cddfSDavid du Colombier 	Mainp,
247dd7cddfSDavid du Colombier 	Timep,
257dd7cddfSDavid du Colombier 	Mousep,
267dd7cddfSDavid du Colombier 	NPROC
277dd7cddfSDavid du Colombier };
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier int pids[NPROC];
307dd7cddfSDavid du Colombier char *procnames[] = {
317dd7cddfSDavid du Colombier 	"main",
327dd7cddfSDavid du Colombier 	"time",
337dd7cddfSDavid du Colombier 	"mouse"
347dd7cddfSDavid du Colombier };
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier Rectangle leftright = {0, 0, 20, 15};
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier uchar leftdata[] = {
397dd7cddfSDavid du Colombier 	0x00, 0x80, 0x00, 0x01, 0x80, 0x00, 0x03, 0x80,
407dd7cddfSDavid du Colombier 	0x00, 0x07, 0x80, 0x00, 0x0f, 0x00, 0x00, 0x1f,
417dd7cddfSDavid du Colombier 	0xff, 0xf0, 0x3f, 0xff, 0xf0, 0xff, 0xff, 0xf0,
427dd7cddfSDavid du Colombier 	0x3f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x0f, 0x00,
437dd7cddfSDavid du Colombier 	0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x01,
447dd7cddfSDavid du Colombier 	0x80, 0x00, 0x00, 0x80, 0x00
457dd7cddfSDavid du Colombier };
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier uchar rightdata[] = {
487dd7cddfSDavid du Colombier 	0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1c,
497dd7cddfSDavid du Colombier 	0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0xff,
507dd7cddfSDavid du Colombier 	0xff, 0x80, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xf0,
517dd7cddfSDavid du Colombier 	0xff, 0xff, 0xc0, 0xff, 0xff, 0x80, 0x00, 0x0f,
527dd7cddfSDavid du Colombier 	0x00, 0x00, 0x1e, 0x00, 0x00, 0x1c, 0x00, 0x00,
537dd7cddfSDavid du Colombier 	0x18, 0x00, 0x00, 0x10, 0x00
547dd7cddfSDavid du Colombier };
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier Image	*blue;		/* full arrow */
577dd7cddfSDavid du Colombier Image	*bgrnd;		/* pale blue background color */
587dd7cddfSDavid du Colombier Image	*left;		/* left-pointing arrow mask */
597dd7cddfSDavid du Colombier Image	*right;		/* right-pointing arrow mask */
607dd7cddfSDavid du Colombier Font	*tinyfont;
617dd7cddfSDavid du Colombier Font	*mediumfont;
627dd7cddfSDavid du Colombier Font	*datefont;
637dd7cddfSDavid du Colombier int	first, last;	/* first and last visible face; last is first invisible */
647dd7cddfSDavid du Colombier int	nfaces;
657dd7cddfSDavid du Colombier int	mousefd;
667dd7cddfSDavid du Colombier int	nacross;
677dd7cddfSDavid du Colombier int	ndown;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier char	date[64];
707dd7cddfSDavid du Colombier Face	**faces;
717dd7cddfSDavid du Colombier char	*maildir = "/mail/fs/mbox";
72d9306527SDavid du Colombier ulong	now;
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier Point	datep = { 8, 6 };
757dd7cddfSDavid du Colombier Point	facep = { 8, 6+0+4 };	/* 0 updated to datefont->height in init() */
767dd7cddfSDavid du Colombier Point	enddate;			/* where date ends on display; used to place arrows */
777dd7cddfSDavid du Colombier Rectangle	leftr;			/* location of left arrow on display */
787dd7cddfSDavid du Colombier Rectangle	rightr;		/* location of right arrow on display */
79d9306527SDavid du Colombier void updatetimes(void);
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier void
827dd7cddfSDavid du Colombier setdate(void)
837dd7cddfSDavid du Colombier {
84d9306527SDavid du Colombier 	now = time(nil);
85d9306527SDavid du Colombier 	strcpy(date, ctime(now));
867dd7cddfSDavid du Colombier 	date[4+4+3+5] = '\0';	/* change from Thu Jul 22 14:28:43 EDT 1999\n to Thu Jul 22 14:28 */
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier void
907dd7cddfSDavid du Colombier init(void)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	mousefd = open("/dev/mouse", OREAD);
937dd7cddfSDavid du Colombier 	if(mousefd < 0){
947dd7cddfSDavid du Colombier 		fprint(2, "faces: can't open mouse: %r\n");
957dd7cddfSDavid du Colombier 		exits("mouse");
967dd7cddfSDavid du Colombier 	}
977dd7cddfSDavid du Colombier 	initplumb();
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier 	/* make background color */
1007dd7cddfSDavid du Colombier 	bgrnd = allocimagemix(display, DPalebluegreen, DWhite);
1019a747e4fSDavid du Colombier 	blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x008888FF);	/* blue-green */
1027dd7cddfSDavid du Colombier 	left = allocimage(display, leftright, GREY1, 0, DWhite);
1037dd7cddfSDavid du Colombier 	right = allocimage(display, leftright, GREY1, 0, DWhite);
1047dd7cddfSDavid du Colombier 	if(bgrnd==nil || blue==nil || left==nil || right==nil){
1057dd7cddfSDavid du Colombier 		fprint(2, "faces: can't create images: %r\n");
1067dd7cddfSDavid du Colombier 		exits("image");
1077dd7cddfSDavid du Colombier 	}
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	loadimage(left, leftright, leftdata, sizeof leftdata);
1107dd7cddfSDavid du Colombier 	loadimage(right, leftright, rightdata, sizeof rightdata);
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	/* initialize little fonts */
1137dd7cddfSDavid du Colombier 	tinyfont = openfont(display, "/lib/font/bit/misc/ascii.5x7.font");
1147dd7cddfSDavid du Colombier 	if(tinyfont == nil)
1157dd7cddfSDavid du Colombier 		tinyfont = font;
1167dd7cddfSDavid du Colombier 	mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
1177dd7cddfSDavid du Colombier 	if(mediumfont == nil)
1187dd7cddfSDavid du Colombier 		mediumfont = font;
1197dd7cddfSDavid du Colombier 	datefont = font;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	facep.y += datefont->height;
1227dd7cddfSDavid du Colombier 	if(datefont->height & 1)	/* stipple parity */
1237dd7cddfSDavid du Colombier 		facep.y++;
1247dd7cddfSDavid du Colombier 	faces = nil;
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier void
1287dd7cddfSDavid du Colombier drawtime(void)
1297dd7cddfSDavid du Colombier {
1307dd7cddfSDavid du Colombier 	Rectangle r;
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 	r.min = addpt(screen->r.min, datep);
1337dd7cddfSDavid du Colombier 	if(eqpt(enddate, ZP)){
1347dd7cddfSDavid du Colombier 		enddate = r.min;
1357dd7cddfSDavid du Colombier 		enddate.x += stringwidth(datefont, "Wed May 30 22:54");	/* nice wide string */
1367dd7cddfSDavid du Colombier 		enddate.x += Facesep;	/* for safety */
1377dd7cddfSDavid du Colombier 	}
1387dd7cddfSDavid du Colombier 	r.max.x = enddate.x;
1397dd7cddfSDavid du Colombier 	r.max.y = enddate.y+datefont->height;
1407dd7cddfSDavid du Colombier 	draw(screen, r, bgrnd, nil, ZP);
1417dd7cddfSDavid du Colombier 	string(screen, r.min, display->black, ZP, datefont, date);
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier void
1457dd7cddfSDavid du Colombier timeproc(void)
1467dd7cddfSDavid du Colombier {
1477dd7cddfSDavid du Colombier 	for(;;){
1487dd7cddfSDavid du Colombier 		lockdisplay(display);
1497dd7cddfSDavid du Colombier 		drawtime();
150d9306527SDavid du Colombier 		updatetimes();
1517dd7cddfSDavid du Colombier 		flushimage(display, 1);
1527dd7cddfSDavid du Colombier 		unlockdisplay(display);
1537dd7cddfSDavid du Colombier 		sleep(60000);
1547dd7cddfSDavid du Colombier 		setdate();
1557dd7cddfSDavid du Colombier 	}
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier int
159d9306527SDavid du Colombier alreadyseen(char *digest)
1607dd7cddfSDavid du Colombier {
1617dd7cddfSDavid du Colombier 	int i;
1627dd7cddfSDavid du Colombier 	Face *f;
1637dd7cddfSDavid du Colombier 
164d9306527SDavid du Colombier 	if(!digest)
1657dd7cddfSDavid du Colombier 		return 0;
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 	/* can do accurate check */
1687dd7cddfSDavid du Colombier 	for(i=0; i<nfaces; i++){
1697dd7cddfSDavid du Colombier 		f = faces[i];
1707dd7cddfSDavid du Colombier 		if(f->str[Sdigest]!=nil && strcmp(digest, f->str[Sdigest])==0)
1717dd7cddfSDavid du Colombier 			return 1;
1727dd7cddfSDavid du Colombier 	}
1737dd7cddfSDavid du Colombier 	return 0;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier int
1777dd7cddfSDavid du Colombier torune(Rune *r, char *s, int nr)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier 	int i;
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier 	for(i=0; i<nr-1 && *s!='\0'; i++)
1827dd7cddfSDavid du Colombier 		s += chartorune(r+i, s);
1837dd7cddfSDavid du Colombier 	r[i] = L'\0';
1847dd7cddfSDavid du Colombier 	return i;
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier void
1887dd7cddfSDavid du Colombier center(Font *f, Point p, char *s, Image *color)
1897dd7cddfSDavid du Colombier {
1907dd7cddfSDavid du Colombier 	int i, n, dx;
1917dd7cddfSDavid du Colombier 	Rune rbuf[32];
1927dd7cddfSDavid du Colombier 	char sbuf[32*UTFmax+1];
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier 	dx = stringwidth(f, s);
1957dd7cddfSDavid du Colombier 	if(dx > Facesize){
1967dd7cddfSDavid du Colombier 		n = torune(rbuf, s, nelem(rbuf));
1977dd7cddfSDavid du Colombier 		for(i=0; i<n; i++){
1987dd7cddfSDavid du Colombier 			dx = runestringnwidth(f, rbuf, i+1);
1997dd7cddfSDavid du Colombier 			if(dx > Facesize)
2007dd7cddfSDavid du Colombier 				break;
2017dd7cddfSDavid du Colombier 		}
2027dd7cddfSDavid du Colombier 		sprint(sbuf, "%.*S", i, rbuf);
2037dd7cddfSDavid du Colombier 		s = sbuf;
2047dd7cddfSDavid du Colombier 		dx = stringwidth(f, s);
2057dd7cddfSDavid du Colombier 	}
2067dd7cddfSDavid du Colombier 	p.x += (Facesize-dx)/2;
2077dd7cddfSDavid du Colombier 	string(screen, p, color, ZP, f, s);
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier Rectangle
2117dd7cddfSDavid du Colombier facerect(int index)	/* index is geometric; 0 is always upper left face */
2127dd7cddfSDavid du Colombier {
2137dd7cddfSDavid du Colombier 	Rectangle r;
2147dd7cddfSDavid du Colombier 	int x, y;
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier 	x = index % nacross;
2177dd7cddfSDavid du Colombier 	y = index / nacross;
2187dd7cddfSDavid du Colombier 	r.min = addpt(screen->r.min, facep);
2197dd7cddfSDavid du Colombier 	r.min.x += x*(Facesize+Facesep);
2207dd7cddfSDavid du Colombier 	r.min.y += y*(Facesize+Facesep+2*mediumfont->height);
2217dd7cddfSDavid du Colombier 	r.max = addpt(r.min, Pt(Facesize, Facesize));
2227dd7cddfSDavid du Colombier 	r.max.y += 2*mediumfont->height;
2237dd7cddfSDavid du Colombier 	/* simple fix to avoid drawing off screen, allowing customers to use position */
2247dd7cddfSDavid du Colombier 	if(index<0 || index>=nacross*ndown)
2257dd7cddfSDavid du Colombier 		r.max.x = r.min.x;
2267dd7cddfSDavid du Colombier 	return r;
2277dd7cddfSDavid du Colombier }
2287dd7cddfSDavid du Colombier 
229d9306527SDavid du Colombier static char *mon = "JanFebMarAprMayJunJulAugSepOctNovDec";
230d9306527SDavid du Colombier char*
231d9306527SDavid du Colombier facetime(Face *f, int *recent)
232d9306527SDavid du Colombier {
233d9306527SDavid du Colombier 	static char buf[30];
234d9306527SDavid du Colombier 
235fb7f0c93SDavid du Colombier 	if((long)(now - f->time) > HhmmTime){
236d9306527SDavid du Colombier 		*recent = 0;
237d9306527SDavid du Colombier 		sprint(buf, "%.3s %2d", mon+3*f->tm.mon, f->tm.mday);
238d9306527SDavid du Colombier 		return buf;
239d9306527SDavid du Colombier 	}else{
240d9306527SDavid du Colombier 		*recent = 1;
241d9306527SDavid du Colombier 		sprint(buf, "%02d:%02d", f->tm.hour, f->tm.min);
242d9306527SDavid du Colombier 		return buf;
243d9306527SDavid du Colombier 	}
244d9306527SDavid du Colombier }
245d9306527SDavid du Colombier 
2467dd7cddfSDavid du Colombier void
2477dd7cddfSDavid du Colombier drawface(Face *f, int i)
2487dd7cddfSDavid du Colombier {
249d9306527SDavid du Colombier 	char *tstr;
2507dd7cddfSDavid du Colombier 	Rectangle r;
2517dd7cddfSDavid du Colombier 	Point p;
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 	if(f == nil)
2547dd7cddfSDavid du Colombier 		return;
2557dd7cddfSDavid du Colombier 	if(i<first || i>=last)
2567dd7cddfSDavid du Colombier 		return;
2577dd7cddfSDavid du Colombier 	r = facerect(i-first);
2587dd7cddfSDavid du Colombier 	draw(screen, r, bgrnd, nil, ZP);
2597dd7cddfSDavid du Colombier 	draw(screen, r, f->bit, f->mask, ZP);
2607dd7cddfSDavid du Colombier 	r.min.y += Facesize;
2617dd7cddfSDavid du Colombier 	center(mediumfont, r.min, f->str[Suser], display->black);
2627dd7cddfSDavid du Colombier 	r.min.y += mediumfont->height;
263d9306527SDavid du Colombier 	tstr = facetime(f, &f->recent);
264d9306527SDavid du Colombier 	center(mediumfont, r.min, tstr, display->black);
2657dd7cddfSDavid du Colombier 	if(f->unknown){
2667dd7cddfSDavid du Colombier 		r.min.y -= mediumfont->height + tinyfont->height + 2;
2677dd7cddfSDavid du Colombier 		for(p.x=-1; p.x<=1; p.x++)
2687dd7cddfSDavid du Colombier 			for(p.y=-1; p.y<=1; p.y++)
2697dd7cddfSDavid du Colombier 				center(tinyfont, addpt(r.min, p), f->str[Sdomain], display->white);
2707dd7cddfSDavid du Colombier 		center(tinyfont, r.min, f->str[Sdomain], display->black);
2717dd7cddfSDavid du Colombier 	}
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier 
2747dd7cddfSDavid du Colombier void
275d9306527SDavid du Colombier updatetimes(void)
276d9306527SDavid du Colombier {
277d9306527SDavid du Colombier 	int i;
278d9306527SDavid du Colombier 	Face *f;
279d9306527SDavid du Colombier 
280d9306527SDavid du Colombier 	for(i=0; i<nfaces; i++){
281d9306527SDavid du Colombier 		f = faces[i];
282d9306527SDavid du Colombier 		if(f == nil)
283d9306527SDavid du Colombier 			continue;
284d3c05884SDavid du Colombier 		if(((long)(now - f->time) <= HhmmTime) != f->recent)
285d9306527SDavid du Colombier 			drawface(f, i);
286d9306527SDavid du Colombier 	}
287d9306527SDavid du Colombier }
288d9306527SDavid du Colombier 
289d9306527SDavid du Colombier void
2907dd7cddfSDavid du Colombier setlast(void)
2917dd7cddfSDavid du Colombier {
2927dd7cddfSDavid du Colombier 	last = first+nacross*ndown;
2937dd7cddfSDavid du Colombier 	if(last > nfaces)
2947dd7cddfSDavid du Colombier 		last = nfaces;
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
2987dd7cddfSDavid du Colombier drawarrows(void)
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier 	Point p;
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier 	p = enddate;
3037dd7cddfSDavid du Colombier 	p.x += Facesep;
3047dd7cddfSDavid du Colombier 	if(p.x & 1)
3057dd7cddfSDavid du Colombier 		p.x++;	/* align background texture */
3067dd7cddfSDavid du Colombier 	leftr = rectaddpt(leftright, p);
3077dd7cddfSDavid du Colombier 	p.x += Dx(leftright) + Facesep;
3087dd7cddfSDavid du Colombier 	rightr = rectaddpt(leftright, p);
3097dd7cddfSDavid du Colombier 	draw(screen, leftr, first>0? blue : bgrnd, left, leftright.min);
3107dd7cddfSDavid du Colombier 	draw(screen, rightr, last<nfaces? blue : bgrnd, right, leftright.min);
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier void
3147dd7cddfSDavid du Colombier addface(Face *f)	/* always adds at 0 */
3157dd7cddfSDavid du Colombier {
3167dd7cddfSDavid du Colombier 	Face **ofaces;
3177dd7cddfSDavid du Colombier 	Rectangle r0, r1, r;
3187dd7cddfSDavid du Colombier 	int y, nx, ny;
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier 	if(f == nil)
3217dd7cddfSDavid du Colombier 		return;
3227dd7cddfSDavid du Colombier 	lockdisplay(display);
3237dd7cddfSDavid du Colombier 	if(first != 0){
3247dd7cddfSDavid du Colombier 		first = 0;
3257dd7cddfSDavid du Colombier 		resized();
3267dd7cddfSDavid du Colombier 	}
3277dd7cddfSDavid du Colombier 	findbit(f);
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 	nx = nacross;
3307dd7cddfSDavid du Colombier 	ny = (nfaces+(nx-1)) / nx;
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	for(y=ny; y>=0; y--){
3337dd7cddfSDavid du Colombier 		/* move them along */
3347dd7cddfSDavid du Colombier 		r0 = facerect(y*nx+0);
3357dd7cddfSDavid du Colombier 		r1 = facerect(y*nx+1);
3367dd7cddfSDavid du Colombier 		r = r1;
3377dd7cddfSDavid du Colombier 		r.max.x = r.min.x + (nx - 1)*(Facesize+Facesep);
3387dd7cddfSDavid du Colombier 		draw(screen, r, screen, nil, r0.min);
3397dd7cddfSDavid du Colombier 		/* copy one down from row above */
3407dd7cddfSDavid du Colombier 		if(y != 0){
3417dd7cddfSDavid du Colombier 			r = facerect((y-1)*nx+nx-1);
3427dd7cddfSDavid du Colombier 			draw(screen, r0, screen, nil, r.min);
3437dd7cddfSDavid du Colombier 		}
3447dd7cddfSDavid du Colombier 	}
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier 	ofaces = faces;
3477dd7cddfSDavid du Colombier 	faces = emalloc((nfaces+1)*sizeof(Face*));
3487dd7cddfSDavid du Colombier 	memmove(faces+1, ofaces, nfaces*(sizeof(Face*)));
3497dd7cddfSDavid du Colombier 	free(ofaces);
3507dd7cddfSDavid du Colombier 	nfaces++;
3517dd7cddfSDavid du Colombier 	setlast();
3527dd7cddfSDavid du Colombier 	drawarrows();
3537dd7cddfSDavid du Colombier 	faces[0] = f;
3547dd7cddfSDavid du Colombier 	drawface(f, 0);
3557dd7cddfSDavid du Colombier 	flushimage(display, 1);
3567dd7cddfSDavid du Colombier 	unlockdisplay(display);
3577dd7cddfSDavid du Colombier }
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier void
3607dd7cddfSDavid du Colombier loadmboxfaces(char *maildir)
3617dd7cddfSDavid du Colombier {
3627dd7cddfSDavid du Colombier 	int dirfd;
3639a747e4fSDavid du Colombier 	Dir *d;
3649a747e4fSDavid du Colombier 	int i, n;
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier 	dirfd = open(maildir, OREAD);
3677dd7cddfSDavid du Colombier 	if(dirfd >= 0){
3687dd7cddfSDavid du Colombier 		chdir(maildir);
3699a747e4fSDavid du Colombier 		while((n = dirread(dirfd, &d)) > 0){
3709a747e4fSDavid du Colombier 			for(i=0; i<n; i++)
3719a747e4fSDavid du Colombier 				addface(dirface(maildir, d[i].name));
3729a747e4fSDavid du Colombier 			free(d);
3739a747e4fSDavid du Colombier 		}
3747dd7cddfSDavid du Colombier 		close(dirfd);
3757dd7cddfSDavid du Colombier 	}
3767dd7cddfSDavid du Colombier }
3777dd7cddfSDavid du Colombier 
3787dd7cddfSDavid du Colombier void
3797dd7cddfSDavid du Colombier freeface(Face *f)
3807dd7cddfSDavid du Colombier {
3817dd7cddfSDavid du Colombier 	int i;
3827dd7cddfSDavid du Colombier 
3837dd7cddfSDavid du Colombier 	if(f->file!=nil && f->bit!=f->file->image)
3847dd7cddfSDavid du Colombier 		freeimage(f->bit);
3857dd7cddfSDavid du Colombier 	freefacefile(f->file);
3867dd7cddfSDavid du Colombier 	for(i=0; i<Nstring; i++)
3877dd7cddfSDavid du Colombier 		free(f->str[i]);
3887dd7cddfSDavid du Colombier 	free(f);
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier void
3927dd7cddfSDavid du Colombier delface(int j)
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier 	Rectangle r0, r1, r;
3957dd7cddfSDavid du Colombier 	int nx, ny, x, y;
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier 	if(j < first)
3987dd7cddfSDavid du Colombier 		first--;
3997dd7cddfSDavid du Colombier 	else if(j < last){
4007dd7cddfSDavid du Colombier 		nx = nacross;
4017dd7cddfSDavid du Colombier 		ny = (nfaces+(nx-1)) / nx;
4027dd7cddfSDavid du Colombier 		x = (j-first)%nx;
4037dd7cddfSDavid du Colombier 		for(y=(j-first)/nx; y<ny; y++){
4047dd7cddfSDavid du Colombier 			if(x != nx-1){
4057dd7cddfSDavid du Colombier 				/* move them along */
4067dd7cddfSDavid du Colombier 				r0 = facerect(y*nx+x);
4077dd7cddfSDavid du Colombier 				r1 = facerect(y*nx+x+1);
4087dd7cddfSDavid du Colombier 				r = r0;
4097dd7cddfSDavid du Colombier 				r.max.x = r.min.x + (nx - x - 1)*(Facesize+Facesep);
4107dd7cddfSDavid du Colombier 				draw(screen, r, screen, nil, r1.min);
4117dd7cddfSDavid du Colombier 			}
4127dd7cddfSDavid du Colombier 			if(y != ny-1){
4137dd7cddfSDavid du Colombier 				/* copy one up from row below */
4147dd7cddfSDavid du Colombier 				r = facerect((y+1)*nx);
4157dd7cddfSDavid du Colombier 				draw(screen, facerect(y*nx+nx-1), screen, nil, r.min);
4167dd7cddfSDavid du Colombier 			}
4177dd7cddfSDavid du Colombier 			x = 0;
4187dd7cddfSDavid du Colombier 		}
4197dd7cddfSDavid du Colombier 		if(last < nfaces)	/* first off-screen becomes visible */
4207dd7cddfSDavid du Colombier 			drawface(faces[last], last-1);
4217dd7cddfSDavid du Colombier 		else{
4227dd7cddfSDavid du Colombier 			/* clear final spot */
4237dd7cddfSDavid du Colombier 			r = facerect(last-first-1);
4247dd7cddfSDavid du Colombier 			draw(screen, r, bgrnd, nil, r.min);
4257dd7cddfSDavid du Colombier 		}
4267dd7cddfSDavid du Colombier 	}
4277dd7cddfSDavid du Colombier 	freeface(faces[j]);
4287dd7cddfSDavid du Colombier 	memmove(faces+j, faces+j+1, (nfaces-(j+1))*sizeof(Face*));
4297dd7cddfSDavid du Colombier 	nfaces--;
4307dd7cddfSDavid du Colombier 	setlast();
4317dd7cddfSDavid du Colombier 	drawarrows();
4327dd7cddfSDavid du Colombier }
4337dd7cddfSDavid du Colombier 
4347dd7cddfSDavid du Colombier void
4357dd7cddfSDavid du Colombier dodelete(int i)
4367dd7cddfSDavid du Colombier {
4377dd7cddfSDavid du Colombier 	Face *f;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier 	f = faces[i];
4407dd7cddfSDavid du Colombier 	if(history){
4417dd7cddfSDavid du Colombier 		free(f->str[Sshow]);
4427dd7cddfSDavid du Colombier 		f->str[Sshow] = estrdup("");
4437dd7cddfSDavid du Colombier 	}else{
4447dd7cddfSDavid du Colombier 		delface(i);
4457dd7cddfSDavid du Colombier 		flushimage(display, 1);
4467dd7cddfSDavid du Colombier 	}
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier void
4507dd7cddfSDavid du Colombier delete(char *s, char *digest)
4517dd7cddfSDavid du Colombier {
4527dd7cddfSDavid du Colombier 	int i;
4537dd7cddfSDavid du Colombier 	Face *f;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	lockdisplay(display);
4567dd7cddfSDavid du Colombier 	for(i=0; i<nfaces; i++){
4577dd7cddfSDavid du Colombier 		f = faces[i];
4587dd7cddfSDavid du Colombier 		if(digest != nil){
4597dd7cddfSDavid du Colombier 			if(f->str[Sdigest]!=nil && strcmp(digest, f->str[Sdigest]) == 0){
4607dd7cddfSDavid du Colombier 				dodelete(i);
4617dd7cddfSDavid du Colombier 				break;
4627dd7cddfSDavid du Colombier 			}
4637dd7cddfSDavid du Colombier 		}else{
4647dd7cddfSDavid du Colombier 			if(f->str[Sshow] && strcmp(s, f->str[Sshow]) == 0){
4657dd7cddfSDavid du Colombier 				dodelete(i);
4667dd7cddfSDavid du Colombier 				break;
4677dd7cddfSDavid du Colombier 			}
4687dd7cddfSDavid du Colombier 		}
4697dd7cddfSDavid du Colombier 	}
4707dd7cddfSDavid du Colombier 	unlockdisplay(display);
4717dd7cddfSDavid du Colombier }
4727dd7cddfSDavid du Colombier 
4737dd7cddfSDavid du Colombier void
4747dd7cddfSDavid du Colombier faceproc(void)
4757dd7cddfSDavid du Colombier {
4767dd7cddfSDavid du Colombier 	for(;;)
4777dd7cddfSDavid du Colombier 		addface(nextface());
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier void
4817dd7cddfSDavid du Colombier resized(void)
4827dd7cddfSDavid du Colombier {
4837dd7cddfSDavid du Colombier 	int i;
4847dd7cddfSDavid du Colombier 
4857dd7cddfSDavid du Colombier 	nacross = (Dx(screen->r)-2*facep.x+Facesep)/(Facesize+Facesep);
4867dd7cddfSDavid du Colombier 	for(ndown=1; rectinrect(facerect(ndown*nacross), screen->r); ndown++)
4877dd7cddfSDavid du Colombier 		;
4887dd7cddfSDavid du Colombier 	setlast();
4897dd7cddfSDavid du Colombier 	draw(screen, screen->r, bgrnd, nil, ZP);
4907dd7cddfSDavid du Colombier 	enddate = ZP;
4917dd7cddfSDavid du Colombier 	drawtime();
4927dd7cddfSDavid du Colombier 	for(i=0; i<nfaces; i++)
4937dd7cddfSDavid du Colombier 		drawface(faces[i], i);
4947dd7cddfSDavid du Colombier 	drawarrows();
4957dd7cddfSDavid du Colombier 	flushimage(display, 1);
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier void
4997dd7cddfSDavid du Colombier eresized(int new)
5007dd7cddfSDavid du Colombier {
5017dd7cddfSDavid du Colombier 	lockdisplay(display);
5027dd7cddfSDavid du Colombier 	if(new && getwindow(display, Refnone) < 0) {
5037dd7cddfSDavid du Colombier 		fprint(2, "can't reattach to window\n");
5047dd7cddfSDavid du Colombier 		killall("reattach");
5057dd7cddfSDavid du Colombier 	}
5067dd7cddfSDavid du Colombier 	resized();
5077dd7cddfSDavid du Colombier 	unlockdisplay(display);
5087dd7cddfSDavid du Colombier }
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier int
5117dd7cddfSDavid du Colombier getmouse(Mouse *m)
5127dd7cddfSDavid du Colombier {
5137dd7cddfSDavid du Colombier 	int n;
5147dd7cddfSDavid du Colombier 	static int eof;
5157dd7cddfSDavid du Colombier 	char buf[128];
5167dd7cddfSDavid du Colombier 
5177dd7cddfSDavid du Colombier 	if(eof)
5187dd7cddfSDavid du Colombier 		return 0;
5197dd7cddfSDavid du Colombier 	for(;;){
5207dd7cddfSDavid du Colombier 		n = read(mousefd, buf, sizeof(buf));
5217dd7cddfSDavid du Colombier 		if(n <= 0){
5227dd7cddfSDavid du Colombier 			/* so callers needn't check return value every time */
5237dd7cddfSDavid du Colombier 			eof = 1;
5247dd7cddfSDavid du Colombier 			m->buttons = 0;
5257dd7cddfSDavid du Colombier 			return 0;
5267dd7cddfSDavid du Colombier 		}
5277dd7cddfSDavid du Colombier 		n = eatomouse(m, buf, n);
5287dd7cddfSDavid du Colombier 		if(n > 0)
5297dd7cddfSDavid du Colombier 			return 1;
5307dd7cddfSDavid du Colombier 	}
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier 
5337dd7cddfSDavid du Colombier enum
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier 	Clicksize	= 3,		/* pixels */
5367dd7cddfSDavid du Colombier };
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier int
5397dd7cddfSDavid du Colombier scroll(int but, Point p)
5407dd7cddfSDavid du Colombier {
5417dd7cddfSDavid du Colombier 	int delta;
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier 	delta = 0;
5447dd7cddfSDavid du Colombier 	lockdisplay(display);
5457dd7cddfSDavid du Colombier 	if(ptinrect(p, leftr) && first>0){
5467dd7cddfSDavid du Colombier 		if(but == 2)
5477dd7cddfSDavid du Colombier 			delta = -first;
5487dd7cddfSDavid du Colombier 		else{
5497dd7cddfSDavid du Colombier 			delta = nacross;
5507dd7cddfSDavid du Colombier 			if(delta > first)
5517dd7cddfSDavid du Colombier 				delta = first;
5527dd7cddfSDavid du Colombier 			delta = -delta;
5537dd7cddfSDavid du Colombier 		}
5547dd7cddfSDavid du Colombier 	}else if(ptinrect(p, rightr) && last<nfaces){
5557dd7cddfSDavid du Colombier 		if(but == 2)
5567dd7cddfSDavid du Colombier 			delta = (nfaces-nacross*ndown) - first;
5577dd7cddfSDavid du Colombier 		else{
5587dd7cddfSDavid du Colombier 			delta = nacross;
5597dd7cddfSDavid du Colombier 			if(delta > nfaces-last)
5607dd7cddfSDavid du Colombier 				delta = nfaces-last;
5617dd7cddfSDavid du Colombier 		}
5627dd7cddfSDavid du Colombier 	}
5637dd7cddfSDavid du Colombier 	first += delta;
5647dd7cddfSDavid du Colombier 	last += delta;
5657dd7cddfSDavid du Colombier 	unlockdisplay(display);
5667dd7cddfSDavid du Colombier 	if(delta)
5677dd7cddfSDavid du Colombier 		eresized(0);
5687dd7cddfSDavid du Colombier 	return delta;
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier 
5717dd7cddfSDavid du Colombier void
5727dd7cddfSDavid du Colombier click(int button, Mouse *m)
5737dd7cddfSDavid du Colombier {
5747dd7cddfSDavid du Colombier 	Point p;
5757dd7cddfSDavid du Colombier 	int i;
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier 	p = m->xy;
5787dd7cddfSDavid du Colombier 	while(m->buttons == (1<<(button-1)))
5797dd7cddfSDavid du Colombier 		getmouse(m);
5807dd7cddfSDavid du Colombier 	if(m->buttons)
5817dd7cddfSDavid du Colombier 		return;
5827dd7cddfSDavid du Colombier 	if(abs(p.x-m->xy.x)>Clicksize || abs(p.y-m->xy.y)>Clicksize)
5837dd7cddfSDavid du Colombier 		return;
5847dd7cddfSDavid du Colombier 	switch(button){
5857dd7cddfSDavid du Colombier 	case 1:
5867dd7cddfSDavid du Colombier 		if(scroll(1, p))
5877dd7cddfSDavid du Colombier 			break;
5887dd7cddfSDavid du Colombier 		if(history){
5897dd7cddfSDavid du Colombier 			/* click clears display */
5907dd7cddfSDavid du Colombier 			lockdisplay(display);
5917dd7cddfSDavid du Colombier 			for(i=0; i<nfaces; i++)
5927dd7cddfSDavid du Colombier 				freeface(faces[i]);
5937dd7cddfSDavid du Colombier 			free(faces);
5947dd7cddfSDavid du Colombier 			faces=nil;
5957dd7cddfSDavid du Colombier 			nfaces = 0;
5967dd7cddfSDavid du Colombier 			unlockdisplay(display);
5977dd7cddfSDavid du Colombier 			eresized(0);
5987dd7cddfSDavid du Colombier 			return;
5997dd7cddfSDavid du Colombier 		}else{
6007dd7cddfSDavid du Colombier 			for(i=first; i<last; i++)	/* clear vwhois faces */
6017dd7cddfSDavid du Colombier 				if(ptinrect(p, facerect(i-first))
602*d9d5974cSDavid du Colombier 				&& strstr(faces[i]->str[Sshow], "/XXXvwhois")){
6037dd7cddfSDavid du Colombier 					delface(i);
6047dd7cddfSDavid du Colombier 					flushimage(display, 1);
6057dd7cddfSDavid du Colombier 				}
6067dd7cddfSDavid du Colombier 		}
6077dd7cddfSDavid du Colombier 		break;
6087dd7cddfSDavid du Colombier 	case 2:
6097dd7cddfSDavid du Colombier 		scroll(2, p);
6107dd7cddfSDavid du Colombier 		break;
6117dd7cddfSDavid du Colombier 	case 3:
6127dd7cddfSDavid du Colombier 		scroll(3, p);
6137dd7cddfSDavid du Colombier 		lockdisplay(display);
6147dd7cddfSDavid du Colombier 		for(i=first; i<last; i++)
6157dd7cddfSDavid du Colombier 			if(ptinrect(p, facerect(i-first))){
6167dd7cddfSDavid du Colombier 				showmail(faces[i]);
6177dd7cddfSDavid du Colombier 				break;
6187dd7cddfSDavid du Colombier 			}
6197dd7cddfSDavid du Colombier 		unlockdisplay(display);
6207dd7cddfSDavid du Colombier 		break;
6217dd7cddfSDavid du Colombier 	}
6227dd7cddfSDavid du Colombier }
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier void
6257dd7cddfSDavid du Colombier mouseproc(void)
6267dd7cddfSDavid du Colombier {
6277dd7cddfSDavid du Colombier 	Mouse mouse;
6287dd7cddfSDavid du Colombier 
6297dd7cddfSDavid du Colombier 	while(getmouse(&mouse)){
6307dd7cddfSDavid du Colombier 		if(mouse.buttons == 1)
6317dd7cddfSDavid du Colombier 			click(1, &mouse);
6327dd7cddfSDavid du Colombier 		else if(mouse.buttons == 2)
6337dd7cddfSDavid du Colombier 			click(2, &mouse);
6347dd7cddfSDavid du Colombier 		else if(mouse.buttons == 4)
6357dd7cddfSDavid du Colombier 			click(3, &mouse);
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier 		while(mouse.buttons)
6387dd7cddfSDavid du Colombier 			getmouse(&mouse);
6397dd7cddfSDavid du Colombier 	}
6407dd7cddfSDavid du Colombier }
6417dd7cddfSDavid du Colombier 
6427dd7cddfSDavid du Colombier void
6437dd7cddfSDavid du Colombier killall(char *s)
6447dd7cddfSDavid du Colombier {
6457dd7cddfSDavid du Colombier 	int i, pid;
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier 	pid = getpid();
6487dd7cddfSDavid du Colombier 	for(i=0; i<NPROC; i++)
6497dd7cddfSDavid du Colombier 		if(pids[i] && pids[i]!=pid)
6507dd7cddfSDavid du Colombier 			postnote(PNPROC, pids[i], "kill");
6517dd7cddfSDavid du Colombier 	exits(s);
6527dd7cddfSDavid du Colombier }
6537dd7cddfSDavid du Colombier 
6547dd7cddfSDavid du Colombier void
6557dd7cddfSDavid du Colombier startproc(void (*f)(void), int index)
6567dd7cddfSDavid du Colombier {
6577dd7cddfSDavid du Colombier 	int pid;
6587dd7cddfSDavid du Colombier 
6597dd7cddfSDavid du Colombier 	switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
6607dd7cddfSDavid du Colombier 	case -1:
6617dd7cddfSDavid du Colombier 		fprint(2, "faces: fork failed: %r\n");
6627dd7cddfSDavid du Colombier 		killall("fork failed");
6637dd7cddfSDavid du Colombier 	case 0:
6647dd7cddfSDavid du Colombier 		f();
6657dd7cddfSDavid du Colombier 		fprint(2, "faces: %s process exits\n", procnames[index]);
6667dd7cddfSDavid du Colombier 		if(index >= 0)
6677dd7cddfSDavid du Colombier 			killall("process died");
6687dd7cddfSDavid du Colombier 		exits(nil);
6697dd7cddfSDavid du Colombier 	}
6707dd7cddfSDavid du Colombier 	if(index >= 0)
6717dd7cddfSDavid du Colombier 		pids[index] = pid;
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier void
6755fab9909SDavid du Colombier usage(void)
6765fab9909SDavid du Colombier {
677*d9d5974cSDavid du Colombier 	fprint(2, "usage: faces [-hi] [-m maildir]\n");
6785fab9909SDavid du Colombier 	exits("usage");
6795fab9909SDavid du Colombier }
6805fab9909SDavid du Colombier 
6815fab9909SDavid du Colombier void
6827dd7cddfSDavid du Colombier main(int argc, char *argv[])
6837dd7cddfSDavid du Colombier {
684a3b78ba5SDavid du Colombier 	int i;
685a3b78ba5SDavid du Colombier 
6867dd7cddfSDavid du Colombier 	ARGBEGIN{
6877dd7cddfSDavid du Colombier 	case 'h':
6887dd7cddfSDavid du Colombier 		history++;
6897dd7cddfSDavid du Colombier 		break;
6907dd7cddfSDavid du Colombier 	case 'i':
6917dd7cddfSDavid du Colombier 		initload++;
6927dd7cddfSDavid du Colombier 		break;
6935fab9909SDavid du Colombier 	case 'm':
6945fab9909SDavid du Colombier 		addmaildir(EARGF(usage()));
695a3b78ba5SDavid du Colombier 		maildir = nil;
6965fab9909SDavid du Colombier 		break;
6977dd7cddfSDavid du Colombier 	default:
6985fab9909SDavid du Colombier 		usage();
6997dd7cddfSDavid du Colombier 	}ARGEND
7007dd7cddfSDavid du Colombier 
7017dd7cddfSDavid du Colombier 	if(initdraw(nil, nil, "faces") < 0){
7027dd7cddfSDavid du Colombier 		fprint(2, "faces: initdraw failed: %r\n");
7037dd7cddfSDavid du Colombier 		exits("initdraw");
7047dd7cddfSDavid du Colombier 	}
705a3b78ba5SDavid du Colombier 	if(maildir)
706a3b78ba5SDavid du Colombier 		addmaildir(maildir);
7077dd7cddfSDavid du Colombier 	init();
7087dd7cddfSDavid du Colombier 	unlockdisplay(display);	/* initdraw leaves it locked */
7097dd7cddfSDavid du Colombier 	display->locking = 1;	/* tell library we're using the display lock */
7107dd7cddfSDavid du Colombier 	setdate();
7117dd7cddfSDavid du Colombier 	eresized(0);
7127dd7cddfSDavid du Colombier 
7137dd7cddfSDavid du Colombier 	pids[Mainp] = getpid();
7147dd7cddfSDavid du Colombier 	startproc(timeproc, Timep);
7157dd7cddfSDavid du Colombier 	startproc(mouseproc, Mousep);
7167dd7cddfSDavid du Colombier 	if(initload)
717a3b78ba5SDavid du Colombier 		for(i = 0; i < nmaildirs; i++)
718a3b78ba5SDavid du Colombier 		 loadmboxfaces(maildirs[i]);
7197dd7cddfSDavid du Colombier 	faceproc();
7207dd7cddfSDavid du Colombier 	fprint(2, "faces: %s process exits\n", procnames[Mainp]);
7217dd7cddfSDavid du Colombier 	killall(nil);
7227dd7cddfSDavid du Colombier }
723