xref: /plan9/sys/src/cmd/acme/acme.c (revision 4aeffbf5869a066cad266dfda04e87c99bacbc21)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
57dd7cddfSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <plumb.h>
117dd7cddfSDavid du Colombier #include "dat.h"
127dd7cddfSDavid du Colombier #include "fns.h"
1359cc4ca5SDavid du Colombier 	/* for generating syms in mkfile only: */
1459cc4ca5SDavid du Colombier 	#include <bio.h>
1559cc4ca5SDavid du Colombier 	#include "edit.h"
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier void	mousethread(void*);
187dd7cddfSDavid du Colombier void	keyboardthread(void*);
197dd7cddfSDavid du Colombier void	waitthread(void*);
207dd7cddfSDavid du Colombier void	xfidallocthread(void*);
219a747e4fSDavid du Colombier void	newwindowthread(void*);
227dd7cddfSDavid du Colombier void plumbproc(void*);
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier Reffont	**fontcache;
257dd7cddfSDavid du Colombier int		nfontcache;
267dd7cddfSDavid du Colombier char		wdir[512] = ".";
277dd7cddfSDavid du Colombier Reffont	*reffonts[2];
287dd7cddfSDavid du Colombier int		snarffd = -1;
297dd7cddfSDavid du Colombier int		mainpid;
307dd7cddfSDavid du Colombier int		plumbsendfd;
317dd7cddfSDavid du Colombier int		plumbeditfd;
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier enum{
347dd7cddfSDavid du Colombier 	NSnarf = 1000	/* less than 1024, I/O buffer size */
357dd7cddfSDavid du Colombier };
367dd7cddfSDavid du Colombier Rune	snarfrune[NSnarf+1];
377dd7cddfSDavid du Colombier 
38afb30c3eSDavid du Colombier char		*fontnames[2] =
39afb30c3eSDavid du Colombier {
40afb30c3eSDavid du Colombier 	"/lib/font/bit/lucidasans/euro.8.font",
41afb30c3eSDavid du Colombier 	"/lib/font/bit/lucm/unicode.9.font"
42afb30c3eSDavid du Colombier };
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier Command *command;
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier void	acmeerrorinit(void);
477dd7cddfSDavid du Colombier void	readfile(Column*, char*);
487dd7cddfSDavid du Colombier int	shutdown(void*, char*);
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier void
derror(Display *,char * errorstr)517dd7cddfSDavid du Colombier derror(Display*, char *errorstr)
527dd7cddfSDavid du Colombier {
537dd7cddfSDavid du Colombier 	error(errorstr);
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier void
threadmain(int argc,char * argv[])577dd7cddfSDavid du Colombier threadmain(int argc, char *argv[])
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier 	int i;
607dd7cddfSDavid du Colombier 	char *p, *loadfile;
617dd7cddfSDavid du Colombier 	char buf[256];
627dd7cddfSDavid du Colombier 	Column *c;
637dd7cddfSDavid du Colombier 	int ncol;
647dd7cddfSDavid du Colombier 	Display *d;
657dd7cddfSDavid du Colombier 	static void *arg[1];
667dd7cddfSDavid du Colombier 
6780ee5cbfSDavid du Colombier 	rfork(RFENVG|RFNAMEG);
6880ee5cbfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	ncol = -1;
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 	loadfile = nil;
727dd7cddfSDavid du Colombier 	ARGBEGIN{
734fec87e5SDavid du Colombier 	case 'a':
744fec87e5SDavid du Colombier 		globalautoindent = TRUE;
754fec87e5SDavid du Colombier 		break;
767dd7cddfSDavid du Colombier 	case 'b':
777dd7cddfSDavid du Colombier 		bartflag = TRUE;
787dd7cddfSDavid du Colombier 		break;
797dd7cddfSDavid du Colombier 	case 'c':
807dd7cddfSDavid du Colombier 		p = ARGF();
817dd7cddfSDavid du Colombier 		if(p == nil)
827dd7cddfSDavid du Colombier 			goto Usage;
837dd7cddfSDavid du Colombier 		ncol = atoi(p);
847dd7cddfSDavid du Colombier 		if(ncol <= 0)
857dd7cddfSDavid du Colombier 			goto Usage;
867dd7cddfSDavid du Colombier 		break;
877dd7cddfSDavid du Colombier 	case 'f':
88afb30c3eSDavid du Colombier 		fontnames[0] = ARGF();
89afb30c3eSDavid du Colombier 		if(fontnames[0] == nil)
907dd7cddfSDavid du Colombier 			goto Usage;
917dd7cddfSDavid du Colombier 		break;
927dd7cddfSDavid du Colombier 	case 'F':
93afb30c3eSDavid du Colombier 		fontnames[1] = ARGF();
94afb30c3eSDavid du Colombier 		if(fontnames[1] == nil)
957dd7cddfSDavid du Colombier 			goto Usage;
967dd7cddfSDavid du Colombier 		break;
977dd7cddfSDavid du Colombier 	case 'l':
987dd7cddfSDavid du Colombier 		loadfile = ARGF();
997dd7cddfSDavid du Colombier 		if(loadfile == nil)
1007dd7cddfSDavid du Colombier 			goto Usage;
1017dd7cddfSDavid du Colombier 		break;
1027dd7cddfSDavid du Colombier 	default:
1037dd7cddfSDavid du Colombier 	Usage:
104*4aeffbf5SDavid du Colombier 		fprint(2, "usage: acme [-ab] [-c ncol] [-f font] [-F fixedfont] [-l loadfile | file...]\n");
1057dd7cddfSDavid du Colombier 		exits("usage");
1067dd7cddfSDavid du Colombier 	}ARGEND
1077dd7cddfSDavid du Colombier 
108afb30c3eSDavid du Colombier 	fontnames[0] = estrdup(fontnames[0]);
109afb30c3eSDavid du Colombier 	fontnames[1] = estrdup(fontnames[1]);
110afb30c3eSDavid du Colombier 
111b8661318SDavid du Colombier 	quotefmtinstall();
1127dd7cddfSDavid du Colombier 	cputype = getenv("cputype");
1137dd7cddfSDavid du Colombier 	objtype = getenv("objtype");
1147dd7cddfSDavid du Colombier 	home = getenv("home");
1157dd7cddfSDavid du Colombier 	p = getenv("tabstop");
11659cc4ca5SDavid du Colombier 	if(p != nil){
1177dd7cddfSDavid du Colombier 		maxtab = strtoul(p, nil, 0);
11859cc4ca5SDavid du Colombier 		free(p);
11959cc4ca5SDavid du Colombier 	}
1207dd7cddfSDavid du Colombier 	if(maxtab == 0)
1217dd7cddfSDavid du Colombier 		maxtab = 4;
1229a747e4fSDavid du Colombier 	if(loadfile)
1239a747e4fSDavid du Colombier 		rowloadfonts(loadfile);
1247dd7cddfSDavid du Colombier 	putenv("font", fontnames[0]);
1257dd7cddfSDavid du Colombier 	snarffd = open("/dev/snarf", OREAD|OCEXEC);
1267dd7cddfSDavid du Colombier 	if(cputype){
1277dd7cddfSDavid du Colombier 		sprint(buf, "/acme/bin/%s", cputype);
1287dd7cddfSDavid du Colombier 		bind(buf, "/bin", MBEFORE);
1297dd7cddfSDavid du Colombier 	}
1307dd7cddfSDavid du Colombier 	bind("/acme/bin", "/bin", MBEFORE);
1317dd7cddfSDavid du Colombier 	getwd(wdir, sizeof wdir);
1327dd7cddfSDavid du Colombier 
1339a747e4fSDavid du Colombier 	if(geninitdraw(nil, derror, fontnames[0], "acme", nil, Refnone) < 0){
1347dd7cddfSDavid du Colombier 		fprint(2, "acme: can't open display: %r\n");
1359a747e4fSDavid du Colombier 		exits("geninitdraw");
1367dd7cddfSDavid du Colombier 	}
1377dd7cddfSDavid du Colombier 	d = display;
1387dd7cddfSDavid du Colombier 	font = d->defaultfont;
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 	reffont.f = font;
1417dd7cddfSDavid du Colombier 	reffonts[0] = &reffont;
1427dd7cddfSDavid du Colombier 	incref(&reffont);	/* one to hold up 'font' variable */
1437dd7cddfSDavid du Colombier 	incref(&reffont);	/* one to hold up reffonts[0] */
1447dd7cddfSDavid du Colombier 	fontcache = emalloc(sizeof(Reffont*));
1457dd7cddfSDavid du Colombier 	nfontcache = 1;
1467dd7cddfSDavid du Colombier 	fontcache[0] = &reffont;
1477dd7cddfSDavid du Colombier 
1487dd7cddfSDavid du Colombier 	iconinit();
1497dd7cddfSDavid du Colombier 	timerinit();
1507dd7cddfSDavid du Colombier 	rxinit();
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	cwait = threadwaitchan();
1537dd7cddfSDavid du Colombier 	ccommand = chancreate(sizeof(Command**), 0);
1547dd7cddfSDavid du Colombier 	ckill = chancreate(sizeof(Rune*), 0);
1557dd7cddfSDavid du Colombier 	cxfidalloc = chancreate(sizeof(Xfid*), 0);
1567dd7cddfSDavid du Colombier 	cxfidfree = chancreate(sizeof(Xfid*), 0);
1579a747e4fSDavid du Colombier 	cnewwindow = chancreate(sizeof(Channel*), 0);
1587dd7cddfSDavid du Colombier 	cerr = chancreate(sizeof(char*), 0);
15959cc4ca5SDavid du Colombier 	cedit = chancreate(sizeof(int), 0);
1607dd7cddfSDavid du Colombier 	cexit = chancreate(sizeof(int), 0);
1615316891fSDavid du Colombier 	cwarn = chancreate(sizeof(void*), 1);
1625316891fSDavid du Colombier 	if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil || cwarn==nil){
1637dd7cddfSDavid du Colombier 		fprint(2, "acme: can't create initial channels: %r\n");
1647dd7cddfSDavid du Colombier 		exits("channels");
1657dd7cddfSDavid du Colombier 	}
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 	mousectl = initmouse(nil, screen);
1687dd7cddfSDavid du Colombier 	if(mousectl == nil){
1697dd7cddfSDavid du Colombier 		fprint(2, "acme: can't initialize mouse: %r\n");
1707dd7cddfSDavid du Colombier 		exits("mouse");
1717dd7cddfSDavid du Colombier 	}
1727dd7cddfSDavid du Colombier 	mouse = mousectl;
1737dd7cddfSDavid du Colombier 	keyboardctl = initkeyboard(nil);
1747dd7cddfSDavid du Colombier 	if(keyboardctl == nil){
1757dd7cddfSDavid du Colombier 		fprint(2, "acme: can't initialize keyboard: %r\n");
1767dd7cddfSDavid du Colombier 		exits("keyboard");
1777dd7cddfSDavid du Colombier 	}
1787dd7cddfSDavid du Colombier 	mainpid = getpid();
1797dd7cddfSDavid du Colombier 	plumbeditfd = plumbopen("edit", OREAD|OCEXEC);
1807dd7cddfSDavid du Colombier 	if(plumbeditfd >= 0){
1817dd7cddfSDavid du Colombier 		cplumb = chancreate(sizeof(Plumbmsg*), 0);
1827dd7cddfSDavid du Colombier 		proccreate(plumbproc, nil, STACK);
1837dd7cddfSDavid du Colombier 	}
1847dd7cddfSDavid du Colombier 	plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	fsysinit();
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 	#define	WPERCOL	8
1897dd7cddfSDavid du Colombier 	disk = diskinit();
1904b30ca09SDavid du Colombier 	if(!loadfile || !rowload(&row, loadfile, TRUE)){
1917dd7cddfSDavid du Colombier 		rowinit(&row, screen->clipr);
1927dd7cddfSDavid du Colombier 		if(ncol < 0){
1937dd7cddfSDavid du Colombier 			if(argc == 0)
1947dd7cddfSDavid du Colombier 				ncol = 2;
1957dd7cddfSDavid du Colombier 			else{
1967dd7cddfSDavid du Colombier 				ncol = (argc+(WPERCOL-1))/WPERCOL;
1977dd7cddfSDavid du Colombier 				if(ncol < 2)
1987dd7cddfSDavid du Colombier 					ncol = 2;
1997dd7cddfSDavid du Colombier 			}
2007dd7cddfSDavid du Colombier 		}
2017dd7cddfSDavid du Colombier 		if(ncol == 0)
2027dd7cddfSDavid du Colombier 			ncol = 2;
2037dd7cddfSDavid du Colombier 		for(i=0; i<ncol; i++){
2047dd7cddfSDavid du Colombier 			c = rowadd(&row, nil, -1);
2057dd7cddfSDavid du Colombier 			if(c==nil && i==0)
2067dd7cddfSDavid du Colombier 				error("initializing columns");
2077dd7cddfSDavid du Colombier 		}
2087dd7cddfSDavid du Colombier 		c = row.col[row.ncol-1];
2097dd7cddfSDavid du Colombier 		if(argc == 0)
2107dd7cddfSDavid du Colombier 			readfile(c, wdir);
2117dd7cddfSDavid du Colombier 		else
2127dd7cddfSDavid du Colombier 			for(i=0; i<argc; i++){
2137dd7cddfSDavid du Colombier 				p = utfrrune(argv[i], '/');
2147dd7cddfSDavid du Colombier 				if((p!=nil && strcmp(p, "/guide")==0) || i/WPERCOL>=row.ncol)
2157dd7cddfSDavid du Colombier 					readfile(c, argv[i]);
2167dd7cddfSDavid du Colombier 				else
2177dd7cddfSDavid du Colombier 					readfile(row.col[i/WPERCOL], argv[i]);
2187dd7cddfSDavid du Colombier 			}
2197dd7cddfSDavid du Colombier 	}
2207dd7cddfSDavid du Colombier 	flushimage(display, 1);
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 	acmeerrorinit();
2237dd7cddfSDavid du Colombier 	threadcreate(keyboardthread, nil, STACK);
2247dd7cddfSDavid du Colombier 	threadcreate(mousethread, nil, STACK);
2257dd7cddfSDavid du Colombier 	threadcreate(waitthread, nil, STACK);
2267dd7cddfSDavid du Colombier 	threadcreate(xfidallocthread, nil, STACK);
2279a747e4fSDavid du Colombier 	threadcreate(newwindowthread, nil, STACK);
2287dd7cddfSDavid du Colombier 
2299a747e4fSDavid du Colombier 	threadnotify(shutdown, 1);
2307dd7cddfSDavid du Colombier 	recvul(cexit);
2317dd7cddfSDavid du Colombier 	killprocs();
2327dd7cddfSDavid du Colombier 	threadexitsall(nil);
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier void
readfile(Column * c,char * s)2367dd7cddfSDavid du Colombier readfile(Column *c, char *s)
2377dd7cddfSDavid du Colombier {
2387dd7cddfSDavid du Colombier 	Window *w;
2397dd7cddfSDavid du Colombier 	Rune rb[256];
2407dd7cddfSDavid du Colombier 	int nb, nr;
2417dd7cddfSDavid du Colombier 	Runestr rs;
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier 	w = coladd(c, nil, nil, -1);
2447dd7cddfSDavid du Colombier 	cvttorunes(s, strlen(s), rb, &nb, &nr, nil);
2457dd7cddfSDavid du Colombier 	rs = cleanrname((Runestr){rb, nr});
2467dd7cddfSDavid du Colombier 	winsetname(w, rs.r, rs.nr);
2477dd7cddfSDavid du Colombier 	textload(&w->body, 0, s, 1);
2487dd7cddfSDavid du Colombier 	w->body.file->mod = FALSE;
2497dd7cddfSDavid du Colombier 	w->dirty = FALSE;
2507dd7cddfSDavid du Colombier 	winsettag(w);
2517dd7cddfSDavid du Colombier 	textscrdraw(&w->body);
2527dd7cddfSDavid du Colombier 	textsetselect(&w->tag, w->tag.file->nc, w->tag.file->nc);
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier char *oknotes[] ={
2567dd7cddfSDavid du Colombier 	"delete",
2577dd7cddfSDavid du Colombier 	"hangup",
2587dd7cddfSDavid du Colombier 	"kill",
2597dd7cddfSDavid du Colombier 	"exit",
2607dd7cddfSDavid du Colombier 	nil
2617dd7cddfSDavid du Colombier };
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier int	dumping;
2647dd7cddfSDavid du Colombier 
2659a747e4fSDavid du Colombier int
shutdown(void *,char * msg)2669a747e4fSDavid du Colombier shutdown(void*, char *msg)
2677dd7cddfSDavid du Colombier {
2687dd7cddfSDavid du Colombier 	int i;
2697dd7cddfSDavid du Colombier 
2707dd7cddfSDavid du Colombier 	killprocs();
2719a747e4fSDavid du Colombier 	if(!dumping && strcmp(msg, "kill")!=0 && strcmp(msg, "exit")!=0 && getpid()==mainpid){
2727dd7cddfSDavid du Colombier 		dumping = TRUE;
2737dd7cddfSDavid du Colombier 		rowdump(&row, nil);
2747dd7cddfSDavid du Colombier 	}
2757dd7cddfSDavid du Colombier 	for(i=0; oknotes[i]; i++)
2767dd7cddfSDavid du Colombier 		if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0)
2777dd7cddfSDavid du Colombier 			threadexitsall(msg);
2787dd7cddfSDavid du Colombier 	print("acme: %s\n", msg);
2797dd7cddfSDavid du Colombier 	abort();
2809a747e4fSDavid du Colombier 	return 0;
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier 
2837dd7cddfSDavid du Colombier void
killprocs(void)2847dd7cddfSDavid du Colombier killprocs(void)
2857dd7cddfSDavid du Colombier {
2867dd7cddfSDavid du Colombier 	Command *c;
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier 	fsysclose();
2899a747e4fSDavid du Colombier //	if(display)
2909a747e4fSDavid du Colombier //		flushimage(display, 1);
2917dd7cddfSDavid du Colombier 
2927dd7cddfSDavid du Colombier 	for(c=command; c; c=c->next)
2937dd7cddfSDavid du Colombier 		postnote(PNGROUP, c->pid, "hangup");
2947dd7cddfSDavid du Colombier 	remove(acmeerrorfile);
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier static int errorfd;
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier void
acmeerrorproc(void *)3007dd7cddfSDavid du Colombier acmeerrorproc(void *)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier 	char *buf;
3037dd7cddfSDavid du Colombier 	int n;
3047dd7cddfSDavid du Colombier 
3057dd7cddfSDavid du Colombier 	threadsetname("acmeerrorproc");
3067dd7cddfSDavid du Colombier 	buf = emalloc(8192+1);
3077dd7cddfSDavid du Colombier 	while((n=read(errorfd, buf, 8192)) >= 0){
3087dd7cddfSDavid du Colombier 		buf[n] = '\0';
30959cc4ca5SDavid du Colombier 		sendp(cerr, estrdup(buf));
3107dd7cddfSDavid du Colombier 	}
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier void
acmeerrorinit(void)3147dd7cddfSDavid du Colombier acmeerrorinit(void)
3157dd7cddfSDavid du Colombier {
3167dd7cddfSDavid du Colombier 	int fd, pfd[2];
3177dd7cddfSDavid du Colombier 	char buf[64];
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	if(pipe(pfd) < 0)
3207dd7cddfSDavid du Colombier 		error("can't create pipe");
3217dd7cddfSDavid du Colombier 	sprint(acmeerrorfile, "/srv/acme.%s.%d", getuser(), mainpid);
3227dd7cddfSDavid du Colombier 	fd = create(acmeerrorfile, OWRITE, 0666);
3237dd7cddfSDavid du Colombier 	if(fd < 0){
32459cc4ca5SDavid du Colombier 		remove(acmeerrorfile);
3257dd7cddfSDavid du Colombier   		fd = create(acmeerrorfile, OWRITE, 0666);
3267dd7cddfSDavid du Colombier 		if(fd < 0)
3277dd7cddfSDavid du Colombier 			error("can't create acmeerror file");
3287dd7cddfSDavid du Colombier 	}
3297dd7cddfSDavid du Colombier 	sprint(buf, "%d", pfd[0]);
3307dd7cddfSDavid du Colombier 	write(fd, buf, strlen(buf));
3317dd7cddfSDavid du Colombier 	close(fd);
3327dd7cddfSDavid du Colombier 	/* reopen pfd[1] close on exec */
3337dd7cddfSDavid du Colombier 	sprint(buf, "/fd/%d", pfd[1]);
3347dd7cddfSDavid du Colombier 	errorfd = open(buf, OREAD|OCEXEC);
3357dd7cddfSDavid du Colombier 	if(errorfd < 0)
3367dd7cddfSDavid du Colombier 		error("can't re-open acmeerror file");
3377dd7cddfSDavid du Colombier 	close(pfd[1]);
3387dd7cddfSDavid du Colombier 	close(pfd[0]);
3397dd7cddfSDavid du Colombier 	proccreate(acmeerrorproc, nil, STACK);
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier void
plumbproc(void *)3437dd7cddfSDavid du Colombier plumbproc(void *)
3447dd7cddfSDavid du Colombier {
3457dd7cddfSDavid du Colombier 	Plumbmsg *m;
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 	threadsetname("plumbproc");
3487dd7cddfSDavid du Colombier 	for(;;){
3497dd7cddfSDavid du Colombier 		m = plumbrecv(plumbeditfd);
3507dd7cddfSDavid du Colombier 		if(m == nil)
3517dd7cddfSDavid du Colombier 			threadexits(nil);
3527dd7cddfSDavid du Colombier 		sendp(cplumb, m);
3537dd7cddfSDavid du Colombier 	}
3547dd7cddfSDavid du Colombier }
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier void
keyboardthread(void *)3577dd7cddfSDavid du Colombier keyboardthread(void *)
3587dd7cddfSDavid du Colombier {
3597dd7cddfSDavid du Colombier 	Rune r;
3607dd7cddfSDavid du Colombier 	Timer *timer;
3617dd7cddfSDavid du Colombier 	Text *t;
3627dd7cddfSDavid du Colombier 	enum { KTimer, KKey, NKALT };
3637dd7cddfSDavid du Colombier 	static Alt alts[NKALT+1];
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 	alts[KTimer].c = nil;
3667dd7cddfSDavid du Colombier 	alts[KTimer].v = nil;
3677dd7cddfSDavid du Colombier 	alts[KTimer].op = CHANNOP;
3687dd7cddfSDavid du Colombier 	alts[KKey].c = keyboardctl->c;
3697dd7cddfSDavid du Colombier 	alts[KKey].v = &r;
3707dd7cddfSDavid du Colombier 	alts[KKey].op = CHANRCV;
3717dd7cddfSDavid du Colombier 	alts[NKALT].op = CHANEND;
3727dd7cddfSDavid du Colombier 
3737dd7cddfSDavid du Colombier 	timer = nil;
3747dd7cddfSDavid du Colombier 	typetext = nil;
3757dd7cddfSDavid du Colombier 	threadsetname("keyboardthread");
3767dd7cddfSDavid du Colombier 	for(;;){
3777dd7cddfSDavid du Colombier 		switch(alt(alts)){
3787dd7cddfSDavid du Colombier 		case KTimer:
3797dd7cddfSDavid du Colombier 			timerstop(timer);
3807dd7cddfSDavid du Colombier 			t = typetext;
3817dd7cddfSDavid du Colombier 			if(t!=nil && t->what==Tag){
3827dd7cddfSDavid du Colombier 				winlock(t->w, 'K');
3837dd7cddfSDavid du Colombier 				wincommit(t->w, t);
3847dd7cddfSDavid du Colombier 				winunlock(t->w);
3857dd7cddfSDavid du Colombier 				flushimage(display, 1);
3867dd7cddfSDavid du Colombier 			}
3877dd7cddfSDavid du Colombier 			alts[KTimer].c = nil;
3887dd7cddfSDavid du Colombier 			alts[KTimer].op = CHANNOP;
3897dd7cddfSDavid du Colombier 			break;
3907dd7cddfSDavid du Colombier 		case KKey:
3917dd7cddfSDavid du Colombier 		casekeyboard:
3927dd7cddfSDavid du Colombier 			typetext = rowtype(&row, r, mouse->xy);
3937dd7cddfSDavid du Colombier 			t = typetext;
3949a747e4fSDavid du Colombier 			if(t!=nil && t->col!=nil && !(r==Kdown || r==Kleft || r==Kright))	/* scrolling doesn't change activecol */
3957dd7cddfSDavid du Colombier 				activecol = t->col;
3967dd7cddfSDavid du Colombier 			if(t!=nil && t->w!=nil)
3977dd7cddfSDavid du Colombier 				t->w->body.file->curtext = &t->w->body;
3987dd7cddfSDavid du Colombier 			if(timer != nil)
3997dd7cddfSDavid du Colombier 				timercancel(timer);
4007dd7cddfSDavid du Colombier 			if(t!=nil && t->what==Tag) {
4017dd7cddfSDavid du Colombier 				timer = timerstart(500);
4027dd7cddfSDavid du Colombier 				alts[KTimer].c = timer->c;
4037dd7cddfSDavid du Colombier 				alts[KTimer].op = CHANRCV;
4047dd7cddfSDavid du Colombier 			}else{
4057dd7cddfSDavid du Colombier 				timer = nil;
4067dd7cddfSDavid du Colombier 				alts[KTimer].c = nil;
4077dd7cddfSDavid du Colombier 				alts[KTimer].op = CHANNOP;
4087dd7cddfSDavid du Colombier 			}
4097dd7cddfSDavid du Colombier 			if(nbrecv(keyboardctl->c, &r) > 0)
4107dd7cddfSDavid du Colombier 				goto casekeyboard;
4117dd7cddfSDavid du Colombier 			flushimage(display, 1);
4127dd7cddfSDavid du Colombier 			break;
4137dd7cddfSDavid du Colombier 		}
4147dd7cddfSDavid du Colombier 	}
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier void
mousethread(void *)4187dd7cddfSDavid du Colombier mousethread(void *)
4197dd7cddfSDavid du Colombier {
4207dd7cddfSDavid du Colombier 	Text *t, *argt;
4217dd7cddfSDavid du Colombier 	int but;
4227dd7cddfSDavid du Colombier 	uint q0, q1;
4237dd7cddfSDavid du Colombier 	Window *w;
4247dd7cddfSDavid du Colombier 	Plumbmsg *pm;
4259a747e4fSDavid du Colombier 	Mouse m;
4267dd7cddfSDavid du Colombier 	char *act;
4275316891fSDavid du Colombier 	enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
4287dd7cddfSDavid du Colombier 	static Alt alts[NMALT+1];
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier 	threadsetname("mousethread");
4317dd7cddfSDavid du Colombier 	alts[MResize].c = mousectl->resizec;
4327dd7cddfSDavid du Colombier 	alts[MResize].v = nil;
4337dd7cddfSDavid du Colombier 	alts[MResize].op = CHANRCV;
4347dd7cddfSDavid du Colombier 	alts[MMouse].c = mousectl->c;
4357dd7cddfSDavid du Colombier 	alts[MMouse].v = &mousectl->Mouse;
4367dd7cddfSDavid du Colombier 	alts[MMouse].op = CHANRCV;
4377dd7cddfSDavid du Colombier 	alts[MPlumb].c = cplumb;
4387dd7cddfSDavid du Colombier 	alts[MPlumb].v = &pm;
4397dd7cddfSDavid du Colombier 	alts[MPlumb].op = CHANRCV;
4405316891fSDavid du Colombier 	alts[MWarnings].c = cwarn;
4415316891fSDavid du Colombier 	alts[MWarnings].v = nil;
4425316891fSDavid du Colombier 	alts[MWarnings].op = CHANRCV;
4437dd7cddfSDavid du Colombier 	if(cplumb == nil)
4447dd7cddfSDavid du Colombier 		alts[MPlumb].op = CHANNOP;
4457dd7cddfSDavid du Colombier 	alts[NMALT].op = CHANEND;
4467dd7cddfSDavid du Colombier 
4477dd7cddfSDavid du Colombier 	for(;;){
4485316891fSDavid du Colombier 		qlock(&row);
4495316891fSDavid du Colombier 		flushwarnings();
4505316891fSDavid du Colombier 		qunlock(&row);
4515316891fSDavid du Colombier 		flushimage(display, 1);
4527dd7cddfSDavid du Colombier 		switch(alt(alts)){
4537dd7cddfSDavid du Colombier 		case MResize:
4547dd7cddfSDavid du Colombier 			if(getwindow(display, Refnone) < 0)
4557dd7cddfSDavid du Colombier 				error("attach to window");
4567dd7cddfSDavid du Colombier 			scrlresize();
4577dd7cddfSDavid du Colombier 			rowresize(&row, screen->clipr);
4587dd7cddfSDavid du Colombier 			break;
4597dd7cddfSDavid du Colombier 		case MPlumb:
4607dd7cddfSDavid du Colombier 			if(strcmp(pm->type, "text") == 0){
4617dd7cddfSDavid du Colombier 				act = plumblookup(pm->attr, "action");
4627dd7cddfSDavid du Colombier 				if(act==nil || strcmp(act, "showfile")==0)
4637dd7cddfSDavid du Colombier 					plumblook(pm);
4647dd7cddfSDavid du Colombier 				else if(strcmp(act, "showdata")==0)
4657dd7cddfSDavid du Colombier 					plumbshow(pm);
4667dd7cddfSDavid du Colombier 			}
4677dd7cddfSDavid du Colombier 			plumbfree(pm);
4687dd7cddfSDavid du Colombier 			break;
4695316891fSDavid du Colombier 		case MWarnings:
4705316891fSDavid du Colombier 			break;
4717dd7cddfSDavid du Colombier 		case MMouse:
4729a747e4fSDavid du Colombier 			/*
4739a747e4fSDavid du Colombier 			 * Make a copy so decisions are consistent; mousectl changes
4749a747e4fSDavid du Colombier 			 * underfoot.  Can't just receive into m because this introduces
4759a747e4fSDavid du Colombier 			 * another race; see /sys/src/libdraw/mouse.c.
4769a747e4fSDavid du Colombier 			 */
4779a747e4fSDavid du Colombier 			m = mousectl->Mouse;
4787dd7cddfSDavid du Colombier 			qlock(&row);
4799a747e4fSDavid du Colombier 			t = rowwhich(&row, m.xy);
4807dd7cddfSDavid du Colombier 			if(t!=mousetext && mousetext!=nil && mousetext->w!=nil){
4817dd7cddfSDavid du Colombier 				winlock(mousetext->w, 'M');
4827dd7cddfSDavid du Colombier 				mousetext->eq0 = ~0;
4837dd7cddfSDavid du Colombier 				wincommit(mousetext->w, mousetext);
4847dd7cddfSDavid du Colombier 				winunlock(mousetext->w);
4857dd7cddfSDavid du Colombier 			}
4867dd7cddfSDavid du Colombier 			mousetext = t;
4877dd7cddfSDavid du Colombier 			if(t == nil)
4887dd7cddfSDavid du Colombier 				goto Continue;
4897dd7cddfSDavid du Colombier 			w = t->w;
4909a747e4fSDavid du Colombier 			if(t==nil || m.buttons==0)
4917dd7cddfSDavid du Colombier 				goto Continue;
4927dd7cddfSDavid du Colombier 			but = 0;
4939a747e4fSDavid du Colombier 			if(m.buttons == 1)
4947dd7cddfSDavid du Colombier 				but = 1;
4959a747e4fSDavid du Colombier 			else if(m.buttons == 2)
4967dd7cddfSDavid du Colombier 				but = 2;
4979a747e4fSDavid du Colombier 			else if(m.buttons == 4)
4987dd7cddfSDavid du Colombier 				but = 3;
4997dd7cddfSDavid du Colombier 			barttext = t;
5009a747e4fSDavid du Colombier 			if(t->what==Body && ptinrect(m.xy, t->scrollr)){
5017dd7cddfSDavid du Colombier 				if(but){
5027dd7cddfSDavid du Colombier 					winlock(w, 'M');
5037dd7cddfSDavid du Colombier 					t->eq0 = ~0;
5047dd7cddfSDavid du Colombier 					textscroll(t, but);
5057dd7cddfSDavid du Colombier 					winunlock(w);
5067dd7cddfSDavid du Colombier 				}
5077dd7cddfSDavid du Colombier 				goto Continue;
5087dd7cddfSDavid du Colombier 			}
509a8453668SDavid du Colombier 			/* scroll buttons, wheels, etc. */
510a8453668SDavid du Colombier 			if(t->what==Body && w != nil && (m.buttons & (8|16))){
511a8453668SDavid du Colombier 				if(m.buttons & 8)
512a8453668SDavid du Colombier 					but = Kscrolloneup;
513a8453668SDavid du Colombier 				else
514a8453668SDavid du Colombier 					but = Kscrollonedown;
515a8453668SDavid du Colombier 				winlock(w, 'M');
516a8453668SDavid du Colombier 				t->eq0 = ~0;
517a8453668SDavid du Colombier 				texttype(t, but);
518a8453668SDavid du Colombier 				winunlock(w);
519a8453668SDavid du Colombier 				goto Continue;
520a8453668SDavid du Colombier 			}
5219a747e4fSDavid du Colombier 			if(ptinrect(m.xy, t->scrollr)){
5227dd7cddfSDavid du Colombier 				if(but){
5237dd7cddfSDavid du Colombier 					if(t->what == Columntag)
5247dd7cddfSDavid du Colombier 						rowdragcol(&row, t->col, but);
5257dd7cddfSDavid du Colombier 					else if(t->what == Tag){
5267dd7cddfSDavid du Colombier 						coldragwin(t->col, t->w, but);
5277dd7cddfSDavid du Colombier 						if(t->w)
5287dd7cddfSDavid du Colombier 							barttext = &t->w->body;
5297dd7cddfSDavid du Colombier 					}
5307dd7cddfSDavid du Colombier 					if(t->col)
5317dd7cddfSDavid du Colombier 						activecol = t->col;
5327dd7cddfSDavid du Colombier 				}
5337dd7cddfSDavid du Colombier 				goto Continue;
5347dd7cddfSDavid du Colombier 			}
5359a747e4fSDavid du Colombier 			if(m.buttons){
5367dd7cddfSDavid du Colombier 				if(w)
5377dd7cddfSDavid du Colombier 					winlock(w, 'M');
5387dd7cddfSDavid du Colombier 				t->eq0 = ~0;
5397dd7cddfSDavid du Colombier 				if(w)
5407dd7cddfSDavid du Colombier 					wincommit(w, t);
5417dd7cddfSDavid du Colombier 				else
5427dd7cddfSDavid du Colombier 					textcommit(t, TRUE);
5439a747e4fSDavid du Colombier 				if(m.buttons & 1){
5447dd7cddfSDavid du Colombier 					textselect(t);
5457dd7cddfSDavid du Colombier 					if(w)
5467dd7cddfSDavid du Colombier 						winsettag(w);
5477dd7cddfSDavid du Colombier 					argtext = t;
5487dd7cddfSDavid du Colombier 					seltext = t;
5497dd7cddfSDavid du Colombier 					if(t->col)
5507dd7cddfSDavid du Colombier 						activecol = t->col;	/* button 1 only */
5517dd7cddfSDavid du Colombier 					if(t->w!=nil && t==&t->w->body)
5527dd7cddfSDavid du Colombier 						activewin = t->w;
5539a747e4fSDavid du Colombier 				}else if(m.buttons & 2){
5547dd7cddfSDavid du Colombier 					if(textselect2(t, &q0, &q1, &argt))
5557dd7cddfSDavid du Colombier 						execute(t, q0, q1, FALSE, argt);
5569a747e4fSDavid du Colombier 				}else if(m.buttons & 4){
5577dd7cddfSDavid du Colombier 					if(textselect3(t, &q0, &q1))
5587dd7cddfSDavid du Colombier 						look3(t, q0, q1, FALSE);
5597dd7cddfSDavid du Colombier 				}
5607dd7cddfSDavid du Colombier 				if(w)
5617dd7cddfSDavid du Colombier 					winunlock(w);
5627dd7cddfSDavid du Colombier 				goto Continue;
5637dd7cddfSDavid du Colombier 			}
5647dd7cddfSDavid du Colombier     Continue:
5657dd7cddfSDavid du Colombier 			qunlock(&row);
5667dd7cddfSDavid du Colombier 			break;
5677dd7cddfSDavid du Colombier 		}
5687dd7cddfSDavid du Colombier 	}
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier 
5717dd7cddfSDavid du Colombier /*
5727dd7cddfSDavid du Colombier  * There is a race between process exiting and our finding out it was ever created.
5737dd7cddfSDavid du Colombier  * This structure keeps a list of processes that have exited we haven't heard of.
5747dd7cddfSDavid du Colombier  */
5757dd7cddfSDavid du Colombier typedef struct Pid Pid;
5767dd7cddfSDavid du Colombier struct Pid
5777dd7cddfSDavid du Colombier {
5787dd7cddfSDavid du Colombier 	int	pid;
5799a747e4fSDavid du Colombier 	char	msg[ERRMAX];
5807dd7cddfSDavid du Colombier 	Pid	*next;
5817dd7cddfSDavid du Colombier };
5827dd7cddfSDavid du Colombier 
5837dd7cddfSDavid du Colombier void
waitthread(void *)5847dd7cddfSDavid du Colombier waitthread(void *)
5857dd7cddfSDavid du Colombier {
5869a747e4fSDavid du Colombier 	Waitmsg *w;
5877dd7cddfSDavid du Colombier 	Command *c, *lc;
5887dd7cddfSDavid du Colombier 	uint pid;
5897dd7cddfSDavid du Colombier 	int found, ncmd;
5907dd7cddfSDavid du Colombier 	Rune *cmd;
5917dd7cddfSDavid du Colombier 	char *err;
5927dd7cddfSDavid du Colombier 	Text *t;
5937dd7cddfSDavid du Colombier 	Pid *pids, *p, *lastp;
5947dd7cddfSDavid du Colombier 	enum { WErr, WKill, WWait, WCmd, NWALT };
5957dd7cddfSDavid du Colombier 	Alt alts[NWALT+1];
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier 	threadsetname("waitthread");
5987dd7cddfSDavid du Colombier 	pids = nil;
5997dd7cddfSDavid du Colombier 	alts[WErr].c = cerr;
6007dd7cddfSDavid du Colombier 	alts[WErr].v = &err;
6017dd7cddfSDavid du Colombier 	alts[WErr].op = CHANRCV;
6027dd7cddfSDavid du Colombier 	alts[WKill].c = ckill;
6037dd7cddfSDavid du Colombier 	alts[WKill].v = &cmd;
6047dd7cddfSDavid du Colombier 	alts[WKill].op = CHANRCV;
6057dd7cddfSDavid du Colombier 	alts[WWait].c = cwait;
6067dd7cddfSDavid du Colombier 	alts[WWait].v = &w;
6077dd7cddfSDavid du Colombier 	alts[WWait].op = CHANRCV;
6087dd7cddfSDavid du Colombier 	alts[WCmd].c = ccommand;
6097dd7cddfSDavid du Colombier 	alts[WCmd].v = &c;
6107dd7cddfSDavid du Colombier 	alts[WCmd].op = CHANRCV;
6117dd7cddfSDavid du Colombier 	alts[NWALT].op = CHANEND;
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier 	command = nil;
6147dd7cddfSDavid du Colombier 	for(;;){
6157dd7cddfSDavid du Colombier 		switch(alt(alts)){
6167dd7cddfSDavid du Colombier 		case WErr:
6177dd7cddfSDavid du Colombier 			qlock(&row);
6187dd7cddfSDavid du Colombier 			warning(nil, "%s", err);
6197dd7cddfSDavid du Colombier 			free(err);
6207dd7cddfSDavid du Colombier 			flushimage(display, 1);
6217dd7cddfSDavid du Colombier 			qunlock(&row);
6227dd7cddfSDavid du Colombier 			break;
6237dd7cddfSDavid du Colombier 		case WKill:
6247dd7cddfSDavid du Colombier 			found = FALSE;
6257dd7cddfSDavid du Colombier 			ncmd = runestrlen(cmd);
6267dd7cddfSDavid du Colombier 			for(c=command; c; c=c->next){
6277dd7cddfSDavid du Colombier 				/* -1 for blank */
6287dd7cddfSDavid du Colombier 				if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE){
6297dd7cddfSDavid du Colombier 					if(postnote(PNGROUP, c->pid, "kill") < 0)
6307dd7cddfSDavid du Colombier 						warning(nil, "kill %S: %r\n", cmd);
6317dd7cddfSDavid du Colombier 					found = TRUE;
6327dd7cddfSDavid du Colombier 				}
6337dd7cddfSDavid du Colombier 			}
6347dd7cddfSDavid du Colombier 			if(!found)
6357dd7cddfSDavid du Colombier 				warning(nil, "Kill: no process %S\n", cmd);
6367dd7cddfSDavid du Colombier 			free(cmd);
6377dd7cddfSDavid du Colombier 			break;
6387dd7cddfSDavid du Colombier 		case WWait:
6399a747e4fSDavid du Colombier 			pid = w->pid;
6407dd7cddfSDavid du Colombier 			lc = nil;
6417dd7cddfSDavid du Colombier 			for(c=command; c; c=c->next){
6427dd7cddfSDavid du Colombier 				if(c->pid == pid){
6437dd7cddfSDavid du Colombier 					if(lc)
6447dd7cddfSDavid du Colombier 						lc->next = c->next;
6457dd7cddfSDavid du Colombier 					else
6467dd7cddfSDavid du Colombier 						command = c->next;
6477dd7cddfSDavid du Colombier 					break;
6487dd7cddfSDavid du Colombier 				}
6497dd7cddfSDavid du Colombier 				lc = c;
6507dd7cddfSDavid du Colombier 			}
6517dd7cddfSDavid du Colombier 			qlock(&row);
6527dd7cddfSDavid du Colombier 			t = &row.tag;
6537dd7cddfSDavid du Colombier 			textcommit(t, TRUE);
6547dd7cddfSDavid du Colombier 			if(c == nil){
6557dd7cddfSDavid du Colombier 				/* helper processes use this exit status */
6569a747e4fSDavid du Colombier 				if(strncmp(w->msg, "libthread", 9) != 0){
6577dd7cddfSDavid du Colombier 					p = emalloc(sizeof(Pid));
6587dd7cddfSDavid du Colombier 					p->pid = pid;
6599a747e4fSDavid du Colombier 					strncpy(p->msg, w->msg, sizeof(p->msg));
6607dd7cddfSDavid du Colombier 					p->next = pids;
6617dd7cddfSDavid du Colombier 					pids = p;
6627dd7cddfSDavid du Colombier 				}
6637dd7cddfSDavid du Colombier 			}else{
6647dd7cddfSDavid du Colombier 				if(search(t, c->name, c->nname)){
6657dd7cddfSDavid du Colombier 					textdelete(t, t->q0, t->q1, TRUE);
6667dd7cddfSDavid du Colombier 					textsetselect(t, 0, 0);
6677dd7cddfSDavid du Colombier 				}
6689a747e4fSDavid du Colombier 				if(w->msg[0])
6699a747e4fSDavid du Colombier 					warning(c->md, "%s\n", w->msg);
6707dd7cddfSDavid du Colombier 				flushimage(display, 1);
6717dd7cddfSDavid du Colombier 			}
6727dd7cddfSDavid du Colombier 			qunlock(&row);
6739a747e4fSDavid du Colombier 			free(w);
6747dd7cddfSDavid du Colombier     Freecmd:
6757dd7cddfSDavid du Colombier 			if(c){
67659cc4ca5SDavid du Colombier 				if(c->iseditcmd)
67759cc4ca5SDavid du Colombier 					sendul(cedit, 0);
6787dd7cddfSDavid du Colombier 				free(c->text);
6797dd7cddfSDavid du Colombier 				free(c->name);
6807dd7cddfSDavid du Colombier 				fsysdelid(c->md);
6817dd7cddfSDavid du Colombier 				free(c);
6827dd7cddfSDavid du Colombier 			}
6837dd7cddfSDavid du Colombier 			break;
6847dd7cddfSDavid du Colombier 		case WCmd:
6857dd7cddfSDavid du Colombier 			/* has this command already exited? */
6867dd7cddfSDavid du Colombier 			lastp = nil;
6877dd7cddfSDavid du Colombier 			for(p=pids; p!=nil; p=p->next){
6887dd7cddfSDavid du Colombier 				if(p->pid == c->pid){
6897dd7cddfSDavid du Colombier 					if(p->msg[0])
6907dd7cddfSDavid du Colombier 						warning(c->md, "%s\n", p->msg);
6917dd7cddfSDavid du Colombier 					if(lastp == nil)
6927dd7cddfSDavid du Colombier 						pids = p->next;
6937dd7cddfSDavid du Colombier 					else
6947dd7cddfSDavid du Colombier 						lastp->next = p->next;
6957dd7cddfSDavid du Colombier 					free(p);
6967dd7cddfSDavid du Colombier 					goto Freecmd;
6977dd7cddfSDavid du Colombier 				}
6987dd7cddfSDavid du Colombier 				lastp = p;
6997dd7cddfSDavid du Colombier 			}
7007dd7cddfSDavid du Colombier 			c->next = command;
7017dd7cddfSDavid du Colombier 			command = c;
7027dd7cddfSDavid du Colombier 			qlock(&row);
7037dd7cddfSDavid du Colombier 			t = &row.tag;
7047dd7cddfSDavid du Colombier 			textcommit(t, TRUE);
7057dd7cddfSDavid du Colombier 			textinsert(t, 0, c->name, c->nname, TRUE);
7067dd7cddfSDavid du Colombier 			textsetselect(t, 0, 0);
7077dd7cddfSDavid du Colombier 			flushimage(display, 1);
7087dd7cddfSDavid du Colombier 			qunlock(&row);
7097dd7cddfSDavid du Colombier 			break;
7107dd7cddfSDavid du Colombier 		}
7117dd7cddfSDavid du Colombier 	}
7127dd7cddfSDavid du Colombier }
7137dd7cddfSDavid du Colombier 
7147dd7cddfSDavid du Colombier void
xfidallocthread(void *)7157dd7cddfSDavid du Colombier xfidallocthread(void*)
7167dd7cddfSDavid du Colombier {
7177dd7cddfSDavid du Colombier 	Xfid *xfree, *x;
7187dd7cddfSDavid du Colombier 	enum { Alloc, Free, N };
7197dd7cddfSDavid du Colombier 	static Alt alts[N+1];
7207dd7cddfSDavid du Colombier 
7217dd7cddfSDavid du Colombier 	threadsetname("xfidallocthread");
7227dd7cddfSDavid du Colombier 	alts[Alloc].c = cxfidalloc;
7237dd7cddfSDavid du Colombier 	alts[Alloc].v = nil;
7247dd7cddfSDavid du Colombier 	alts[Alloc].op = CHANRCV;
7257dd7cddfSDavid du Colombier 	alts[Free].c = cxfidfree;
7267dd7cddfSDavid du Colombier 	alts[Free].v = &x;
7277dd7cddfSDavid du Colombier 	alts[Free].op = CHANRCV;
7287dd7cddfSDavid du Colombier 	alts[N].op = CHANEND;
7297dd7cddfSDavid du Colombier 
7307dd7cddfSDavid du Colombier 	xfree = nil;
7317dd7cddfSDavid du Colombier 	for(;;){
7327dd7cddfSDavid du Colombier 		switch(alt(alts)){
7337dd7cddfSDavid du Colombier 		case Alloc:
7347dd7cddfSDavid du Colombier 			x = xfree;
7357dd7cddfSDavid du Colombier 			if(x)
7367dd7cddfSDavid du Colombier 				xfree = x->next;
7377dd7cddfSDavid du Colombier 			else{
7387dd7cddfSDavid du Colombier 				x = emalloc(sizeof(Xfid));
7397dd7cddfSDavid du Colombier 				x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
7407dd7cddfSDavid du Colombier 				x->arg = x;
7417dd7cddfSDavid du Colombier 				threadcreate(xfidctl, x->arg, STACK);
7427dd7cddfSDavid du Colombier 			}
7437dd7cddfSDavid du Colombier 			sendp(cxfidalloc, x);
7447dd7cddfSDavid du Colombier 			break;
7457dd7cddfSDavid du Colombier 		case Free:
7467dd7cddfSDavid du Colombier 			x->next = xfree;
7477dd7cddfSDavid du Colombier 			xfree = x;
7487dd7cddfSDavid du Colombier 			break;
7497dd7cddfSDavid du Colombier 		}
7507dd7cddfSDavid du Colombier 	}
7517dd7cddfSDavid du Colombier }
7527dd7cddfSDavid du Colombier 
7539a747e4fSDavid du Colombier /* this thread, in the main proc, allows fsysproc to get a window made without doing graphics */
7549a747e4fSDavid du Colombier void
newwindowthread(void *)7559a747e4fSDavid du Colombier newwindowthread(void*)
7569a747e4fSDavid du Colombier {
7579a747e4fSDavid du Colombier 	Window *w;
7589a747e4fSDavid du Colombier 
7599a747e4fSDavid du Colombier 	threadsetname("newwindowthread");
7609a747e4fSDavid du Colombier 
7619a747e4fSDavid du Colombier 	for(;;){
7629a747e4fSDavid du Colombier 		/* only fsysproc is talking to us, so synchronization is trivial */
7639a747e4fSDavid du Colombier 		recvp(cnewwindow);
764d9306527SDavid du Colombier 		w = makenewwindow(nil);
7659a747e4fSDavid du Colombier 		winsettag(w);
7669a747e4fSDavid du Colombier 		sendp(cnewwindow, w);
7679a747e4fSDavid du Colombier 	}
7689a747e4fSDavid du Colombier }
7699a747e4fSDavid du Colombier 
7707dd7cddfSDavid du Colombier Reffont*
rfget(int fix,int save,int setfont,char * name)7717dd7cddfSDavid du Colombier rfget(int fix, int save, int setfont, char *name)
7727dd7cddfSDavid du Colombier {
7737dd7cddfSDavid du Colombier 	Reffont *r;
7747dd7cddfSDavid du Colombier 	Font *f;
7757dd7cddfSDavid du Colombier 	int i;
7767dd7cddfSDavid du Colombier 
7777dd7cddfSDavid du Colombier 	r = nil;
7787dd7cddfSDavid du Colombier 	if(name == nil){
7797dd7cddfSDavid du Colombier 		name = fontnames[fix];
7807dd7cddfSDavid du Colombier 		r = reffonts[fix];
7817dd7cddfSDavid du Colombier 	}
7827dd7cddfSDavid du Colombier 	if(r == nil){
7837dd7cddfSDavid du Colombier 		for(i=0; i<nfontcache; i++)
7847dd7cddfSDavid du Colombier 			if(strcmp(name, fontcache[i]->f->name) == 0){
7857dd7cddfSDavid du Colombier 				r = fontcache[i];
7867dd7cddfSDavid du Colombier 				goto Found;
7877dd7cddfSDavid du Colombier 			}
78859cc4ca5SDavid du Colombier 		f = openfont(display, name);
7897dd7cddfSDavid du Colombier 		if(f == nil){
7907dd7cddfSDavid du Colombier 			warning(nil, "can't open font file %s: %r\n", name);
7917dd7cddfSDavid du Colombier 			return nil;
7927dd7cddfSDavid du Colombier 		}
7937dd7cddfSDavid du Colombier 		r = emalloc(sizeof(Reffont));
7947dd7cddfSDavid du Colombier 		r->f = f;
7956d0d1481SDavid du Colombier 		fontcache = erealloc(fontcache, (nfontcache+1)*sizeof(Reffont*));
7967dd7cddfSDavid du Colombier 		fontcache[nfontcache++] = r;
7977dd7cddfSDavid du Colombier 	}
7987dd7cddfSDavid du Colombier     Found:
7997dd7cddfSDavid du Colombier 	if(save){
8007dd7cddfSDavid du Colombier 		incref(r);
8017dd7cddfSDavid du Colombier 		if(reffonts[fix])
8027dd7cddfSDavid du Colombier 			rfclose(reffonts[fix]);
8037dd7cddfSDavid du Colombier 		reffonts[fix] = r;
8046d0d1481SDavid du Colombier 		if(name != fontnames[fix]){
8059a747e4fSDavid du Colombier 			free(fontnames[fix]);
8066d0d1481SDavid du Colombier 			fontnames[fix] = estrdup(name);
8076d0d1481SDavid du Colombier 		}
8087dd7cddfSDavid du Colombier 	}
8097dd7cddfSDavid du Colombier 	if(setfont){
8107dd7cddfSDavid du Colombier 		reffont.f = r->f;
8117dd7cddfSDavid du Colombier 		incref(r);
8127dd7cddfSDavid du Colombier 		rfclose(reffonts[0]);
8137dd7cddfSDavid du Colombier 		font = r->f;
8147dd7cddfSDavid du Colombier 		reffonts[0] = r;
8157dd7cddfSDavid du Colombier 		incref(r);
8167dd7cddfSDavid du Colombier 		iconinit();
8177dd7cddfSDavid du Colombier 	}
8187dd7cddfSDavid du Colombier 	incref(r);
8197dd7cddfSDavid du Colombier 	return r;
8207dd7cddfSDavid du Colombier }
8217dd7cddfSDavid du Colombier 
8227dd7cddfSDavid du Colombier void
rfclose(Reffont * r)8237dd7cddfSDavid du Colombier rfclose(Reffont *r)
8247dd7cddfSDavid du Colombier {
8257dd7cddfSDavid du Colombier 	int i;
8267dd7cddfSDavid du Colombier 
8277dd7cddfSDavid du Colombier 	if(decref(r) == 0){
8287dd7cddfSDavid du Colombier 		for(i=0; i<nfontcache; i++)
8297dd7cddfSDavid du Colombier 			if(r == fontcache[i])
8307dd7cddfSDavid du Colombier 				break;
8317dd7cddfSDavid du Colombier 		if(i >= nfontcache)
8327dd7cddfSDavid du Colombier 			warning(nil, "internal error: can't find font in cache\n");
8337dd7cddfSDavid du Colombier 		else{
8347dd7cddfSDavid du Colombier 			nfontcache--;
8357dd7cddfSDavid du Colombier 			memmove(fontcache+i, fontcache+i+1, (nfontcache-i)*sizeof(Reffont*));
8367dd7cddfSDavid du Colombier 		}
8377dd7cddfSDavid du Colombier 		freefont(r->f);
8387dd7cddfSDavid du Colombier 		free(r);
8397dd7cddfSDavid du Colombier 	}
8407dd7cddfSDavid du Colombier }
8417dd7cddfSDavid du Colombier 
8427dd7cddfSDavid du Colombier Cursor boxcursor = {
8437dd7cddfSDavid du Colombier 	{-7, -7},
8447dd7cddfSDavid du Colombier 	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
8457dd7cddfSDavid du Colombier 	 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
8467dd7cddfSDavid du Colombier 	 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
8477dd7cddfSDavid du Colombier 	 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
8487dd7cddfSDavid du Colombier 	{0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
8497dd7cddfSDavid du Colombier 	 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
8507dd7cddfSDavid du Colombier 	 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
8517dd7cddfSDavid du Colombier 	 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00}
8527dd7cddfSDavid du Colombier };
8537dd7cddfSDavid du Colombier 
8547dd7cddfSDavid du Colombier void
iconinit(void)8557dd7cddfSDavid du Colombier iconinit(void)
8567dd7cddfSDavid du Colombier {
8577dd7cddfSDavid du Colombier 	Rectangle r;
8587dd7cddfSDavid du Colombier 	Image *tmp;
8597dd7cddfSDavid du Colombier 
8607dd7cddfSDavid du Colombier 	/* Blue */
8617dd7cddfSDavid du Colombier 	tagcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
8629a747e4fSDavid du Colombier 	tagcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
8639a747e4fSDavid du Colombier 	tagcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
8647dd7cddfSDavid du Colombier 	tagcols[TEXT] = display->black;
8657dd7cddfSDavid du Colombier 	tagcols[HTEXT] = display->black;
8667dd7cddfSDavid du Colombier 
8677dd7cddfSDavid du Colombier 	/* Yellow */
8687dd7cddfSDavid du Colombier 	textcols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
8699a747e4fSDavid du Colombier 	textcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
8709a747e4fSDavid du Colombier 	textcols[BORD] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellowgreen);
8717dd7cddfSDavid du Colombier 	textcols[TEXT] = display->black;
8727dd7cddfSDavid du Colombier 	textcols[HTEXT] = display->black;
8737dd7cddfSDavid du Colombier 
8747dd7cddfSDavid du Colombier 	if(button){
8757dd7cddfSDavid du Colombier 		freeimage(button);
8767dd7cddfSDavid du Colombier 		freeimage(modbutton);
8777dd7cddfSDavid du Colombier 		freeimage(colbutton);
8787dd7cddfSDavid du Colombier 	}
8797dd7cddfSDavid du Colombier 
8807dd7cddfSDavid du Colombier 	r = Rect(0, 0, Scrollwid+2, font->height+1);
8819a747e4fSDavid du Colombier 	button = allocimage(display, r, screen->chan, 0, DNofill);
8827dd7cddfSDavid du Colombier 	draw(button, r, tagcols[BACK], nil, r.min);
8837dd7cddfSDavid du Colombier 	r.max.x -= 2;
8847dd7cddfSDavid du Colombier 	border(button, r, 2, tagcols[BORD], ZP);
8857dd7cddfSDavid du Colombier 
8867dd7cddfSDavid du Colombier 	r = button->r;
8879a747e4fSDavid du Colombier 	modbutton = allocimage(display, r, screen->chan, 0, DNofill);
8887dd7cddfSDavid du Colombier 	draw(modbutton, r, tagcols[BACK], nil, r.min);
8897dd7cddfSDavid du Colombier 	r.max.x -= 2;
8907dd7cddfSDavid du Colombier 	border(modbutton, r, 2, tagcols[BORD], ZP);
8917dd7cddfSDavid du Colombier 	r = insetrect(r, 2);
8929a747e4fSDavid du Colombier 	tmp = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedblue);
8937dd7cddfSDavid du Colombier 	draw(modbutton, r, tmp, nil, ZP);
8947dd7cddfSDavid du Colombier 	freeimage(tmp);
8957dd7cddfSDavid du Colombier 
8967dd7cddfSDavid du Colombier 	r = button->r;
8979a747e4fSDavid du Colombier 	colbutton = allocimage(display, r, screen->chan, 0, DPurpleblue);
8987dd7cddfSDavid du Colombier 
8999a747e4fSDavid du Colombier 	but2col = allocimage(display, r, screen->chan, 1, 0xAA0000FF);
9009a747e4fSDavid du Colombier 	but3col = allocimage(display, r, screen->chan, 1, 0x006600FF);
9017dd7cddfSDavid du Colombier }
9027dd7cddfSDavid du Colombier 
9037dd7cddfSDavid du Colombier /*
9047dd7cddfSDavid du Colombier  * /dev/snarf updates when the file is closed, so we must open our own
9057dd7cddfSDavid du Colombier  * fd here rather than use snarffd
9067dd7cddfSDavid du Colombier  */
9077dd7cddfSDavid du Colombier 
9087dd7cddfSDavid du Colombier /* rio truncates larges snarf buffers, so this avoids using the
9097dd7cddfSDavid du Colombier  * service if the string is huge */
9107dd7cddfSDavid du Colombier 
9117dd7cddfSDavid du Colombier #define MAXSNARF 100*1024
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier void
putsnarf(void)9147dd7cddfSDavid du Colombier putsnarf(void)
9157dd7cddfSDavid du Colombier {
9167dd7cddfSDavid du Colombier 	int fd, i, n;
9177dd7cddfSDavid du Colombier 
9187dd7cddfSDavid du Colombier 	if(snarffd<0 || snarfbuf.nc==0)
9197dd7cddfSDavid du Colombier 		return;
9207dd7cddfSDavid du Colombier 	if(snarfbuf.nc > MAXSNARF)
9217dd7cddfSDavid du Colombier 		return;
9227dd7cddfSDavid du Colombier 	fd = open("/dev/snarf", OWRITE);
9237dd7cddfSDavid du Colombier 	if(fd < 0)
9247dd7cddfSDavid du Colombier 		return;
9257dd7cddfSDavid du Colombier 	for(i=0; i<snarfbuf.nc; i+=n){
9267dd7cddfSDavid du Colombier 		n = snarfbuf.nc-i;
9277dd7cddfSDavid du Colombier 		if(n >= NSnarf)
9287dd7cddfSDavid du Colombier 			n = NSnarf;
9297dd7cddfSDavid du Colombier 		bufread(&snarfbuf, i, snarfrune, n);
9307dd7cddfSDavid du Colombier 		if(fprint(fd, "%.*S", n, snarfrune) < 0)
9317dd7cddfSDavid du Colombier 			break;
9327dd7cddfSDavid du Colombier 	}
9337dd7cddfSDavid du Colombier 	close(fd);
9347dd7cddfSDavid du Colombier }
9357dd7cddfSDavid du Colombier 
9367dd7cddfSDavid du Colombier void
getsnarf()9377dd7cddfSDavid du Colombier getsnarf()
9387dd7cddfSDavid du Colombier {
9397dd7cddfSDavid du Colombier 	int nulls;
9407dd7cddfSDavid du Colombier 
9417dd7cddfSDavid du Colombier 	if(snarfbuf.nc > MAXSNARF)
9427dd7cddfSDavid du Colombier 		return;
9437dd7cddfSDavid du Colombier 	if(snarffd < 0)
9447dd7cddfSDavid du Colombier 		return;
9457dd7cddfSDavid du Colombier 	seek(snarffd, 0, 0);
9467dd7cddfSDavid du Colombier 	bufreset(&snarfbuf);
9477dd7cddfSDavid du Colombier 	bufload(&snarfbuf, 0, snarffd, &nulls);
9487dd7cddfSDavid du Colombier }
949