xref: /plan9-contrib/sys/src/cmd/rio/xfid.c (revision 2906cf0c8250511ba5ce896f8e5505ea9c265e35)
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"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier #define	MAXSNARF	100*1024
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier char Einuse[] =		"file in use";
177dd7cddfSDavid du Colombier char Edeleted[] =	"window deleted";
187dd7cddfSDavid du Colombier char Ebadreq[] =	"bad graphics request";
1959cc4ca5SDavid du Colombier char Etooshort[] =	"buffer too small";
207dd7cddfSDavid du Colombier char Ebadtile[] =	"unknown tile";
217dd7cddfSDavid du Colombier char Eshort[] =		"short i/o request";
227dd7cddfSDavid du Colombier char Elong[] = 		"snarf buffer too long";
237dd7cddfSDavid du Colombier char Eunkid[] = 	"unknown id in attach";
247dd7cddfSDavid du Colombier char Ebadrect[] = 	"bad rectangle in attach";
257dd7cddfSDavid du Colombier char Ewindow[] = 	"cannot make window";
267dd7cddfSDavid du Colombier char Enowindow[] = 	"window has no image";
277dd7cddfSDavid du Colombier char Ebadmouse[] = 	"bad format on /dev/mouse";
287dd7cddfSDavid du Colombier char Ebadwrect[] = 	"rectangle outside screen";
297dd7cddfSDavid du Colombier char Ebadoffset[] = 	"window read not on scan line boundary";
3080ee5cbfSDavid du Colombier extern char Eperm[];
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier static	Xfid	*xfidfree;
337dd7cddfSDavid du Colombier static	Xfid	*xfid;
347dd7cddfSDavid du Colombier static	Channel	*cxfidalloc;	/* chan(Xfid*) */
357dd7cddfSDavid du Colombier static	Channel	*cxfidfree;	/* chan(Xfid*) */
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier static	char	*tsnarf;
387dd7cddfSDavid du Colombier static	int	ntsnarf;
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier void
xfidallocthread(void *)417dd7cddfSDavid du Colombier xfidallocthread(void*)
427dd7cddfSDavid du Colombier {
437dd7cddfSDavid du Colombier 	Xfid *x;
447dd7cddfSDavid du Colombier 	enum { Alloc, Free, N };
457dd7cddfSDavid du Colombier 	static Alt alts[N+1];
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	alts[Alloc].c = cxfidalloc;
487dd7cddfSDavid du Colombier 	alts[Alloc].v = nil;
497dd7cddfSDavid du Colombier 	alts[Alloc].op = CHANRCV;
507dd7cddfSDavid du Colombier 	alts[Free].c = cxfidfree;
517dd7cddfSDavid du Colombier 	alts[Free].v = &x;
527dd7cddfSDavid du Colombier 	alts[Free].op = CHANRCV;
537dd7cddfSDavid du Colombier 	alts[N].op = CHANEND;
547dd7cddfSDavid du Colombier 	for(;;){
557dd7cddfSDavid du Colombier 		switch(alt(alts)){
567dd7cddfSDavid du Colombier 		case Alloc:
577dd7cddfSDavid du Colombier 			x = xfidfree;
587dd7cddfSDavid du Colombier 			if(x)
597dd7cddfSDavid du Colombier 				xfidfree = x->free;
607dd7cddfSDavid du Colombier 			else{
617dd7cddfSDavid du Colombier 				x = emalloc(sizeof(Xfid));
627dd7cddfSDavid du Colombier 				x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
6380ee5cbfSDavid du Colombier 				x->flushc = chancreate(sizeof(int), 0);	/* notification only; no data */
647dd7cddfSDavid du Colombier 				x->flushtag = -1;
657dd7cddfSDavid du Colombier 				x->next = xfid;
667dd7cddfSDavid du Colombier 				xfid = x;
677dd7cddfSDavid du Colombier 				threadcreate(xfidctl, x, 16384);
687dd7cddfSDavid du Colombier 			}
6959cc4ca5SDavid du Colombier 			if(x->ref != 0){
709a747e4fSDavid du Colombier 				fprint(2, "%p incref %ld\n", x, x->ref);
7159cc4ca5SDavid du Colombier 				error("incref");
7259cc4ca5SDavid du Colombier 			}
7359cc4ca5SDavid du Colombier 			if(x->flushtag != -1)
7459cc4ca5SDavid du Colombier 				error("flushtag in allocate");
757dd7cddfSDavid du Colombier 			incref(x);
767dd7cddfSDavid du Colombier 			sendp(cxfidalloc, x);
777dd7cddfSDavid du Colombier 			break;
787dd7cddfSDavid du Colombier 		case Free:
7959cc4ca5SDavid du Colombier 			if(x->ref != 0){
809a747e4fSDavid du Colombier 				fprint(2, "%p decref %ld\n", x, x->ref);
8159cc4ca5SDavid du Colombier 				error("decref");
8259cc4ca5SDavid du Colombier 			}
8359cc4ca5SDavid du Colombier 			if(x->flushtag != -1)
8459cc4ca5SDavid du Colombier 				error("flushtag in free");
857dd7cddfSDavid du Colombier 			x->free = xfidfree;
867dd7cddfSDavid du Colombier 			xfidfree = x;
877dd7cddfSDavid du Colombier 			break;
887dd7cddfSDavid du Colombier 		}
897dd7cddfSDavid du Colombier 	}
907dd7cddfSDavid du Colombier }
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier Channel*
xfidinit(void)937dd7cddfSDavid du Colombier xfidinit(void)
947dd7cddfSDavid du Colombier {
957dd7cddfSDavid du Colombier 	cxfidalloc = chancreate(sizeof(Xfid*), 0);
967dd7cddfSDavid du Colombier 	cxfidfree = chancreate(sizeof(Xfid*), 0);
977dd7cddfSDavid du Colombier 	threadcreate(xfidallocthread, nil, STACK);
987dd7cddfSDavid du Colombier 	return cxfidalloc;
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier void
xfidctl(void * arg)1027dd7cddfSDavid du Colombier xfidctl(void *arg)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier 	Xfid *x;
1057dd7cddfSDavid du Colombier 	void (*f)(Xfid*);
10659cc4ca5SDavid du Colombier 	char buf[64];
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier 	x = arg;
10959cc4ca5SDavid du Colombier 	snprint(buf, sizeof buf, "xfid.%p", x);
11059cc4ca5SDavid du Colombier 	threadsetname(buf);
1117dd7cddfSDavid du Colombier 	for(;;){
1127dd7cddfSDavid du Colombier 		f = recvp(x->c);
1137dd7cddfSDavid du Colombier 		(*f)(x);
1147dd7cddfSDavid du Colombier 		if(decref(x) == 0)
1157dd7cddfSDavid du Colombier 			sendp(cxfidfree, x);
1167dd7cddfSDavid du Colombier 	}
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier void
xfidflush(Xfid * x)1207dd7cddfSDavid du Colombier xfidflush(Xfid *x)
1217dd7cddfSDavid du Colombier {
1227dd7cddfSDavid du Colombier 	Fcall t;
1237dd7cddfSDavid du Colombier 	Xfid *xf;
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier 	for(xf=xfid; xf; xf=xf->next)
1267dd7cddfSDavid du Colombier 		if(xf->flushtag == x->oldtag){
1277dd7cddfSDavid du Colombier 			xf->flushtag = -1;
1287dd7cddfSDavid du Colombier 			xf->flushing = TRUE;
1297dd7cddfSDavid du Colombier 			incref(xf);	/* to hold data structures up at tail of synchronization */
13059cc4ca5SDavid du Colombier 			if(xf->ref == 1)
13159cc4ca5SDavid du Colombier 				error("ref 1 in flush");
1327dd7cddfSDavid du Colombier 			if(canqlock(&xf->active)){
1337dd7cddfSDavid du Colombier 				qunlock(&xf->active);
13480ee5cbfSDavid du Colombier 				sendul(xf->flushc, 0);
1357dd7cddfSDavid du Colombier 			}else{
1367dd7cddfSDavid du Colombier 				qlock(&xf->active);	/* wait for him to finish */
1377dd7cddfSDavid du Colombier 				qunlock(&xf->active);
1387dd7cddfSDavid du Colombier 			}
1397dd7cddfSDavid du Colombier 			xf->flushing = FALSE;
1407dd7cddfSDavid du Colombier 			if(decref(xf) == 0)
1417dd7cddfSDavid du Colombier 				sendp(cxfidfree, xf);
1427dd7cddfSDavid du Colombier 			break;
1437dd7cddfSDavid du Colombier 		}
1447dd7cddfSDavid du Colombier 	filsysrespond(x->fs, x, &t, nil);
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier void
xfidattach(Xfid * x)1487dd7cddfSDavid du Colombier xfidattach(Xfid *x)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	Fcall t;
1513ff48bf5SDavid du Colombier 	int id, hideit, scrollit;
1527dd7cddfSDavid du Colombier 	Window *w;
1539a747e4fSDavid du Colombier 	char *err, *n, *dir, errbuf[ERRMAX];
1547dd7cddfSDavid du Colombier 	int pid, newlymade;
1557dd7cddfSDavid du Colombier 	Rectangle r;
1567dd7cddfSDavid du Colombier 	Image *i;
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier 	t.qid = x->f->qid;
1597dd7cddfSDavid du Colombier 	qlock(&all);
1607dd7cddfSDavid du Colombier 	w = nil;
1617dd7cddfSDavid du Colombier 	err = Eunkid;
1627dd7cddfSDavid du Colombier 	newlymade = FALSE;
1639a747e4fSDavid du Colombier 	hideit = 0;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	if(x->aname[0] == 'N'){	/* N 100,100, 200, 200 - old syntax */
1667dd7cddfSDavid du Colombier 		n = x->aname+1;
1677dd7cddfSDavid du Colombier 		pid = strtoul(n, &n, 0);
1687dd7cddfSDavid du Colombier 		if(*n == ',')
1697dd7cddfSDavid du Colombier 			n++;
1707dd7cddfSDavid du Colombier 		r.min.x = strtoul(n, &n, 0);
1717dd7cddfSDavid du Colombier 		if(*n == ',')
1727dd7cddfSDavid du Colombier 			n++;
1737dd7cddfSDavid du Colombier 		r.min.y = strtoul(n, &n, 0);
1747dd7cddfSDavid du Colombier 		if(*n == ',')
1757dd7cddfSDavid du Colombier 			n++;
1767dd7cddfSDavid du Colombier 		r.max.x = strtoul(n, &n, 0);
1777dd7cddfSDavid du Colombier 		if(*n == ',')
1787dd7cddfSDavid du Colombier 			n++;
1797dd7cddfSDavid du Colombier 		r.max.y = strtoul(n, &n, 0);
18059cc4ca5SDavid du Colombier   Allocate:
18159cc4ca5SDavid du Colombier 		if(!goodrect(r))
1827dd7cddfSDavid du Colombier 			err = Ebadrect;
1837dd7cddfSDavid du Colombier 		else{
1849a747e4fSDavid du Colombier 			if(hideit)
1859a747e4fSDavid du Colombier 				i = allocimage(display, r, screen->chan, 0, DWhite);
1869a747e4fSDavid du Colombier 			else
1877dd7cddfSDavid du Colombier 				i = allocwindow(wscreen, r, Refbackup, DWhite);
1887dd7cddfSDavid du Colombier 			if(i){
1897dd7cddfSDavid du Colombier 				border(i, r, Selborder, display->black, ZP);
1907dd7cddfSDavid du Colombier 				if(pid == 0)
1917dd7cddfSDavid du Colombier 					pid = -1;	/* make sure we don't pop a shell! - UGH */
1923ff48bf5SDavid du Colombier 				w = new(i, hideit, scrolling, pid, nil, nil, nil);
1937dd7cddfSDavid du Colombier 				flushimage(display, 1);
1947dd7cddfSDavid du Colombier 				newlymade = TRUE;
1957dd7cddfSDavid du Colombier 			}else
1967dd7cddfSDavid du Colombier 				err = Ewindow;
1977dd7cddfSDavid du Colombier 		}
1987dd7cddfSDavid du Colombier 	}else if(strncmp(x->aname, "new", 3) == 0){	/* new -dx -dy - new syntax, as in wctl */
1997dd7cddfSDavid du Colombier 		pid = 0;
2003ff48bf5SDavid du Colombier 		if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
2017dd7cddfSDavid du Colombier 			err = errbuf;
2027dd7cddfSDavid du Colombier 		else
2037dd7cddfSDavid du Colombier 			goto Allocate;
2047dd7cddfSDavid du Colombier 	}else{
2057dd7cddfSDavid du Colombier 		id = atoi(x->aname);
2067dd7cddfSDavid du Colombier 		w = wlookid(id);
2077dd7cddfSDavid du Colombier 	}
2087dd7cddfSDavid du Colombier 	x->f->w = w;
2097dd7cddfSDavid du Colombier 	if(w == nil){
2107dd7cddfSDavid du Colombier 		qunlock(&all);
211*2906cf0cSDavid du Colombier 		x->f->busy = FALSE;
2127dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &t, err);
2137dd7cddfSDavid du Colombier 		return;
2147dd7cddfSDavid du Colombier 	}
2157dd7cddfSDavid du Colombier 	if(!newlymade)	/* counteract dec() in winshell() */
2167dd7cddfSDavid du Colombier 		incref(w);
2177dd7cddfSDavid du Colombier 	qunlock(&all);
2187dd7cddfSDavid du Colombier 	filsysrespond(x->fs, x, &t, nil);
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier void
xfidopen(Xfid * x)2227dd7cddfSDavid du Colombier xfidopen(Xfid *x)
2237dd7cddfSDavid du Colombier {
2247dd7cddfSDavid du Colombier 	Fcall t;
2257dd7cddfSDavid du Colombier 	Window *w;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 	w = x->f->w;
2287dd7cddfSDavid du Colombier 	if(w->deleted){
2297dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &t, Edeleted);
2307dd7cddfSDavid du Colombier 		return;
2317dd7cddfSDavid du Colombier 	}
2327dd7cddfSDavid du Colombier 	switch(FILE(x->f->qid)){
2337dd7cddfSDavid du Colombier 	case Qconsctl:
2347dd7cddfSDavid du Colombier 		if(w->ctlopen){
2357dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &t, Einuse);
2367dd7cddfSDavid du Colombier 			return;
2377dd7cddfSDavid du Colombier 		}
2387dd7cddfSDavid du Colombier 		w->ctlopen = TRUE;
2397dd7cddfSDavid du Colombier 		break;
24080ee5cbfSDavid du Colombier 	case Qkbdin:
24180ee5cbfSDavid du Colombier 		if(w !=  wkeyboard){
24280ee5cbfSDavid du Colombier 			filsysrespond(x->fs, x, &t, Eperm);
24380ee5cbfSDavid du Colombier 			return;
24480ee5cbfSDavid du Colombier 		}
24580ee5cbfSDavid du Colombier 		break;
2467dd7cddfSDavid du Colombier 	case Qmouse:
2477dd7cddfSDavid du Colombier 		if(w->mouseopen){
2487dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &t, Einuse);
2497dd7cddfSDavid du Colombier 			return;
2507dd7cddfSDavid du Colombier 		}
2517dd7cddfSDavid du Colombier 		/*
2527dd7cddfSDavid du Colombier 		 * Reshaped: there's a race if the appl. opens the
2537dd7cddfSDavid du Colombier 		 * window, is resized, and then opens the mouse,
2547dd7cddfSDavid du Colombier 		 * but that's rare.  The alternative is to generate
2557dd7cddfSDavid du Colombier 		 * a resized event every time a new program starts
2567dd7cddfSDavid du Colombier 		 * up in a window that has been resized since the
2577dd7cddfSDavid du Colombier 		 * dawn of time.  We choose the lesser evil.
2587dd7cddfSDavid du Colombier 		 */
2597dd7cddfSDavid du Colombier 		w->resized = FALSE;
2607dd7cddfSDavid du Colombier 		w->mouseopen = TRUE;
2617dd7cddfSDavid du Colombier 		break;
2627dd7cddfSDavid du Colombier 	case Qsnarf:
2637dd7cddfSDavid du Colombier 		if(x->mode==ORDWR || x->mode==OWRITE){
2647dd7cddfSDavid du Colombier 			if(tsnarf)
2657dd7cddfSDavid du Colombier 				free(tsnarf);	/* collision, but OK */
2667dd7cddfSDavid du Colombier 			ntsnarf = 0;
2677dd7cddfSDavid du Colombier 			tsnarf = malloc(1);
2687dd7cddfSDavid du Colombier 		}
2697dd7cddfSDavid du Colombier 		break;
27059cc4ca5SDavid du Colombier 	case Qwctl:
27159cc4ca5SDavid du Colombier 		if(x->mode==OREAD || x->mode==ORDWR){
27259cc4ca5SDavid du Colombier 			/*
27359cc4ca5SDavid du Colombier 			 * It would be much nicer to implement fan-out for wctl reads,
27459cc4ca5SDavid du Colombier 			 * so multiple people can see the resizings, but rio just isn't
27559cc4ca5SDavid du Colombier 			 * structured for that.  It's structured for /dev/cons, which gives
27659cc4ca5SDavid du Colombier 			 * alternate data to alternate readers.  So to keep things sane for
27759cc4ca5SDavid du Colombier 			 * wctl, we compromise and give an error if two people try to
27859cc4ca5SDavid du Colombier 			 * open it.  Apologies.
27959cc4ca5SDavid du Colombier 			 */
28059cc4ca5SDavid du Colombier 			if(w->wctlopen){
28159cc4ca5SDavid du Colombier 				filsysrespond(x->fs, x, &t, Einuse);
28259cc4ca5SDavid du Colombier 				return;
28359cc4ca5SDavid du Colombier 			}
28459cc4ca5SDavid du Colombier 			w->wctlopen = TRUE;
28559cc4ca5SDavid du Colombier 			w->wctlready = 1;
28659cc4ca5SDavid du Colombier 			wsendctlmesg(w, Wakeup, ZR, nil);
28759cc4ca5SDavid du Colombier 		}
28859cc4ca5SDavid du Colombier 		break;
2897dd7cddfSDavid du Colombier 	}
2907dd7cddfSDavid du Colombier 	t.qid = x->f->qid;
2919a747e4fSDavid du Colombier 	t.iounit = messagesize-IOHDRSZ;
2927dd7cddfSDavid du Colombier 	x->f->open = TRUE;
2937dd7cddfSDavid du Colombier 	x->f->mode = x->mode;
2947dd7cddfSDavid du Colombier 	filsysrespond(x->fs, x, &t, nil);
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
xfidclose(Xfid * x)2987dd7cddfSDavid du Colombier xfidclose(Xfid *x)
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier 	Fcall t;
3017dd7cddfSDavid du Colombier 	Window *w;
3027dd7cddfSDavid du Colombier 	int nb, nulls;
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	w = x->f->w;
3057dd7cddfSDavid du Colombier 	switch(FILE(x->f->qid)){
3067dd7cddfSDavid du Colombier 	case Qconsctl:
3079a747e4fSDavid du Colombier 		if(w->rawing){
3089a747e4fSDavid du Colombier 			w->rawing = FALSE;
3097dd7cddfSDavid du Colombier 			wsendctlmesg(w, Rawoff, ZR, nil);
3109a747e4fSDavid du Colombier 		}
3119a747e4fSDavid du Colombier 		if(w->holding){
3129a747e4fSDavid du Colombier 			w->holding = FALSE;
3137dd7cddfSDavid du Colombier 			wsendctlmesg(w, Holdoff, ZR, nil);
3149a747e4fSDavid du Colombier 		}
3157dd7cddfSDavid du Colombier 		w->ctlopen = FALSE;
3167dd7cddfSDavid du Colombier 		break;
3177dd7cddfSDavid du Colombier 	case Qcursor:
3187dd7cddfSDavid du Colombier 		w->cursorp = nil;
3197dd7cddfSDavid du Colombier 		wsetcursor(w, FALSE);
3207dd7cddfSDavid du Colombier 		break;
3217dd7cddfSDavid du Colombier 	case Qmouse:
3227dd7cddfSDavid du Colombier 		w->resized = FALSE;
3237dd7cddfSDavid du Colombier 		w->mouseopen = FALSE;
3247dd7cddfSDavid du Colombier 		if(w->i != nil)
3257dd7cddfSDavid du Colombier 			wsendctlmesg(w, Refresh, w->i->r, nil);
3267dd7cddfSDavid du Colombier 		break;
3277dd7cddfSDavid du Colombier 	/* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
3287dd7cddfSDavid du Colombier 	case Qsnarf:
3297dd7cddfSDavid du Colombier 		if(x->f->mode==ORDWR || x->f->mode==OWRITE){
3307dd7cddfSDavid du Colombier 			snarf = runerealloc(snarf, ntsnarf+1);
3317dd7cddfSDavid du Colombier 			cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
3327dd7cddfSDavid du Colombier 			free(tsnarf);
3337dd7cddfSDavid du Colombier 			tsnarf = nil;
3347dd7cddfSDavid du Colombier 			ntsnarf = 0;
3357dd7cddfSDavid du Colombier 		}
3367dd7cddfSDavid du Colombier 		break;
33759cc4ca5SDavid du Colombier 	case Qwctl:
33880ee5cbfSDavid du Colombier 		if(x->f->mode==OREAD || x->f->mode==ORDWR)
33959cc4ca5SDavid du Colombier 			w->wctlopen = FALSE;
34059cc4ca5SDavid du Colombier 		break;
3417dd7cddfSDavid du Colombier 	}
3427dd7cddfSDavid du Colombier 	wclose(w);
3437dd7cddfSDavid du Colombier 	filsysrespond(x->fs, x, &t, nil);
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier void
xfidwrite(Xfid * x)3477dd7cddfSDavid du Colombier xfidwrite(Xfid *x)
3487dd7cddfSDavid du Colombier {
3497dd7cddfSDavid du Colombier 	Fcall fc;
3507dd7cddfSDavid du Colombier 	int c, cnt, qid, nb, off, nr;
3517dd7cddfSDavid du Colombier 	char buf[256], *p;
3527dd7cddfSDavid du Colombier 	Point pt;
3537dd7cddfSDavid du Colombier 	Window *w;
3547dd7cddfSDavid du Colombier 	Rune *r;
3557dd7cddfSDavid du Colombier 	Conswritemesg cwm;
3567dd7cddfSDavid du Colombier 	Stringpair pair;
35780ee5cbfSDavid du Colombier 	enum { CWdata, CWflush, NCW };
35880ee5cbfSDavid du Colombier 	Alt alts[NCW+1];
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 	w = x->f->w;
3617dd7cddfSDavid du Colombier 	if(w->deleted){
3627dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, Edeleted);
3637dd7cddfSDavid du Colombier 		return;
3647dd7cddfSDavid du Colombier 	}
3657dd7cddfSDavid du Colombier 	qid = FILE(x->f->qid);
3667dd7cddfSDavid du Colombier 	cnt = x->count;
3677dd7cddfSDavid du Colombier 	off = x->offset;
3687dd7cddfSDavid du Colombier 	x->data[cnt] = 0;
3697dd7cddfSDavid du Colombier 	switch(qid){
3707dd7cddfSDavid du Colombier 	case Qcons:
3717dd7cddfSDavid du Colombier 		nr = x->f->nrpart;
3727dd7cddfSDavid du Colombier 		if(nr > 0){
3739a747e4fSDavid du Colombier 			memmove(x->data+nr, x->data, cnt);	/* there's room: see malloc in filsysproc */
3747dd7cddfSDavid du Colombier 			memmove(x->data, x->f->rpart, nr);
3757dd7cddfSDavid du Colombier 			cnt += nr;
3767dd7cddfSDavid du Colombier 			x->f->nrpart = 0;
3777dd7cddfSDavid du Colombier 		}
3787dd7cddfSDavid du Colombier 		r = runemalloc(cnt);
3797dd7cddfSDavid du Colombier 		cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
3807dd7cddfSDavid du Colombier 		/* approach end of buffer */
3817dd7cddfSDavid du Colombier 		while(fullrune(x->data+nb, cnt-nb)){
3827dd7cddfSDavid du Colombier 			c = nb;
3837dd7cddfSDavid du Colombier 			nb += chartorune(&r[nr], x->data+c);
3847dd7cddfSDavid du Colombier 			if(r[nr])
3857dd7cddfSDavid du Colombier 				nr++;
3867dd7cddfSDavid du Colombier 		}
3877dd7cddfSDavid du Colombier 		if(nb < cnt){
3887dd7cddfSDavid du Colombier 			memmove(x->f->rpart, x->data+nb, cnt-nb);
3897dd7cddfSDavid du Colombier 			x->f->nrpart = cnt-nb;
3907dd7cddfSDavid du Colombier 		}
3917dd7cddfSDavid du Colombier 		x->flushtag = x->tag;
39280ee5cbfSDavid du Colombier 
39380ee5cbfSDavid du Colombier 		alts[CWdata].c = w->conswrite;
39480ee5cbfSDavid du Colombier 		alts[CWdata].v = &cwm;
39580ee5cbfSDavid du Colombier 		alts[CWdata].op = CHANRCV;
39680ee5cbfSDavid du Colombier 		alts[CWflush].c = x->flushc;
39780ee5cbfSDavid du Colombier 		alts[CWflush].v = nil;
39880ee5cbfSDavid du Colombier 		alts[CWflush].op = CHANRCV;
39980ee5cbfSDavid du Colombier 		alts[NCW].op = CHANEND;
40080ee5cbfSDavid du Colombier 
40180ee5cbfSDavid du Colombier 		switch(alt(alts)){
40280ee5cbfSDavid du Colombier 		case CWdata:
40380ee5cbfSDavid du Colombier 			break;
40480ee5cbfSDavid du Colombier 		case CWflush:
4057dd7cddfSDavid du Colombier 			filsyscancel(x);
4067dd7cddfSDavid du Colombier 			return;
4077dd7cddfSDavid du Colombier 		}
40880ee5cbfSDavid du Colombier 
40980ee5cbfSDavid du Colombier 		/* received data */
41059cc4ca5SDavid du Colombier 		x->flushtag = -1;
4117dd7cddfSDavid du Colombier 		if(x->flushing){
41280ee5cbfSDavid du Colombier 			recv(x->flushc, nil);	/* wake up flushing xfid */
4137dd7cddfSDavid du Colombier 			pair.s = runemalloc(1);
4147dd7cddfSDavid du Colombier 			pair.ns = 0;
4157dd7cddfSDavid du Colombier 			send(cwm.cw, &pair);		/* wake up window with empty data */
4167dd7cddfSDavid du Colombier 			filsyscancel(x);
4177dd7cddfSDavid du Colombier 			return;
4187dd7cddfSDavid du Colombier 		}
4197dd7cddfSDavid du Colombier 		qlock(&x->active);
4207dd7cddfSDavid du Colombier 		pair.s = r;
4217dd7cddfSDavid du Colombier 		pair.ns = nr;
4227dd7cddfSDavid du Colombier 		send(cwm.cw, &pair);
4237dd7cddfSDavid du Colombier 		fc.count = x->count;
4247dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, nil);
4257dd7cddfSDavid du Colombier 		qunlock(&x->active);
4267dd7cddfSDavid du Colombier 		return;
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 	case Qconsctl:
4297dd7cddfSDavid du Colombier 		if(strncmp(x->data, "holdon", 6)==0){
4307dd7cddfSDavid du Colombier 			if(w->holding++ == 0)
4317dd7cddfSDavid du Colombier 				wsendctlmesg(w, Holdon, ZR, nil);
4327dd7cddfSDavid du Colombier 			break;
4337dd7cddfSDavid du Colombier 		}
4347dd7cddfSDavid du Colombier 		if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
4357dd7cddfSDavid du Colombier 			if(--w->holding == FALSE)
4367dd7cddfSDavid du Colombier 				wsendctlmesg(w, Holdoff, ZR, nil);
4377dd7cddfSDavid du Colombier 			break;
4387dd7cddfSDavid du Colombier 		}
4397dd7cddfSDavid du Colombier 		if(strncmp(x->data, "rawon", 5)==0){
4403ff48bf5SDavid du Colombier 			if(w->holding){
4413ff48bf5SDavid du Colombier 				w->holding = FALSE;
4423ff48bf5SDavid du Colombier 				wsendctlmesg(w, Holdoff, ZR, nil);
4433ff48bf5SDavid du Colombier 			}
4447dd7cddfSDavid du Colombier 			if(w->rawing++ == 0)
4457dd7cddfSDavid du Colombier 				wsendctlmesg(w, Rawon, ZR, nil);
4467dd7cddfSDavid du Colombier 			break;
4477dd7cddfSDavid du Colombier 		}
4487dd7cddfSDavid du Colombier 		if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
4497dd7cddfSDavid du Colombier 			if(--w->rawing == 0)
4507dd7cddfSDavid du Colombier 				wsendctlmesg(w, Rawoff, ZR, nil);
4517dd7cddfSDavid du Colombier 			break;
4527dd7cddfSDavid du Colombier 		}
4537dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, "unknown control message");
4547dd7cddfSDavid du Colombier 		return;
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier 	case Qcursor:
4577dd7cddfSDavid du Colombier 		if(cnt < 2*4+2*2*16)
4587dd7cddfSDavid du Colombier 			w->cursorp = nil;
4597dd7cddfSDavid du Colombier 		else{
4607dd7cddfSDavid du Colombier 			w->cursor.offset.x = BGLONG(x->data+0*4);
4617dd7cddfSDavid du Colombier 			w->cursor.offset.y = BGLONG(x->data+1*4);
4627dd7cddfSDavid du Colombier 			memmove(w->cursor.clr, x->data+2*4, 2*2*16);
4637dd7cddfSDavid du Colombier 			w->cursorp = &w->cursor;
4647dd7cddfSDavid du Colombier 		}
4657dd7cddfSDavid du Colombier 		wsetcursor(w, !sweeping);
4667dd7cddfSDavid du Colombier 		break;
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 	case Qlabel:
4699a747e4fSDavid du Colombier 		if(off != 0){
4709a747e4fSDavid du Colombier 			filsysrespond(x->fs, x, &fc, "non-zero offset writing label");
4719a747e4fSDavid du Colombier 			return;
4729a747e4fSDavid du Colombier 		}
4739a747e4fSDavid du Colombier 		free(w->label);
4749a747e4fSDavid du Colombier 		w->label = emalloc(cnt+1);
4759a747e4fSDavid du Colombier 		memmove(w->label, x->data, cnt);
4769a747e4fSDavid du Colombier 		w->label[cnt] = 0;
4777dd7cddfSDavid du Colombier 		break;
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	case Qmouse:
4807dd7cddfSDavid du Colombier 		if(w!=input || Dx(w->screenr)<=0)
4817dd7cddfSDavid du Colombier 			break;
4827dd7cddfSDavid du Colombier 		if(x->data[0] != 'm'){
4837dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, Ebadmouse);
4847dd7cddfSDavid du Colombier 			return;
4857dd7cddfSDavid du Colombier 		}
4867dd7cddfSDavid du Colombier 		p = nil;
4877dd7cddfSDavid du Colombier 		pt.x = strtoul(x->data+1, &p, 0);
4887dd7cddfSDavid du Colombier 		if(p == nil){
4897dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, Eshort);
4907dd7cddfSDavid du Colombier 			return;
4917dd7cddfSDavid du Colombier 		}
4927dd7cddfSDavid du Colombier 		pt.y = strtoul(p, nil, 0);
4937dd7cddfSDavid du Colombier 		if(w==input && wpointto(mouse->xy)==w)
4947dd7cddfSDavid du Colombier 			wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
4957dd7cddfSDavid du Colombier 		break;
4967dd7cddfSDavid du Colombier 
4977dd7cddfSDavid du Colombier 	case Qsnarf:
4987dd7cddfSDavid du Colombier 		/* always append only */
4997dd7cddfSDavid du Colombier 		if(ntsnarf > MAXSNARF){	/* avoid thrashing when people cut huge text */
5007dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, Elong);
5017dd7cddfSDavid du Colombier 			return;
5027dd7cddfSDavid du Colombier 		}
5037dd7cddfSDavid du Colombier 		tsnarf = erealloc(tsnarf, ntsnarf+cnt+1);	/* room for NUL */
5047dd7cddfSDavid du Colombier 		memmove(tsnarf+ntsnarf, x->data, cnt);
5057dd7cddfSDavid du Colombier 		ntsnarf += cnt;
50680ee5cbfSDavid du Colombier 		snarfversion++;
5077dd7cddfSDavid du Colombier 		break;
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier 	case Qwdir:
5107dd7cddfSDavid du Colombier 		if(cnt == 0)
5117dd7cddfSDavid du Colombier 			break;
5127dd7cddfSDavid du Colombier 		if(x->data[cnt-1] == '\n'){
5137dd7cddfSDavid du Colombier 			if(cnt == 1)
5147dd7cddfSDavid du Colombier 				break;
5157dd7cddfSDavid du Colombier 			x->data[cnt-1] = '\0';
5167dd7cddfSDavid du Colombier 		}
5177dd7cddfSDavid du Colombier 		/* assume data comes in a single write */
51880ee5cbfSDavid du Colombier 		/*
51980ee5cbfSDavid du Colombier 		  * Problem: programs like dossrv, ftp produce illegal UTF;
52080ee5cbfSDavid du Colombier 		  * we must cope by converting it first.
52180ee5cbfSDavid du Colombier 		  */
52280ee5cbfSDavid du Colombier 		snprint(buf, sizeof buf, "%.*s", cnt, x->data);
52380ee5cbfSDavid du Colombier 		if(buf[0] == '/'){
5247dd7cddfSDavid du Colombier 			free(w->dir);
52580ee5cbfSDavid du Colombier 			w->dir = estrdup(buf);
5267dd7cddfSDavid du Colombier 		}else{
52780ee5cbfSDavid du Colombier 			p = emalloc(strlen(w->dir) + 1 + strlen(buf) + 1);
52880ee5cbfSDavid du Colombier 			sprint(p, "%s/%s", w->dir, buf);
5297dd7cddfSDavid du Colombier 			free(w->dir);
5307dd7cddfSDavid du Colombier 			w->dir = cleanname(p);
5317dd7cddfSDavid du Colombier 		}
5327dd7cddfSDavid du Colombier 		break;
5337dd7cddfSDavid du Colombier 
53480ee5cbfSDavid du Colombier 	case Qkbdin:
53580ee5cbfSDavid du Colombier 		keyboardsend(x->data, cnt);
53680ee5cbfSDavid du Colombier 		break;
53780ee5cbfSDavid du Colombier 
5387dd7cddfSDavid du Colombier 	case Qwctl:
5397dd7cddfSDavid du Colombier 		if(writewctl(x, buf) < 0){
5407dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, buf);
5417dd7cddfSDavid du Colombier 			return;
5427dd7cddfSDavid du Colombier 		}
5439a747e4fSDavid du Colombier 		flushimage(display, 1);
5447dd7cddfSDavid du Colombier 		break;
5457dd7cddfSDavid du Colombier 
5467dd7cddfSDavid du Colombier 	default:
5479a747e4fSDavid du Colombier 		fprint(2, buf, "unknown qid %d in write\n", qid);
5487dd7cddfSDavid du Colombier 		sprint(buf, "unknown qid in write");
5497dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, buf);
5507dd7cddfSDavid du Colombier 		return;
5517dd7cddfSDavid du Colombier 	}
5527dd7cddfSDavid du Colombier 	fc.count = cnt;
5537dd7cddfSDavid du Colombier 	filsysrespond(x->fs, x, &fc, nil);
5547dd7cddfSDavid du Colombier }
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier int
readwindow(Image * i,char * t,Rectangle r,int offset,int n)5579a747e4fSDavid du Colombier readwindow(Image *i, char *t, Rectangle r, int offset, int n)
5587dd7cddfSDavid du Colombier {
5597dd7cddfSDavid du Colombier 	int ww, y;
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	offset -= 5*12;
5629a747e4fSDavid du Colombier 	ww = bytesperline(r, screen->depth);
5637dd7cddfSDavid du Colombier 	r.min.y += offset/ww;
5647dd7cddfSDavid du Colombier 	if(r.min.y >= r.max.y)
5657dd7cddfSDavid du Colombier 		return 0;
5667dd7cddfSDavid du Colombier 	y = r.min.y + n/ww;
5677dd7cddfSDavid du Colombier 	if(y < r.max.y)
5687dd7cddfSDavid du Colombier 		r.max.y = y;
5697dd7cddfSDavid du Colombier 	if(r.max.y <= r.min.y)
5707dd7cddfSDavid du Colombier 		return 0;
5719a747e4fSDavid du Colombier 	return unloadimage(i, r, (uchar*)t, n);
5727dd7cddfSDavid du Colombier }
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier void
xfidread(Xfid * x)5757dd7cddfSDavid du Colombier xfidread(Xfid *x)
5767dd7cddfSDavid du Colombier {
5777dd7cddfSDavid du Colombier 	Fcall fc;
57880ee5cbfSDavid du Colombier 	int n, off, cnt, c;
5797dd7cddfSDavid du Colombier 	uint qid;
5807dd7cddfSDavid du Colombier 	char buf[128], *t;
5817dd7cddfSDavid du Colombier 	char cbuf[30];
5827dd7cddfSDavid du Colombier 	Window *w;
5837dd7cddfSDavid du Colombier 	Mouse ms;
5847dd7cddfSDavid du Colombier 	Rectangle r;
5857dd7cddfSDavid du Colombier 	Image *i;
5867dd7cddfSDavid du Colombier 	Channel *c1, *c2;	/* chan (tuple(char*, int)) */
5877dd7cddfSDavid du Colombier 	Consreadmesg crm;
5887dd7cddfSDavid du Colombier 	Mousereadmesg mrm;
58959cc4ca5SDavid du Colombier 	Consreadmesg cwrm;
5907dd7cddfSDavid du Colombier 	Stringpair pair;
59180ee5cbfSDavid du Colombier 	enum { CRdata, CRflush, NCR };
59280ee5cbfSDavid du Colombier 	enum { MRdata, MRflush, NMR };
59380ee5cbfSDavid du Colombier 	enum { WCRdata, WCRflush, NWCR };
59480ee5cbfSDavid du Colombier 	Alt alts[NCR+1];
5957dd7cddfSDavid du Colombier 
5967dd7cddfSDavid du Colombier 	w = x->f->w;
5977dd7cddfSDavid du Colombier 	if(w->deleted){
5987dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, Edeleted);
5997dd7cddfSDavid du Colombier 		return;
6007dd7cddfSDavid du Colombier 	}
6017dd7cddfSDavid du Colombier 	qid = FILE(x->f->qid);
6027dd7cddfSDavid du Colombier 	off = x->offset;
6037dd7cddfSDavid du Colombier 	cnt = x->count;
6047dd7cddfSDavid du Colombier 	switch(qid){
6057dd7cddfSDavid du Colombier 	case Qcons:
6067dd7cddfSDavid du Colombier 		x->flushtag = x->tag;
60780ee5cbfSDavid du Colombier 
60880ee5cbfSDavid du Colombier 		alts[CRdata].c = w->consread;
60980ee5cbfSDavid du Colombier 		alts[CRdata].v = &crm;
61080ee5cbfSDavid du Colombier 		alts[CRdata].op = CHANRCV;
61180ee5cbfSDavid du Colombier 		alts[CRflush].c = x->flushc;
61280ee5cbfSDavid du Colombier 		alts[CRflush].v = nil;
61380ee5cbfSDavid du Colombier 		alts[CRflush].op = CHANRCV;
61480ee5cbfSDavid du Colombier 		alts[NMR].op = CHANEND;
61580ee5cbfSDavid du Colombier 
61680ee5cbfSDavid du Colombier 		switch(alt(alts)){
61780ee5cbfSDavid du Colombier 		case CRdata:
61880ee5cbfSDavid du Colombier 			break;
61980ee5cbfSDavid du Colombier 		case CRflush:
6207dd7cddfSDavid du Colombier 			filsyscancel(x);
6217dd7cddfSDavid du Colombier 			return;
6227dd7cddfSDavid du Colombier 		}
62380ee5cbfSDavid du Colombier 
62480ee5cbfSDavid du Colombier 		/* received data */
62580ee5cbfSDavid du Colombier 		x->flushtag = -1;
62680ee5cbfSDavid du Colombier 		c1 = crm.c1;
62780ee5cbfSDavid du Colombier 		c2 = crm.c2;
6287dd7cddfSDavid du Colombier 		t = malloc(cnt+UTFmax+1);	/* room to unpack partial rune plus */
6297dd7cddfSDavid du Colombier 		pair.s = t;
6307dd7cddfSDavid du Colombier 		pair.ns = cnt;
6317dd7cddfSDavid du Colombier 		send(c1, &pair);
6327dd7cddfSDavid du Colombier 		if(x->flushing){
63380ee5cbfSDavid du Colombier 			recv(x->flushc, nil);	/* wake up flushing xfid */
6347dd7cddfSDavid du Colombier 			recv(c2, nil);			/* wake up window and toss data */
6357dd7cddfSDavid du Colombier 			free(t);
6367dd7cddfSDavid du Colombier 			filsyscancel(x);
6377dd7cddfSDavid du Colombier 			return;
6387dd7cddfSDavid du Colombier 		}
6397dd7cddfSDavid du Colombier 		qlock(&x->active);
6407dd7cddfSDavid du Colombier 		recv(c2, &pair);
6417dd7cddfSDavid du Colombier 		fc.data = pair.s;
6427dd7cddfSDavid du Colombier 		fc.count = pair.ns;
6437dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, nil);
6447dd7cddfSDavid du Colombier 		free(t);
6457dd7cddfSDavid du Colombier 		qunlock(&x->active);
6467dd7cddfSDavid du Colombier 		break;
6477dd7cddfSDavid du Colombier 
6487dd7cddfSDavid du Colombier 	case Qlabel:
6497dd7cddfSDavid du Colombier 		n = strlen(w->label);
6507dd7cddfSDavid du Colombier 		if(off > n)
6517dd7cddfSDavid du Colombier 			off = n;
6527dd7cddfSDavid du Colombier 		if(off+cnt > n)
6537dd7cddfSDavid du Colombier 			cnt = n-off;
6547dd7cddfSDavid du Colombier 		fc.data = w->label+off;
6557dd7cddfSDavid du Colombier 		fc.count = cnt;
6567dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, nil);
6577dd7cddfSDavid du Colombier 		break;
6587dd7cddfSDavid du Colombier 
6597dd7cddfSDavid du Colombier 	case Qmouse:
6607dd7cddfSDavid du Colombier 		x->flushtag = x->tag;
66180ee5cbfSDavid du Colombier 
66280ee5cbfSDavid du Colombier 		alts[MRdata].c = w->mouseread;
66380ee5cbfSDavid du Colombier 		alts[MRdata].v = &mrm;
66480ee5cbfSDavid du Colombier 		alts[MRdata].op = CHANRCV;
66580ee5cbfSDavid du Colombier 		alts[MRflush].c = x->flushc;
66680ee5cbfSDavid du Colombier 		alts[MRflush].v = nil;
66780ee5cbfSDavid du Colombier 		alts[MRflush].op = CHANRCV;
66880ee5cbfSDavid du Colombier 		alts[NMR].op = CHANEND;
66980ee5cbfSDavid du Colombier 
67080ee5cbfSDavid du Colombier 		switch(alt(alts)){
67180ee5cbfSDavid du Colombier 		case MRdata:
67280ee5cbfSDavid du Colombier 			break;
67380ee5cbfSDavid du Colombier 		case MRflush:
6747dd7cddfSDavid du Colombier 			filsyscancel(x);
6757dd7cddfSDavid du Colombier 			return;
6767dd7cddfSDavid du Colombier 		}
67780ee5cbfSDavid du Colombier 
67880ee5cbfSDavid du Colombier 		/* received data */
67959cc4ca5SDavid du Colombier 		x->flushtag = -1;
6807dd7cddfSDavid du Colombier 		if(x->flushing){
68180ee5cbfSDavid du Colombier 			recv(x->flushc, nil);		/* wake up flushing xfid */
68280ee5cbfSDavid du Colombier 			recv(mrm.cm, nil);			/* wake up window and toss data */
6837dd7cddfSDavid du Colombier 			filsyscancel(x);
6847dd7cddfSDavid du Colombier 			return;
6857dd7cddfSDavid du Colombier 		}
6867dd7cddfSDavid du Colombier 		qlock(&x->active);
68780ee5cbfSDavid du Colombier 		recv(mrm.cm, &ms);
6887dd7cddfSDavid du Colombier 		c = 'm';
6897dd7cddfSDavid du Colombier 		if(w->resized)
6907dd7cddfSDavid du Colombier 			c = 'r';
6917dd7cddfSDavid du Colombier 		n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
6927dd7cddfSDavid du Colombier 		w->resized = 0;
6937dd7cddfSDavid du Colombier 		fc.data = buf;
6947dd7cddfSDavid du Colombier 		fc.count = min(n, cnt);
6957dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, nil);
6967dd7cddfSDavid du Colombier 		qunlock(&x->active);
6977dd7cddfSDavid du Colombier 		break;
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier 	case Qcursor:
7007dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, "cursor read not implemented");
7017dd7cddfSDavid du Colombier 		break;
7027dd7cddfSDavid du Colombier 
7037dd7cddfSDavid du Colombier 	/* The algorithm for snarf and text is expensive but easy and rarely used */
7047dd7cddfSDavid du Colombier 	case Qsnarf:
70580ee5cbfSDavid du Colombier 		getsnarf();
7067dd7cddfSDavid du Colombier 		if(nsnarf)
7077dd7cddfSDavid du Colombier 			t = runetobyte(snarf, nsnarf, &n);
7087dd7cddfSDavid du Colombier 		else {
7097dd7cddfSDavid du Colombier 			t = nil;
7107dd7cddfSDavid du Colombier 			n = 0;
7117dd7cddfSDavid du Colombier 		}
7127dd7cddfSDavid du Colombier 		goto Text;
7137dd7cddfSDavid du Colombier 
7147dd7cddfSDavid du Colombier 	case Qtext:
7157dd7cddfSDavid du Colombier 		t = wcontents(w, &n);
7167dd7cddfSDavid du Colombier 		goto Text;
7177dd7cddfSDavid du Colombier 
7187dd7cddfSDavid du Colombier 	Text:
7197dd7cddfSDavid du Colombier 		if(off > n){
7207dd7cddfSDavid du Colombier 			off = n;
7217dd7cddfSDavid du Colombier 			cnt = 0;
7227dd7cddfSDavid du Colombier 		}
7237dd7cddfSDavid du Colombier 		if(off+cnt > n)
7247dd7cddfSDavid du Colombier 			cnt = n-off;
7257dd7cddfSDavid du Colombier 		fc.data = t+off;
7267dd7cddfSDavid du Colombier 		fc.count = cnt;
7277dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, nil);
7287dd7cddfSDavid du Colombier 		free(t);
7297dd7cddfSDavid du Colombier 		break;
7307dd7cddfSDavid du Colombier 
7317dd7cddfSDavid du Colombier 	case Qwdir:
7327dd7cddfSDavid du Colombier 		t = estrdup(w->dir);
7337dd7cddfSDavid du Colombier 		n = strlen(t);
7347dd7cddfSDavid du Colombier 		goto Text;
7357dd7cddfSDavid du Colombier 
7367dd7cddfSDavid du Colombier 	case Qwinid:
7377dd7cddfSDavid du Colombier 		n = sprint(buf, "%11d ", w->id);
7387dd7cddfSDavid du Colombier 		t = estrdup(buf);
7397dd7cddfSDavid du Colombier 		goto Text;
7407dd7cddfSDavid du Colombier 
7417dd7cddfSDavid du Colombier 
7427dd7cddfSDavid du Colombier 	case Qwinname:
7437dd7cddfSDavid du Colombier 		n = strlen(w->name);
7447dd7cddfSDavid du Colombier 		if(n == 0){
7457dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, "window has no name");
7467dd7cddfSDavid du Colombier 			break;
7477dd7cddfSDavid du Colombier 		}
7487dd7cddfSDavid du Colombier 		t = estrdup(w->name);
7497dd7cddfSDavid du Colombier 		goto Text;
7507dd7cddfSDavid du Colombier 
7517dd7cddfSDavid du Colombier 	case Qwindow:
7527dd7cddfSDavid du Colombier 		i = w->i;
75380ee5cbfSDavid du Colombier 		if(i == nil || Dx(w->screenr)<=0){
7547dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, Enowindow);
7557dd7cddfSDavid du Colombier 			return;
7567dd7cddfSDavid du Colombier 		}
7577dd7cddfSDavid du Colombier 		r = w->screenr;
7587dd7cddfSDavid du Colombier 		goto caseImage;
7597dd7cddfSDavid du Colombier 
7607dd7cddfSDavid du Colombier 	case Qscreen:
7617dd7cddfSDavid du Colombier 		i = display->image;
7629a747e4fSDavid du Colombier 		if(i == nil){
7639a747e4fSDavid du Colombier 			filsysrespond(x->fs, x, &fc, "no top-level screen");
7649a747e4fSDavid du Colombier 			break;
7659a747e4fSDavid du Colombier 		}
7667dd7cddfSDavid du Colombier 		r = i->r;
7677dd7cddfSDavid du Colombier 		/* fall through */
7687dd7cddfSDavid du Colombier 
7697dd7cddfSDavid du Colombier 	caseImage:
7707dd7cddfSDavid du Colombier 		if(off < 5*12){
7717dd7cddfSDavid du Colombier 			n = sprint(buf, "%11s %11d %11d %11d %11d ",
7729a747e4fSDavid du Colombier 				chantostr(cbuf, screen->chan),
7737dd7cddfSDavid du Colombier 				i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y);
7747dd7cddfSDavid du Colombier 			t = estrdup(buf);
7757dd7cddfSDavid du Colombier 			goto Text;
7767dd7cddfSDavid du Colombier 		}
7777dd7cddfSDavid du Colombier 		t = malloc(cnt);
7787dd7cddfSDavid du Colombier 		fc.data = t;
7799a747e4fSDavid du Colombier 		n = readwindow(i, t, r, off, cnt);	/* careful; fc.count is unsigned */
7809a747e4fSDavid du Colombier 		if(n < 0){
7817dd7cddfSDavid du Colombier 			buf[0] = 0;
7829a747e4fSDavid du Colombier 			errstr(buf, sizeof buf);
7837dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, buf);
7849a747e4fSDavid du Colombier 		}else{
7859a747e4fSDavid du Colombier 			fc.count = n;
7867dd7cddfSDavid du Colombier 			filsysrespond(x->fs, x, &fc, nil);
7879a747e4fSDavid du Colombier 		}
7887dd7cddfSDavid du Colombier 		free(t);
7897dd7cddfSDavid du Colombier 		return;
7907dd7cddfSDavid du Colombier 
79159cc4ca5SDavid du Colombier 	case Qwctl:	/* read returns rectangle, hangs if not resized */
79259cc4ca5SDavid du Colombier 		if(cnt < 4*12){
79359cc4ca5SDavid du Colombier 			filsysrespond(x->fs, x, &fc, Etooshort);
79459cc4ca5SDavid du Colombier 			break;
79559cc4ca5SDavid du Colombier 		}
79659cc4ca5SDavid du Colombier 		x->flushtag = x->tag;
79780ee5cbfSDavid du Colombier 
79880ee5cbfSDavid du Colombier 		alts[WCRdata].c = w->wctlread;
79980ee5cbfSDavid du Colombier 		alts[WCRdata].v = &cwrm;
80080ee5cbfSDavid du Colombier 		alts[WCRdata].op = CHANRCV;
80180ee5cbfSDavid du Colombier 		alts[WCRflush].c = x->flushc;
80280ee5cbfSDavid du Colombier 		alts[WCRflush].v = nil;
80380ee5cbfSDavid du Colombier 		alts[WCRflush].op = CHANRCV;
80480ee5cbfSDavid du Colombier 		alts[NMR].op = CHANEND;
80580ee5cbfSDavid du Colombier 
80680ee5cbfSDavid du Colombier 		switch(alt(alts)){
80780ee5cbfSDavid du Colombier 		case WCRdata:
80880ee5cbfSDavid du Colombier 			break;
80980ee5cbfSDavid du Colombier 		case WCRflush:
81059cc4ca5SDavid du Colombier 			filsyscancel(x);
81159cc4ca5SDavid du Colombier 			return;
81259cc4ca5SDavid du Colombier 		}
81380ee5cbfSDavid du Colombier 
81480ee5cbfSDavid du Colombier 		/* received data */
81559cc4ca5SDavid du Colombier 		x->flushtag = -1;
81680ee5cbfSDavid du Colombier 		c1 = cwrm.c1;
81780ee5cbfSDavid du Colombier 		c2 = cwrm.c2;
81880ee5cbfSDavid du Colombier 		t = malloc(cnt+1);	/* be sure to have room for NUL */
81980ee5cbfSDavid du Colombier 		pair.s = t;
82080ee5cbfSDavid du Colombier 		pair.ns = cnt+1;
82180ee5cbfSDavid du Colombier 		send(c1, &pair);
82259cc4ca5SDavid du Colombier 		if(x->flushing){
82380ee5cbfSDavid du Colombier 			recv(x->flushc, nil);	/* wake up flushing xfid */
82459cc4ca5SDavid du Colombier 			recv(c2, nil);			/* wake up window and toss data */
82559cc4ca5SDavid du Colombier 			free(t);
82659cc4ca5SDavid du Colombier 			filsyscancel(x);
82759cc4ca5SDavid du Colombier 			return;
82859cc4ca5SDavid du Colombier 		}
82959cc4ca5SDavid du Colombier 		qlock(&x->active);
83059cc4ca5SDavid du Colombier 		recv(c2, &pair);
83159cc4ca5SDavid du Colombier 		fc.data = pair.s;
83280ee5cbfSDavid du Colombier 		if(pair.ns > cnt)
83380ee5cbfSDavid du Colombier 			pair.ns = cnt;
83459cc4ca5SDavid du Colombier 		fc.count = pair.ns;
83559cc4ca5SDavid du Colombier 		filsysrespond(x->fs, x, &fc, nil);
83659cc4ca5SDavid du Colombier 		free(t);
83759cc4ca5SDavid du Colombier 		qunlock(&x->active);
83859cc4ca5SDavid du Colombier 		break;
83959cc4ca5SDavid du Colombier 
8407dd7cddfSDavid du Colombier 	default:
8419a747e4fSDavid du Colombier 		fprint(2, "unknown qid %d in read\n", qid);
8427dd7cddfSDavid du Colombier 		sprint(buf, "unknown qid in read");
8437dd7cddfSDavid du Colombier 		filsysrespond(x->fs, x, &fc, buf);
8447dd7cddfSDavid du Colombier 		break;
8457dd7cddfSDavid du Colombier 	}
8467dd7cddfSDavid du Colombier }
847