xref: /plan9/sys/src/cmd/rio/wind.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
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>
11fe853e23SDavid du Colombier #include <complete.h>
127dd7cddfSDavid du Colombier #include "dat.h"
137dd7cddfSDavid du Colombier #include "fns.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier #define MOVEIT if(0)
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier enum
187dd7cddfSDavid du Colombier {
1915b88db3SDavid du Colombier 	HiWater	= 640000,	/* max size of history */
2015b88db3SDavid du Colombier 	LoWater	= 400000,	/* min size of history after max'ed */
2115b88db3SDavid du Colombier 	MinWater	= 20000,	/* room to leave available when reallocating */
227dd7cddfSDavid du Colombier };
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier static	int		topped;
257dd7cddfSDavid du Colombier static	int		id;
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier static	Image	*cols[NCOL];
287dd7cddfSDavid du Colombier static	Image	*grey;
297dd7cddfSDavid du Colombier static	Image	*darkgrey;
307dd7cddfSDavid du Colombier static	Cursor	*lastcursor;
317dd7cddfSDavid du Colombier static	Image	*titlecol;
327dd7cddfSDavid du Colombier static	Image	*lighttitlecol;
337dd7cddfSDavid du Colombier static	Image	*holdcol;
347dd7cddfSDavid du Colombier static	Image	*lightholdcol;
357dd7cddfSDavid du Colombier static	Image	*paleholdcol;
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier Window*
wmk(Image * i,Mousectl * mc,Channel * ck,Channel * cctl,int scrolling)383ff48bf5SDavid du Colombier wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 	Window *w;
417dd7cddfSDavid du Colombier 	Rectangle r;
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	if(cols[0] == nil){
447dd7cddfSDavid du Colombier 		/* greys are multiples of 0x11111100+0xFF, 14* being palest */
457dd7cddfSDavid du Colombier 		grey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
467dd7cddfSDavid du Colombier 		darkgrey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF);
477dd7cddfSDavid du Colombier 		cols[BACK] = display->white;
487dd7cddfSDavid du Colombier 		cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
497dd7cddfSDavid du Colombier 		cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF);
507dd7cddfSDavid du Colombier 		cols[TEXT] = display->black;
517dd7cddfSDavid du Colombier 		cols[HTEXT] = display->black;
527dd7cddfSDavid du Colombier 		titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
537dd7cddfSDavid du Colombier 		lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
547dd7cddfSDavid du Colombier 		holdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
557dd7cddfSDavid du Colombier 		lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
567dd7cddfSDavid du Colombier 		paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
577dd7cddfSDavid du Colombier 	}
587dd7cddfSDavid du Colombier 	w = emalloc(sizeof(Window));
597dd7cddfSDavid du Colombier 	w->screenr = i->r;
607dd7cddfSDavid du Colombier 	r = insetrect(i->r, Selborder+1);
617dd7cddfSDavid du Colombier 	w->i = i;
627dd7cddfSDavid du Colombier 	w->mc = *mc;
637dd7cddfSDavid du Colombier 	w->ck = ck;
647dd7cddfSDavid du Colombier 	w->cctl = cctl;
657dd7cddfSDavid du Colombier 	w->cursorp = nil;
667dd7cddfSDavid du Colombier 	w->conswrite = chancreate(sizeof(Conswritemesg), 0);
677dd7cddfSDavid du Colombier 	w->consread =  chancreate(sizeof(Consreadmesg), 0);
687dd7cddfSDavid du Colombier 	w->mouseread =  chancreate(sizeof(Mousereadmesg), 0);
6959cc4ca5SDavid du Colombier 	w->wctlread =  chancreate(sizeof(Consreadmesg), 0);
707dd7cddfSDavid du Colombier 	w->scrollr = r;
717dd7cddfSDavid du Colombier 	w->scrollr.max.x = r.min.x+Scrollwid;
727dd7cddfSDavid du Colombier 	w->lastsr = ZR;
737dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
747dd7cddfSDavid du Colombier 	frinit(w, r, font, i, cols);
757dd7cddfSDavid du Colombier 	w->maxtab = maxtab*stringwidth(font, "0");
767dd7cddfSDavid du Colombier 	w->topped = ++topped;
777dd7cddfSDavid du Colombier 	w->id = ++id;
787dd7cddfSDavid du Colombier 	w->notefd = -1;
797dd7cddfSDavid du Colombier 	w->scrolling = scrolling;
807dd7cddfSDavid du Colombier 	w->dir = estrdup(startdir);
819a747e4fSDavid du Colombier 	w->label = estrdup("<unnamed>");
827dd7cddfSDavid du Colombier 	r = insetrect(w->i->r, Selborder);
837dd7cddfSDavid du Colombier 	draw(w->i, r, cols[BACK], nil, w->entire.min);
847dd7cddfSDavid du Colombier 	wborder(w, Selborder);
857dd7cddfSDavid du Colombier 	wscrdraw(w);
867dd7cddfSDavid du Colombier 	incref(w);	/* ref will be removed after mounting; avoids delete before ready to be deleted */
877dd7cddfSDavid du Colombier 	return w;
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier void
wsetname(Window * w)917dd7cddfSDavid du Colombier wsetname(Window *w)
927dd7cddfSDavid du Colombier {
937dd7cddfSDavid du Colombier 	int i, n;
949a747e4fSDavid du Colombier 	char err[ERRMAX];
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier 	n = sprint(w->name, "window.%d.%d", w->id, w->namecount++);
977dd7cddfSDavid du Colombier 	for(i='A'; i<='Z'; i++){
987dd7cddfSDavid du Colombier 		if(nameimage(w->i, w->name, 1) > 0)
997dd7cddfSDavid du Colombier 			return;
1009a747e4fSDavid du Colombier 		errstr(err, sizeof err);
1017dd7cddfSDavid du Colombier 		if(strcmp(err, "image name in use") != 0)
1027dd7cddfSDavid du Colombier 			break;
1037dd7cddfSDavid du Colombier 		w->name[n] = i;
1047dd7cddfSDavid du Colombier 		w->name[n+1] = 0;
1057dd7cddfSDavid du Colombier 	}
1067dd7cddfSDavid du Colombier 	w->name[0] = 0;
1079a747e4fSDavid du Colombier 	fprint(2, "rio: setname failed: %s\n", err);
1087dd7cddfSDavid du Colombier }
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier void
wresize(Window * w,Image * i,int move)1117dd7cddfSDavid du Colombier wresize(Window *w, Image *i, int move)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier 	Rectangle r, or;
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier 	or = w->i->r;
1167dd7cddfSDavid du Colombier 	if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(i->r)))
1177dd7cddfSDavid du Colombier 		draw(i, i->r, w->i, nil, w->i->r.min);
1187dd7cddfSDavid du Colombier 	freeimage(w->i);
1197dd7cddfSDavid du Colombier 	w->i = i;
1209a747e4fSDavid du Colombier 	wsetname(w);
1217dd7cddfSDavid du Colombier 	w->mc.image = i;
1227dd7cddfSDavid du Colombier 	r = insetrect(i->r, Selborder+1);
1237dd7cddfSDavid du Colombier 	w->scrollr = r;
1247dd7cddfSDavid du Colombier 	w->scrollr.max.x = r.min.x+Scrollwid;
1257dd7cddfSDavid du Colombier 	w->lastsr = ZR;
1267dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
1277dd7cddfSDavid du Colombier 	if(move)
1287dd7cddfSDavid du Colombier 		frsetrects(w, r, w->i);
1297dd7cddfSDavid du Colombier 	else{
1307dd7cddfSDavid du Colombier 		frclear(w, FALSE);
1317dd7cddfSDavid du Colombier 		frinit(w, r, w->font, w->i, cols);
1327dd7cddfSDavid du Colombier 		wsetcols(w);
1337dd7cddfSDavid du Colombier 		w->maxtab = maxtab*stringwidth(w->font, "0");
1347dd7cddfSDavid du Colombier 		r = insetrect(w->i->r, Selborder);
1357dd7cddfSDavid du Colombier 		draw(w->i, r, cols[BACK], nil, w->entire.min);
1367dd7cddfSDavid du Colombier 		wfill(w);
1377dd7cddfSDavid du Colombier 		wsetselect(w, w->q0, w->q1);
1387dd7cddfSDavid du Colombier 		wscrdraw(w);
1397dd7cddfSDavid du Colombier 	}
1407dd7cddfSDavid du Colombier 	wborder(w, Selborder);
1417dd7cddfSDavid du Colombier 	w->topped = ++topped;
1427dd7cddfSDavid du Colombier 	w->resized = TRUE;
1437dd7cddfSDavid du Colombier 	w->mouse.counter++;
1447dd7cddfSDavid du Colombier }
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier void
wrefresh(Window * w,Rectangle)1477dd7cddfSDavid du Colombier wrefresh(Window *w, Rectangle)
1487dd7cddfSDavid du Colombier {
1497dd7cddfSDavid du Colombier 	/* BUG: rectangle is ignored */
1507dd7cddfSDavid du Colombier 	if(w == input)
1517dd7cddfSDavid du Colombier 		wborder(w, Selborder);
1527dd7cddfSDavid du Colombier 	else
1537dd7cddfSDavid du Colombier 		wborder(w, Unselborder);
1547dd7cddfSDavid du Colombier 	if(w->mouseopen)
1557dd7cddfSDavid du Colombier 		return;
1567dd7cddfSDavid du Colombier 	draw(w->i, insetrect(w->i->r, Borderwidth), w->cols[BACK], nil, w->i->r.min);
1577dd7cddfSDavid du Colombier 	w->ticked = 0;
1587dd7cddfSDavid du Colombier 	if(w->p0 > 0)
1597dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);
1607dd7cddfSDavid du Colombier 	if(w->p1 < w->nchars)
1617dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);
1627dd7cddfSDavid du Colombier 	frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);
1637dd7cddfSDavid du Colombier 	w->lastsr = ZR;
1647dd7cddfSDavid du Colombier 	wscrdraw(w);
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier int
wclose(Window * w)1687dd7cddfSDavid du Colombier wclose(Window *w)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	int i;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	i = decref(w);
1737dd7cddfSDavid du Colombier 	if(i > 0)
1747dd7cddfSDavid du Colombier 		return 0;
1757dd7cddfSDavid du Colombier 	if(i < 0)
1767dd7cddfSDavid du Colombier 		error("negative ref count");
1777dd7cddfSDavid du Colombier 	if(!w->deleted)
1787dd7cddfSDavid du Colombier 		wclosewin(w);
1797dd7cddfSDavid du Colombier 	wsendctlmesg(w, Exited, ZR, nil);
1807dd7cddfSDavid du Colombier 	return 1;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 
1847dd7cddfSDavid du Colombier void
winctl(void * arg)1857dd7cddfSDavid du Colombier winctl(void *arg)
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier 	Rune *rp, *bp, *tp, *up, *kbdr;
1887dd7cddfSDavid du Colombier 	uint qh;
1897dd7cddfSDavid du Colombier 	int nr, nb, c, wid, i, npart, initial, lastb;
19080ee5cbfSDavid du Colombier 	char *s, *t, part[3];
1917dd7cddfSDavid du Colombier 	Window *w;
1927dd7cddfSDavid du Colombier 	Mousestate *mp, m;
19359cc4ca5SDavid du Colombier 	enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT };
1947dd7cddfSDavid du Colombier 	Alt alts[NWALT+1];
1957dd7cddfSDavid du Colombier 	Mousereadmesg mrm;
1967dd7cddfSDavid du Colombier 	Conswritemesg cwm;
1977dd7cddfSDavid du Colombier 	Consreadmesg crm;
19859cc4ca5SDavid du Colombier 	Consreadmesg cwrm;
1997dd7cddfSDavid du Colombier 	Stringpair pair;
2007dd7cddfSDavid du Colombier 	Wctlmesg wcm;
20159cc4ca5SDavid du Colombier 	char buf[4*12+1];
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier 	w = arg;
20459cc4ca5SDavid du Colombier 	snprint(buf, sizeof buf, "winctl-id%d", w->id);
2057dd7cddfSDavid du Colombier 	threadsetname(buf);
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	mrm.cm = chancreate(sizeof(Mouse), 0);
2087dd7cddfSDavid du Colombier 	cwm.cw = chancreate(sizeof(Stringpair), 0);
2097dd7cddfSDavid du Colombier 	crm.c1 = chancreate(sizeof(Stringpair), 0);
2107dd7cddfSDavid du Colombier 	crm.c2 = chancreate(sizeof(Stringpair), 0);
21159cc4ca5SDavid du Colombier 	cwrm.c1 = chancreate(sizeof(Stringpair), 0);
21259cc4ca5SDavid du Colombier 	cwrm.c2 = chancreate(sizeof(Stringpair), 0);
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 
2157dd7cddfSDavid du Colombier 	alts[WKey].c = w->ck;
2167dd7cddfSDavid du Colombier 	alts[WKey].v = &kbdr;
2177dd7cddfSDavid du Colombier 	alts[WKey].op = CHANRCV;
2187dd7cddfSDavid du Colombier 	alts[WMouse].c = w->mc.c;
2197dd7cddfSDavid du Colombier 	alts[WMouse].v = &w->mc.Mouse;
2207dd7cddfSDavid du Colombier 	alts[WMouse].op = CHANRCV;
2217dd7cddfSDavid du Colombier 	alts[WMouseread].c = w->mouseread;
2227dd7cddfSDavid du Colombier 	alts[WMouseread].v = &mrm;
2237dd7cddfSDavid du Colombier 	alts[WMouseread].op = CHANSND;
2247dd7cddfSDavid du Colombier 	alts[WCtl].c = w->cctl;
2257dd7cddfSDavid du Colombier 	alts[WCtl].v = &wcm;
2267dd7cddfSDavid du Colombier 	alts[WCtl].op = CHANRCV;
2277dd7cddfSDavid du Colombier 	alts[WCwrite].c = w->conswrite;
2287dd7cddfSDavid du Colombier 	alts[WCwrite].v = &cwm;
2297dd7cddfSDavid du Colombier 	alts[WCwrite].op = CHANSND;
2307dd7cddfSDavid du Colombier 	alts[WCread].c = w->consread;
2317dd7cddfSDavid du Colombier 	alts[WCread].v = &crm;
2327dd7cddfSDavid du Colombier 	alts[WCread].op = CHANSND;
23359cc4ca5SDavid du Colombier 	alts[WWread].c = w->wctlread;
23459cc4ca5SDavid du Colombier 	alts[WWread].v = &cwrm;
23559cc4ca5SDavid du Colombier 	alts[WWread].op = CHANSND;
2367dd7cddfSDavid du Colombier 	alts[NWALT].op = CHANEND;
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier 	npart = 0;
2397dd7cddfSDavid du Colombier 	lastb = -1;
2407dd7cddfSDavid du Colombier 	for(;;){
2417dd7cddfSDavid du Colombier 		if(w->mouseopen && w->mouse.counter != w->mouse.lastcounter)
2427dd7cddfSDavid du Colombier 			alts[WMouseread].op = CHANSND;
2437dd7cddfSDavid du Colombier 		else
2447dd7cddfSDavid du Colombier 			alts[WMouseread].op = CHANNOP;
2457dd7cddfSDavid du Colombier 		if(!w->scrolling && !w->mouseopen && w->qh>w->org+w->nchars)
2467dd7cddfSDavid du Colombier 			alts[WCwrite].op = CHANNOP;
2477dd7cddfSDavid du Colombier 		else
2487dd7cddfSDavid du Colombier 			alts[WCwrite].op = CHANSND;
24959cc4ca5SDavid du Colombier 		if(w->deleted || !w->wctlready)
25059cc4ca5SDavid du Colombier 			alts[WWread].op = CHANNOP;
25159cc4ca5SDavid du Colombier 		else
25259cc4ca5SDavid du Colombier 			alts[WWread].op = CHANSND;
2537dd7cddfSDavid du Colombier 		/* this code depends on NL and EOT fitting in a single byte */
2547dd7cddfSDavid du Colombier 		/* kind of expensive for each loop; worth precomputing? */
2557dd7cddfSDavid du Colombier 		if(w->holding)
2567dd7cddfSDavid du Colombier 			alts[WCread].op = CHANNOP;
2577dd7cddfSDavid du Colombier 		else if(npart || (w->rawing && w->nraw>0))
2587dd7cddfSDavid du Colombier 			alts[WCread].op = CHANSND;
2597dd7cddfSDavid du Colombier 		else{
2607dd7cddfSDavid du Colombier 			alts[WCread].op = CHANNOP;
2617dd7cddfSDavid du Colombier 			for(i=w->qh; i<w->nr; i++){
2627dd7cddfSDavid du Colombier 				c = w->r[i];
2637dd7cddfSDavid du Colombier 				if(c=='\n' || c=='\004'){
2647dd7cddfSDavid du Colombier 					alts[WCread].op = CHANSND;
2657dd7cddfSDavid du Colombier 					break;
2667dd7cddfSDavid du Colombier 				}
2677dd7cddfSDavid du Colombier 			}
2687dd7cddfSDavid du Colombier 		}
2697dd7cddfSDavid du Colombier 		switch(alt(alts)){
2707dd7cddfSDavid du Colombier 		case WKey:
2717dd7cddfSDavid du Colombier 			for(i=0; kbdr[i]!=L'\0'; i++)
2727dd7cddfSDavid du Colombier 				wkeyctl(w, kbdr[i]);
2737dd7cddfSDavid du Colombier //			wkeyctl(w, r);
2747dd7cddfSDavid du Colombier ///			while(nbrecv(w->ck, &r))
2757dd7cddfSDavid du Colombier //				wkeyctl(w, r);
2767dd7cddfSDavid du Colombier 			break;
2777dd7cddfSDavid du Colombier 		case WMouse:
2787dd7cddfSDavid du Colombier 			if(w->mouseopen) {
2797dd7cddfSDavid du Colombier 				w->mouse.counter++;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 				/* queue click events */
2827dd7cddfSDavid du Colombier 				if(!w->mouse.qfull && lastb != w->mc.buttons) {	/* add to ring */
2837dd7cddfSDavid du Colombier 					mp = &w->mouse.queue[w->mouse.wi];
2847dd7cddfSDavid du Colombier 					if(++w->mouse.wi == nelem(w->mouse.queue))
2857dd7cddfSDavid du Colombier 						w->mouse.wi = 0;
2867dd7cddfSDavid du Colombier 					if(w->mouse.wi == w->mouse.ri)
2877dd7cddfSDavid du Colombier 						w->mouse.qfull = TRUE;
2887dd7cddfSDavid du Colombier 					mp->Mouse = w->mc;
2897dd7cddfSDavid du Colombier 					mp->counter = w->mouse.counter;
2907dd7cddfSDavid du Colombier 					lastb = w->mc.buttons;
2917dd7cddfSDavid du Colombier 				}
2927dd7cddfSDavid du Colombier 			} else
2937dd7cddfSDavid du Colombier 				wmousectl(w);
2947dd7cddfSDavid du Colombier 			break;
2957dd7cddfSDavid du Colombier 		case WMouseread:
2967dd7cddfSDavid du Colombier 			/* send a queued event or, if the queue is empty, the current state */
2977dd7cddfSDavid du Colombier 			/* if the queue has filled, we discard all the events it contained. */
2987dd7cddfSDavid du Colombier 			/* the intent is to discard frantic clicking by the user during long latencies. */
2997dd7cddfSDavid du Colombier 			w->mouse.qfull = FALSE;
3007dd7cddfSDavid du Colombier 			if(w->mouse.wi != w->mouse.ri) {
3017dd7cddfSDavid du Colombier 				m = w->mouse.queue[w->mouse.ri];
3027dd7cddfSDavid du Colombier 				if(++w->mouse.ri == nelem(w->mouse.queue))
3037dd7cddfSDavid du Colombier 					w->mouse.ri = 0;
3047dd7cddfSDavid du Colombier 			} else
3057dd7cddfSDavid du Colombier 				m = (Mousestate){w->mc.Mouse, w->mouse.counter};
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier 			w->mouse.lastcounter = m.counter;
3087dd7cddfSDavid du Colombier 			send(mrm.cm, &m.Mouse);
3097dd7cddfSDavid du Colombier 			continue;
3107dd7cddfSDavid du Colombier 		case WCtl:
3117dd7cddfSDavid du Colombier 			if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
31259cc4ca5SDavid du Colombier 				chanfree(crm.c1);
31359cc4ca5SDavid du Colombier 				chanfree(crm.c2);
31459cc4ca5SDavid du Colombier 				chanfree(mrm.cm);
31559cc4ca5SDavid du Colombier 				chanfree(cwm.cw);
31659cc4ca5SDavid du Colombier 				chanfree(cwrm.c1);
31759cc4ca5SDavid du Colombier 				chanfree(cwrm.c2);
3187dd7cddfSDavid du Colombier 				threadexits(nil);
3197dd7cddfSDavid du Colombier 			}
3207dd7cddfSDavid du Colombier 			continue;
3217dd7cddfSDavid du Colombier 		case WCwrite:
3227dd7cddfSDavid du Colombier 			recv(cwm.cw, &pair);
3237dd7cddfSDavid du Colombier 			rp = pair.s;
3247dd7cddfSDavid du Colombier 			nr = pair.ns;
3257dd7cddfSDavid du Colombier 			bp = rp;
3267dd7cddfSDavid du Colombier 			for(i=0; i<nr; i++)
3277dd7cddfSDavid du Colombier 				if(*bp++ == '\b'){
3287dd7cddfSDavid du Colombier 					--bp;
3297dd7cddfSDavid du Colombier 					initial = 0;
3307dd7cddfSDavid du Colombier 					tp = runemalloc(nr);
3317dd7cddfSDavid du Colombier 					runemove(tp, rp, i);
3327dd7cddfSDavid du Colombier 					up = tp+i;
3337dd7cddfSDavid du Colombier 					for(; i<nr; i++){
3347dd7cddfSDavid du Colombier 						*up = *bp++;
3357dd7cddfSDavid du Colombier 						if(*up == '\b')
3367dd7cddfSDavid du Colombier 							if(up == tp)
3377dd7cddfSDavid du Colombier 								initial++;
3387dd7cddfSDavid du Colombier 							else
3397dd7cddfSDavid du Colombier 								--up;
3407dd7cddfSDavid du Colombier 						else
3417dd7cddfSDavid du Colombier 							up++;
3427dd7cddfSDavid du Colombier 					}
3437dd7cddfSDavid du Colombier 					if(initial){
3447dd7cddfSDavid du Colombier 						if(initial > w->qh)
3457dd7cddfSDavid du Colombier 							initial = w->qh;
3467dd7cddfSDavid du Colombier 						qh = w->qh-initial;
3477dd7cddfSDavid du Colombier 						wdelete(w, qh, qh+initial);
3487dd7cddfSDavid du Colombier 						w->qh = qh;
3497dd7cddfSDavid du Colombier 					}
3507dd7cddfSDavid du Colombier 					free(rp);
3517dd7cddfSDavid du Colombier 					rp = tp;
3527dd7cddfSDavid du Colombier 					nr = up-tp;
3537dd7cddfSDavid du Colombier 					rp[nr] = 0;
3547dd7cddfSDavid du Colombier 					break;
3557dd7cddfSDavid du Colombier 				}
3567dd7cddfSDavid du Colombier 			w->qh = winsert(w, rp, nr, w->qh)+nr;
3577dd7cddfSDavid du Colombier 			if(w->scrolling || w->mouseopen)
3587dd7cddfSDavid du Colombier 				wshow(w, w->qh);
3597dd7cddfSDavid du Colombier 			wsetselect(w, w->q0, w->q1);
3607dd7cddfSDavid du Colombier 			wscrdraw(w);
3617dd7cddfSDavid du Colombier 			free(rp);
3627dd7cddfSDavid du Colombier 			break;
3637dd7cddfSDavid du Colombier 		case WCread:
3647dd7cddfSDavid du Colombier 			recv(crm.c1, &pair);
3657dd7cddfSDavid du Colombier 			t = pair.s;
3667dd7cddfSDavid du Colombier 			nb = pair.ns;
3677dd7cddfSDavid du Colombier 			i = npart;
3687dd7cddfSDavid du Colombier 			npart = 0;
3697dd7cddfSDavid du Colombier 			if(i)
3707dd7cddfSDavid du Colombier 				memmove(t, part, i);
3717dd7cddfSDavid du Colombier 			while(i<nb && (w->qh<w->nr || w->nraw>0)){
3727dd7cddfSDavid du Colombier 				if(w->qh == w->nr){
3737dd7cddfSDavid du Colombier 					wid = runetochar(t+i, &w->raw[0]);
3747dd7cddfSDavid du Colombier 					w->nraw--;
3757dd7cddfSDavid du Colombier 					runemove(w->raw, w->raw+1, w->nraw);
3767dd7cddfSDavid du Colombier 				}else
3777dd7cddfSDavid du Colombier 					wid = runetochar(t+i, &w->r[w->qh++]);
3787dd7cddfSDavid du Colombier 				c = t[i];	/* knows break characters fit in a byte */
3797dd7cddfSDavid du Colombier 				i += wid;
3807dd7cddfSDavid du Colombier 				if(!w->rawing && (c == '\n' || c=='\004')){
3817dd7cddfSDavid du Colombier 					if(c == '\004')
3827dd7cddfSDavid du Colombier 						i--;
3837dd7cddfSDavid du Colombier 					break;
3847dd7cddfSDavid du Colombier 				}
3857dd7cddfSDavid du Colombier 			}
3867dd7cddfSDavid du Colombier 			if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')
3877dd7cddfSDavid du Colombier 				w->qh++;
3887dd7cddfSDavid du Colombier 			if(i > nb){
3897dd7cddfSDavid du Colombier 				npart = i-nb;
3907dd7cddfSDavid du Colombier 				memmove(part, t+nb, npart);
3917dd7cddfSDavid du Colombier 				i = nb;
3927dd7cddfSDavid du Colombier 			}
3937dd7cddfSDavid du Colombier 			pair.s = t;
3947dd7cddfSDavid du Colombier 			pair.ns = i;
3957dd7cddfSDavid du Colombier 			send(crm.c2, &pair);
3967dd7cddfSDavid du Colombier 			continue;
39759cc4ca5SDavid du Colombier 		case WWread:
39859cc4ca5SDavid du Colombier 			w->wctlready = 0;
39959cc4ca5SDavid du Colombier 			recv(cwrm.c1, &pair);
40059cc4ca5SDavid du Colombier 			if(w->deleted || w->i==nil)
40159cc4ca5SDavid du Colombier 				pair.ns = sprint(pair.s, "");
40259cc4ca5SDavid du Colombier 			else{
40380ee5cbfSDavid du Colombier 				s = "visible";
40480ee5cbfSDavid du Colombier 				for(i=0; i<nhidden; i++)
40580ee5cbfSDavid du Colombier 					if(hidden[i] == w){
40680ee5cbfSDavid du Colombier 						s = "hidden";
40780ee5cbfSDavid du Colombier 						break;
40880ee5cbfSDavid du Colombier 					}
40980ee5cbfSDavid du Colombier 				t = "notcurrent";
41080ee5cbfSDavid du Colombier 				if(w == input)
41180ee5cbfSDavid du Colombier 					t = "current";
41280ee5cbfSDavid du Colombier 				pair.ns = snprint(pair.s, pair.ns, "%11d %11d %11d %11d %s %s ",
41380ee5cbfSDavid du Colombier 					w->i->r.min.x, w->i->r.min.y, w->i->r.max.x, w->i->r.max.y, t, s);
41459cc4ca5SDavid du Colombier 			}
41559cc4ca5SDavid du Colombier 			send(cwrm.c2, &pair);
41659cc4ca5SDavid du Colombier 			continue;
4177dd7cddfSDavid du Colombier 		}
4187dd7cddfSDavid du Colombier 		if(!w->deleted)
4197dd7cddfSDavid du Colombier 			flushimage(display, 1);
4207dd7cddfSDavid du Colombier 	}
4217dd7cddfSDavid du Colombier }
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier void
waddraw(Window * w,Rune * r,int nr)4247dd7cddfSDavid du Colombier waddraw(Window *w, Rune *r, int nr)
4257dd7cddfSDavid du Colombier {
4267dd7cddfSDavid du Colombier 	w->raw = runerealloc(w->raw, w->nraw+nr);
4277dd7cddfSDavid du Colombier 	runemove(w->raw+w->nraw, r, nr);
4287dd7cddfSDavid du Colombier 	w->nraw += nr;
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier 
43159cc4ca5SDavid du Colombier /*
43259cc4ca5SDavid du Colombier  * Need to do this in a separate proc because if process we're interrupting
43359cc4ca5SDavid du Colombier  * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
43459cc4ca5SDavid du Colombier  */
43559cc4ca5SDavid du Colombier void
interruptproc(void * v)43659cc4ca5SDavid du Colombier interruptproc(void *v)
43759cc4ca5SDavid du Colombier {
43859cc4ca5SDavid du Colombier 	int *notefd;
43959cc4ca5SDavid du Colombier 
44059cc4ca5SDavid du Colombier 	notefd = v;
44159cc4ca5SDavid du Colombier 	write(*notefd, "interrupt", 9);
44259cc4ca5SDavid du Colombier 	free(notefd);
44359cc4ca5SDavid du Colombier }
44459cc4ca5SDavid du Colombier 
445fe853e23SDavid du Colombier int
windfilewidth(Window * w,uint q0,int oneelement)446fe853e23SDavid du Colombier windfilewidth(Window *w, uint q0, int oneelement)
447fe853e23SDavid du Colombier {
448fe853e23SDavid du Colombier 	uint q;
449fe853e23SDavid du Colombier 	Rune r;
450fe853e23SDavid du Colombier 
451fe853e23SDavid du Colombier 	q = q0;
452fe853e23SDavid du Colombier 	while(q > 0){
453fe853e23SDavid du Colombier 		r = w->r[q-1];
454fe853e23SDavid du Colombier 		if(r<=' ')
455fe853e23SDavid du Colombier 			break;
456fe853e23SDavid du Colombier 		if(oneelement && r=='/')
457fe853e23SDavid du Colombier 			break;
458fe853e23SDavid du Colombier 		--q;
459fe853e23SDavid du Colombier 	}
460fe853e23SDavid du Colombier 	return q0-q;
461fe853e23SDavid du Colombier }
462fe853e23SDavid du Colombier 
463fe853e23SDavid du Colombier void
showcandidates(Window * w,Completion * c)464fe853e23SDavid du Colombier showcandidates(Window *w, Completion *c)
465fe853e23SDavid du Colombier {
466bbd73495SDavid du Colombier 	int i;
467fe853e23SDavid du Colombier 	Fmt f;
468fe853e23SDavid du Colombier 	Rune *rp;
469fe853e23SDavid du Colombier 	uint nr, qline, q0;
470abe9e455SDavid du Colombier 	char *s;
471fe853e23SDavid du Colombier 
472fe853e23SDavid du Colombier 	runefmtstrinit(&f);
473abe9e455SDavid du Colombier 	if (c->nmatch == 0)
474abe9e455SDavid du Colombier 		s = "[no matches in ";
475abe9e455SDavid du Colombier 	else
476abe9e455SDavid du Colombier 		s = "[";
477fe853e23SDavid du Colombier 	if(c->nfile > 32)
478abe9e455SDavid du Colombier 		fmtprint(&f, "%s%d files]\n", s, c->nfile);
479fe853e23SDavid du Colombier 	else{
480abe9e455SDavid du Colombier 		fmtprint(&f, "%s", s);
481fe853e23SDavid du Colombier 		for(i=0; i<c->nfile; i++){
482fe853e23SDavid du Colombier 			if(i > 0)
483fe853e23SDavid du Colombier 				fmtprint(&f, " ");
484fe853e23SDavid du Colombier 			fmtprint(&f, "%s", c->filename[i]);
485fe853e23SDavid du Colombier 		}
486fe853e23SDavid du Colombier 		fmtprint(&f, "]\n");
487fe853e23SDavid du Colombier 	}
488fe853e23SDavid du Colombier 	/* place text at beginning of line before host point */
489fe853e23SDavid du Colombier 	qline = w->qh;
490fe853e23SDavid du Colombier 	while(qline>0 && w->r[qline-1] != '\n')
491fe853e23SDavid du Colombier 		qline--;
492fe853e23SDavid du Colombier 
493fe853e23SDavid du Colombier 	rp = runefmtstrflush(&f);
494fe853e23SDavid du Colombier 	nr = runestrlen(rp);
495fe853e23SDavid du Colombier 
496fe853e23SDavid du Colombier 	q0 = w->q0;
497da51d93aSDavid du Colombier 	q0 += winsert(w, rp, runestrlen(rp), qline) - qline;
498fe853e23SDavid du Colombier 	free(rp);
499fe853e23SDavid du Colombier 	wsetselect(w, q0+nr, q0+nr);
500fe853e23SDavid du Colombier }
501fe853e23SDavid du Colombier 
502fe853e23SDavid du Colombier Rune*
namecomplete(Window * w)503fe853e23SDavid du Colombier namecomplete(Window *w)
504fe853e23SDavid du Colombier {
505fe853e23SDavid du Colombier 	int nstr, npath;
506fe853e23SDavid du Colombier 	Rune *rp, *path, *str;
507fe853e23SDavid du Colombier 	Completion *c;
508fe853e23SDavid du Colombier 	char *s, *dir, *root;
509fe853e23SDavid du Colombier 
510fe853e23SDavid du Colombier 	/* control-f: filename completion; works back to white space or / */
511fe853e23SDavid du Colombier 	if(w->q0<w->nr && w->r[w->q0]>' ')	/* must be at end of word */
512fe853e23SDavid du Colombier 		return nil;
513fe853e23SDavid du Colombier 	nstr = windfilewidth(w, w->q0, TRUE);
514fe853e23SDavid du Colombier 	str = runemalloc(nstr);
515fe853e23SDavid du Colombier 	runemove(str, w->r+(w->q0-nstr), nstr);
516fe853e23SDavid du Colombier 	npath = windfilewidth(w, w->q0-nstr, FALSE);
517fe853e23SDavid du Colombier 	path = runemalloc(npath);
518fe853e23SDavid du Colombier 	runemove(path, w->r+(w->q0-nstr-npath), npath);
519fe853e23SDavid du Colombier 	rp = nil;
520fe853e23SDavid du Colombier 
521fe853e23SDavid du Colombier 	/* is path rooted? if not, we need to make it relative to window path */
522fe853e23SDavid du Colombier 	if(npath>0 && path[0]=='/'){
523fe853e23SDavid du Colombier 		dir = malloc(UTFmax*npath+1);
524fe853e23SDavid du Colombier 		sprint(dir, "%.*S", npath, path);
525fe853e23SDavid du Colombier 	}else{
526fe853e23SDavid du Colombier 		if(strcmp(w->dir, "") == 0)
527fe853e23SDavid du Colombier 			root = ".";
528fe853e23SDavid du Colombier 		else
529fe853e23SDavid du Colombier 			root = w->dir;
530fe853e23SDavid du Colombier 		dir = malloc(strlen(root)+1+UTFmax*npath+1);
531fe853e23SDavid du Colombier 		sprint(dir, "%s/%.*S", root, npath, path);
532fe853e23SDavid du Colombier 	}
533fe853e23SDavid du Colombier 	dir = cleanname(dir);
534fe853e23SDavid du Colombier 
535fe853e23SDavid du Colombier 	s = smprint("%.*S", nstr, str);
536fe853e23SDavid du Colombier 	c = complete(dir, s);
537fe853e23SDavid du Colombier 	free(s);
538fe853e23SDavid du Colombier 	if(c == nil)
539fe853e23SDavid du Colombier 		goto Return;
540fe853e23SDavid du Colombier 
541fe853e23SDavid du Colombier 	if(!c->advance)
542fe853e23SDavid du Colombier 		showcandidates(w, c);
543fe853e23SDavid du Colombier 
544fe853e23SDavid du Colombier 	if(c->advance)
545fe853e23SDavid du Colombier 		rp = runesmprint("%s", c->string);
546fe853e23SDavid du Colombier 
547fe853e23SDavid du Colombier   Return:
548fe853e23SDavid du Colombier 	freecompletion(c);
549fe853e23SDavid du Colombier 	free(dir);
550fe853e23SDavid du Colombier 	free(path);
551fe853e23SDavid du Colombier 	free(str);
552fe853e23SDavid du Colombier 	return rp;
553fe853e23SDavid du Colombier }
554fe853e23SDavid du Colombier 
5557dd7cddfSDavid du Colombier void
wkeyctl(Window * w,Rune r)5567dd7cddfSDavid du Colombier wkeyctl(Window *w, Rune r)
5577dd7cddfSDavid du Colombier {
5587dd7cddfSDavid du Colombier 	uint q0 ,q1;
559a8453668SDavid du Colombier 	int n, nb, nr;
560fe853e23SDavid du Colombier 	Rune *rp;
56159cc4ca5SDavid du Colombier 	int *notefd;
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier 	if(r == 0)
5647dd7cddfSDavid du Colombier 		return;
5657dd7cddfSDavid du Colombier 	if(w->deleted)
5667dd7cddfSDavid du Colombier 		return;
567fe853e23SDavid du Colombier 	/* navigation keys work only when mouse is not open */
568fe853e23SDavid du Colombier 	if(!w->mouseopen)
569fe853e23SDavid du Colombier 		switch(r){
570a8453668SDavid du Colombier 		case Kdown:
571a8453668SDavid du Colombier 			n = w->maxlines/3;
572a8453668SDavid du Colombier 			goto case_Down;
573a8453668SDavid du Colombier 		case Kscrollonedown:
574a8453668SDavid du Colombier 			n = mousescrollsize(w->maxlines);
575a8453668SDavid du Colombier 			if(n <= 0)
576a8453668SDavid du Colombier 				n = 1;
577a8453668SDavid du Colombier 			goto case_Down;
578a8453668SDavid du Colombier 		case Kpgdown:
579a8453668SDavid du Colombier 			n = 2*w->maxlines/3;
580a8453668SDavid du Colombier 		case_Down:
581a8453668SDavid du Colombier 			q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+n*w->font->height));
5827dd7cddfSDavid du Colombier 			wsetorigin(w, q0, TRUE);
5837dd7cddfSDavid du Colombier 			return;
584a8453668SDavid du Colombier 		case Kup:
585a8453668SDavid du Colombier 			n = w->maxlines/3;
586a8453668SDavid du Colombier 			goto case_Up;
587a8453668SDavid du Colombier 		case Kscrolloneup:
588a8453668SDavid du Colombier 			n = mousescrollsize(w->maxlines);
589a8453668SDavid du Colombier 			if(n <= 0)
590a8453668SDavid du Colombier 				n = 1;
591a8453668SDavid du Colombier 			goto case_Up;
592a8453668SDavid du Colombier 		case Kpgup:
593a8453668SDavid du Colombier 			n = 2*w->maxlines/3;
594a8453668SDavid du Colombier 		case_Up:
595a8453668SDavid du Colombier 			q0 = wbacknl(w, w->org, n);
5967dd7cddfSDavid du Colombier 			wsetorigin(w, q0, TRUE);
5977dd7cddfSDavid du Colombier 			return;
598a8453668SDavid du Colombier 		case Kleft:
599fe853e23SDavid du Colombier 			if(w->q0 > 0){
600fe853e23SDavid du Colombier 				q0 = w->q0-1;
601fe853e23SDavid du Colombier 				wsetselect(w, q0, q0);
602fe853e23SDavid du Colombier 				wshow(w, q0);
603fe853e23SDavid du Colombier 			}
604fe853e23SDavid du Colombier 			return;
605a8453668SDavid du Colombier 		case Kright:
606fe853e23SDavid du Colombier 			if(w->q1 < w->nr){
607fe853e23SDavid du Colombier 				q1 = w->q1+1;
608fe853e23SDavid du Colombier 				wsetselect(w, q1, q1);
609fe853e23SDavid du Colombier 				wshow(w, q1);
610fe853e23SDavid du Colombier 			}
611fe853e23SDavid du Colombier 			return;
612a8453668SDavid du Colombier 		case Khome:
613fe853e23SDavid du Colombier 			wshow(w, 0);
614fe853e23SDavid du Colombier 			return;
615a8453668SDavid du Colombier 		case Kend:
616fe853e23SDavid du Colombier 			wshow(w, w->nr);
617fe853e23SDavid du Colombier 			return;
618e7d29567SDavid du Colombier 		case 0x01:	/* ^A: beginning of line */
619e7d29567SDavid du Colombier 			if(w->q0==0 || w->q0==w->qh || w->r[w->q0-1]=='\n')
620e7d29567SDavid du Colombier 				return;
621e7d29567SDavid du Colombier 			nb = wbswidth(w, 0x15 /* ^U */);
622e7d29567SDavid du Colombier 			wsetselect(w, w->q0-nb, w->q0-nb);
623e7d29567SDavid du Colombier 			wshow(w, w->q0);
624e7d29567SDavid du Colombier 			return;
625e7d29567SDavid du Colombier 		case 0x05:	/* ^E: end of line */
626e7d29567SDavid du Colombier 			q0 = w->q0;
627e7d29567SDavid du Colombier 			while(q0 < w->nr && w->r[q0]!='\n')
628e7d29567SDavid du Colombier 				q0++;
629e7d29567SDavid du Colombier 			wsetselect(w, q0, q0);
630e7d29567SDavid du Colombier 			wshow(w, w->q0);
631e7d29567SDavid du Colombier 			return;
6327dd7cddfSDavid du Colombier 		}
6337dd7cddfSDavid du Colombier 	if(w->rawing && (w->q0==w->nr || w->mouseopen)){
6347dd7cddfSDavid du Colombier 		waddraw(w, &r, 1);
6357dd7cddfSDavid du Colombier 		return;
6367dd7cddfSDavid du Colombier 	}
6377dd7cddfSDavid du Colombier 	if(r==0x1B || (w->holding && r==0x7F)){	/* toggle hold */
6387dd7cddfSDavid du Colombier 		if(w->holding)
6397dd7cddfSDavid du Colombier 			--w->holding;
6407dd7cddfSDavid du Colombier 		else
6417dd7cddfSDavid du Colombier 			w->holding++;
6427dd7cddfSDavid du Colombier 		wrepaint(w);
6437dd7cddfSDavid du Colombier 		if(r == 0x1B)
6447dd7cddfSDavid du Colombier 			return;
6457dd7cddfSDavid du Colombier 	}
6467dd7cddfSDavid du Colombier 	if(r != 0x7F){
6477dd7cddfSDavid du Colombier 		wsnarf(w);
6487dd7cddfSDavid du Colombier 		wcut(w);
6497dd7cddfSDavid du Colombier 	}
6507dd7cddfSDavid du Colombier 	switch(r){
6517dd7cddfSDavid du Colombier 	case 0x7F:		/* send interrupt */
6527dd7cddfSDavid du Colombier 		w->qh = w->nr;
6537dd7cddfSDavid du Colombier 		wshow(w, w->qh);
65459cc4ca5SDavid du Colombier 		notefd = emalloc(sizeof(int));
65559cc4ca5SDavid du Colombier 		*notefd = w->notefd;
65659cc4ca5SDavid du Colombier 		proccreate(interruptproc, notefd, 4096);
6577dd7cddfSDavid du Colombier 		return;
658fe853e23SDavid du Colombier 	case 0x06:	/* ^F: file name completion */
659fe853e23SDavid du Colombier 	case Kins:		/* Insert: file name completion */
660fe853e23SDavid du Colombier 		rp = namecomplete(w);
661fe853e23SDavid du Colombier 		if(rp == nil)
662fe853e23SDavid du Colombier 			return;
663fe853e23SDavid du Colombier 		nr = runestrlen(rp);
664fe853e23SDavid du Colombier 		q0 = w->q0;
665fe853e23SDavid du Colombier 		q0 = winsert(w, rp, nr, q0);
666fe853e23SDavid du Colombier 		wshow(w, q0+nr);
667fe853e23SDavid du Colombier 		free(rp);
668fe853e23SDavid du Colombier 		return;
6697dd7cddfSDavid du Colombier 	case 0x08:	/* ^H: erase character */
6707dd7cddfSDavid du Colombier 	case 0x15:	/* ^U: erase line */
6717dd7cddfSDavid du Colombier 	case 0x17:	/* ^W: erase word */
6727dd7cddfSDavid du Colombier 		if(w->q0==0 || w->q0==w->qh)
6737dd7cddfSDavid du Colombier 			return;
6747dd7cddfSDavid du Colombier 		nb = wbswidth(w, r);
6757dd7cddfSDavid du Colombier 		q1 = w->q0;
6767dd7cddfSDavid du Colombier 		q0 = q1-nb;
67780ee5cbfSDavid du Colombier 		if(q0 < w->org){
67880ee5cbfSDavid du Colombier 			q0 = w->org;
67980ee5cbfSDavid du Colombier 			nb = q1-q0;
68080ee5cbfSDavid du Colombier 		}
68180ee5cbfSDavid du Colombier 		if(nb > 0){
6827dd7cddfSDavid du Colombier 			wdelete(w, q0, q0+nb);
6837dd7cddfSDavid du Colombier 			wsetselect(w, q0, q0);
68480ee5cbfSDavid du Colombier 		}
6857dd7cddfSDavid du Colombier 		return;
6867dd7cddfSDavid du Colombier 	}
6877dd7cddfSDavid du Colombier 	/* otherwise ordinary character; just insert */
6887dd7cddfSDavid du Colombier 	q0 = w->q0;
6897dd7cddfSDavid du Colombier 	q0 = winsert(w, &r, 1, q0);
6907dd7cddfSDavid du Colombier 	wshow(w, q0+1);
6917dd7cddfSDavid du Colombier }
6927dd7cddfSDavid du Colombier 
6937dd7cddfSDavid du Colombier void
wsetcols(Window * w)6947dd7cddfSDavid du Colombier wsetcols(Window *w)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier 	if(w->holding)
6977dd7cddfSDavid du Colombier 		if(w == input)
6987dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = holdcol;
6997dd7cddfSDavid du Colombier 		else
7007dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = lightholdcol;
7017dd7cddfSDavid du Colombier 	else
7027dd7cddfSDavid du Colombier 		if(w == input)
7037dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = display->black;
7047dd7cddfSDavid du Colombier 		else
7057dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = darkgrey;
7067dd7cddfSDavid du Colombier }
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier void
wrepaint(Window * w)7097dd7cddfSDavid du Colombier wrepaint(Window *w)
7107dd7cddfSDavid du Colombier {
7117dd7cddfSDavid du Colombier 	wsetcols(w);
7120c547597SDavid du Colombier 	if(!w->mouseopen)
7138f5875f3SDavid du Colombier 		frredraw(w);
7147dd7cddfSDavid du Colombier 	if(w == input){
7157dd7cddfSDavid du Colombier 		wborder(w, Selborder);
7167dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
7177dd7cddfSDavid du Colombier 	}else
7187dd7cddfSDavid du Colombier 		wborder(w, Unselborder);
7197dd7cddfSDavid du Colombier }
7207dd7cddfSDavid du Colombier 
7217dd7cddfSDavid du Colombier int
wbswidth(Window * w,Rune c)7227dd7cddfSDavid du Colombier wbswidth(Window *w, Rune c)
7237dd7cddfSDavid du Colombier {
7247dd7cddfSDavid du Colombier 	uint q, eq, stop;
7257dd7cddfSDavid du Colombier 	Rune r;
7267dd7cddfSDavid du Colombier 	int skipping;
7277dd7cddfSDavid du Colombier 
7287dd7cddfSDavid du Colombier 	/* there is known to be at least one character to erase */
7297dd7cddfSDavid du Colombier 	if(c == 0x08)	/* ^H: erase character */
7307dd7cddfSDavid du Colombier 		return 1;
7317dd7cddfSDavid du Colombier 	q = w->q0;
7327dd7cddfSDavid du Colombier 	stop = 0;
7337dd7cddfSDavid du Colombier 	if(q > w->qh)
7347dd7cddfSDavid du Colombier 		stop = w->qh;
7357dd7cddfSDavid du Colombier 	skipping = TRUE;
7367dd7cddfSDavid du Colombier 	while(q > stop){
7377dd7cddfSDavid du Colombier 		r = w->r[q-1];
7387dd7cddfSDavid du Colombier 		if(r == '\n'){		/* eat at most one more character */
7397dd7cddfSDavid du Colombier 			if(q == w->q0)	/* eat the newline */
7407dd7cddfSDavid du Colombier 				--q;
7417dd7cddfSDavid du Colombier 			break;
7427dd7cddfSDavid du Colombier 		}
7437dd7cddfSDavid du Colombier 		if(c == 0x17){
7447dd7cddfSDavid du Colombier 			eq = isalnum(r);
7457dd7cddfSDavid du Colombier 			if(eq && skipping)	/* found one; stop skipping */
7467dd7cddfSDavid du Colombier 				skipping = FALSE;
7477dd7cddfSDavid du Colombier 			else if(!eq && !skipping)
7487dd7cddfSDavid du Colombier 				break;
7497dd7cddfSDavid du Colombier 		}
7507dd7cddfSDavid du Colombier 		--q;
7517dd7cddfSDavid du Colombier 	}
7527dd7cddfSDavid du Colombier 	return w->q0-q;
7537dd7cddfSDavid du Colombier }
7547dd7cddfSDavid du Colombier 
7557dd7cddfSDavid du Colombier void
wsnarf(Window * w)7567dd7cddfSDavid du Colombier wsnarf(Window *w)
7577dd7cddfSDavid du Colombier {
7587dd7cddfSDavid du Colombier 	if(w->q1 == w->q0)
7597dd7cddfSDavid du Colombier 		return;
7607dd7cddfSDavid du Colombier 	nsnarf = w->q1-w->q0;
7617dd7cddfSDavid du Colombier 	snarf = runerealloc(snarf, nsnarf);
76280ee5cbfSDavid du Colombier 	snarfversion++;	/* maybe modified by parent */
7637dd7cddfSDavid du Colombier 	runemove(snarf, w->r+w->q0, nsnarf);
7647dd7cddfSDavid du Colombier 	putsnarf();
7657dd7cddfSDavid du Colombier }
7667dd7cddfSDavid du Colombier 
7677dd7cddfSDavid du Colombier void
wcut(Window * w)7687dd7cddfSDavid du Colombier wcut(Window *w)
7697dd7cddfSDavid du Colombier {
7707dd7cddfSDavid du Colombier 	if(w->q1 == w->q0)
7717dd7cddfSDavid du Colombier 		return;
7727dd7cddfSDavid du Colombier 	wdelete(w, w->q0, w->q1);
77380ee5cbfSDavid du Colombier 	wsetselect(w, w->q0, w->q0);
7747dd7cddfSDavid du Colombier }
7757dd7cddfSDavid du Colombier 
7767dd7cddfSDavid du Colombier void
wpaste(Window * w)7777dd7cddfSDavid du Colombier wpaste(Window *w)
7787dd7cddfSDavid du Colombier {
7797dd7cddfSDavid du Colombier 	uint q0;
7807dd7cddfSDavid du Colombier 
7817dd7cddfSDavid du Colombier 	if(nsnarf == 0)
7827dd7cddfSDavid du Colombier 		return;
7837dd7cddfSDavid du Colombier 	wcut(w);
7847dd7cddfSDavid du Colombier 	q0 = w->q0;
7857dd7cddfSDavid du Colombier 	if(w->rawing && q0==w->nr){
7867dd7cddfSDavid du Colombier 		waddraw(w, snarf, nsnarf);
7877dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0);
7887dd7cddfSDavid du Colombier 	}else{
7896ff5e913SDavid du Colombier 		q0 = winsert(w, snarf, nsnarf, w->q0);
7907dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0+nsnarf);
7917dd7cddfSDavid du Colombier 	}
7927dd7cddfSDavid du Colombier }
7937dd7cddfSDavid du Colombier 
7947dd7cddfSDavid du Colombier void
wplumb(Window * w)7957dd7cddfSDavid du Colombier wplumb(Window *w)
7967dd7cddfSDavid du Colombier {
7977dd7cddfSDavid du Colombier 	Plumbmsg *m;
7987dd7cddfSDavid du Colombier 	static int fd = -2;
7997dd7cddfSDavid du Colombier 	char buf[32];
8007dd7cddfSDavid du Colombier 	uint p0, p1;
8017dd7cddfSDavid du Colombier 	Cursor *c;
8027dd7cddfSDavid du Colombier 
8037dd7cddfSDavid du Colombier 	if(fd == -2)
8047dd7cddfSDavid du Colombier 		fd = plumbopen("send", OWRITE|OCEXEC);
8057dd7cddfSDavid du Colombier 	if(fd < 0)
8067dd7cddfSDavid du Colombier 		return;
8077dd7cddfSDavid du Colombier 	m = emalloc(sizeof(Plumbmsg));
8087dd7cddfSDavid du Colombier 	m->src = estrdup("rio");
8097dd7cddfSDavid du Colombier 	m->dst = nil;
8107dd7cddfSDavid du Colombier 	m->wdir = estrdup(w->dir);
81159cc4ca5SDavid du Colombier 	m->type = estrdup("text");
8127dd7cddfSDavid du Colombier 	p0 = w->q0;
8137dd7cddfSDavid du Colombier 	p1 = w->q1;
8147dd7cddfSDavid du Colombier 	if(w->q1 > w->q0)
8157dd7cddfSDavid du Colombier 		m->attr = nil;
8167dd7cddfSDavid du Colombier 	else{
8177dd7cddfSDavid du Colombier 		while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
8187dd7cddfSDavid du Colombier 			p0--;
8197dd7cddfSDavid du Colombier 		while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
8207dd7cddfSDavid du Colombier 			p1++;
8217dd7cddfSDavid du Colombier 		sprint(buf, "click=%d", w->q0-p0);
8227dd7cddfSDavid du Colombier 		m->attr = plumbunpackattr(buf);
8237dd7cddfSDavid du Colombier 	}
8249a747e4fSDavid du Colombier 	if(p1-p0 > messagesize-1024){
8257dd7cddfSDavid du Colombier 		plumbfree(m);
8269a747e4fSDavid du Colombier 		return;	/* too large for 9P */
8277dd7cddfSDavid du Colombier 	}
8287dd7cddfSDavid du Colombier 	m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
8297dd7cddfSDavid du Colombier 	if(plumbsend(fd, m) < 0){
8307dd7cddfSDavid du Colombier 		c = lastcursor;
8317dd7cddfSDavid du Colombier 		riosetcursor(&query, 1);
8327dd7cddfSDavid du Colombier 		sleep(300);
8337dd7cddfSDavid du Colombier 		riosetcursor(c, 1);
8347dd7cddfSDavid du Colombier 	}
8357dd7cddfSDavid du Colombier 	plumbfree(m);
8367dd7cddfSDavid du Colombier }
8377dd7cddfSDavid du Colombier 
8387dd7cddfSDavid du Colombier int
winborder(Window * w,Point xy)8397dd7cddfSDavid du Colombier winborder(Window *w, Point xy)
8407dd7cddfSDavid du Colombier {
8417dd7cddfSDavid du Colombier 	return ptinrect(xy, w->screenr) && !ptinrect(xy, insetrect(w->screenr, Selborder));
8427dd7cddfSDavid du Colombier }
8437dd7cddfSDavid du Colombier 
8447dd7cddfSDavid du Colombier void
wmousectl(Window * w)8457dd7cddfSDavid du Colombier wmousectl(Window *w)
8467dd7cddfSDavid du Colombier {
8477dd7cddfSDavid du Colombier 	int but;
8487dd7cddfSDavid du Colombier 
8497dd7cddfSDavid du Colombier 	if(w->mc.buttons == 1)
8507dd7cddfSDavid du Colombier 		but = 1;
8517dd7cddfSDavid du Colombier 	else if(w->mc.buttons == 2)
8527dd7cddfSDavid du Colombier 		but = 2;
8537dd7cddfSDavid du Colombier 	else if(w->mc.buttons == 4)
8547dd7cddfSDavid du Colombier 		but = 3;
855a8453668SDavid du Colombier 	else{
856a8453668SDavid du Colombier 		if(w->mc.buttons == 8)
857a8453668SDavid du Colombier 			wkeyctl(w, Kscrolloneup);
858a8453668SDavid du Colombier 		if(w->mc.buttons == 16)
859a8453668SDavid du Colombier 			wkeyctl(w, Kscrollonedown);
8607dd7cddfSDavid du Colombier 		return;
861a8453668SDavid du Colombier 	}
862a8453668SDavid du Colombier 
8637dd7cddfSDavid du Colombier 	incref(w);		/* hold up window while we track */
8647dd7cddfSDavid du Colombier 	if(w->deleted)
8657dd7cddfSDavid du Colombier 		goto Return;
8667dd7cddfSDavid du Colombier 	if(ptinrect(w->mc.xy, w->scrollr)){
8677dd7cddfSDavid du Colombier 		if(but)
8687dd7cddfSDavid du Colombier 			wscroll(w, but);
8697dd7cddfSDavid du Colombier 		goto Return;
8707dd7cddfSDavid du Colombier 	}
8717dd7cddfSDavid du Colombier 	if(but == 1)
8727dd7cddfSDavid du Colombier 		wselect(w);
8737dd7cddfSDavid du Colombier 	/* else all is handled by main process */
8747dd7cddfSDavid du Colombier    Return:
8757dd7cddfSDavid du Colombier 	wclose(w);
8767dd7cddfSDavid du Colombier }
8777dd7cddfSDavid du Colombier 
8787dd7cddfSDavid du Colombier void
wdelete(Window * w,uint q0,uint q1)8797dd7cddfSDavid du Colombier wdelete(Window *w, uint q0, uint q1)
8807dd7cddfSDavid du Colombier {
8817dd7cddfSDavid du Colombier 	uint n, p0, p1;
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 	n = q1-q0;
8847dd7cddfSDavid du Colombier 	if(n == 0)
8857dd7cddfSDavid du Colombier 		return;
8867dd7cddfSDavid du Colombier 	runemove(w->r+q0, w->r+q1, w->nr-q1);
8877dd7cddfSDavid du Colombier 	w->nr -= n;
8887dd7cddfSDavid du Colombier 	if(q0 < w->q0)
8897dd7cddfSDavid du Colombier 		w->q0 -= min(n, w->q0-q0);
8907dd7cddfSDavid du Colombier 	if(q0 < w->q1)
8917dd7cddfSDavid du Colombier 		w->q1 -= min(n, w->q1-q0);
8927dd7cddfSDavid du Colombier 	if(q1 < w->qh)
8937dd7cddfSDavid du Colombier 		w->qh -= n;
8947dd7cddfSDavid du Colombier 	else if(q0 < w->qh)
8957dd7cddfSDavid du Colombier 		w->qh = q0;
8967dd7cddfSDavid du Colombier 	if(q1 <= w->org)
8977dd7cddfSDavid du Colombier 		w->org -= n;
8987dd7cddfSDavid du Colombier 	else if(q0 < w->org+w->nchars){
8997dd7cddfSDavid du Colombier 		p1 = q1 - w->org;
9007dd7cddfSDavid du Colombier 		if(p1 > w->nchars)
9017dd7cddfSDavid du Colombier 			p1 = w->nchars;
9027dd7cddfSDavid du Colombier 		if(q0 < w->org){
9037dd7cddfSDavid du Colombier 			w->org = q0;
9047dd7cddfSDavid du Colombier 			p0 = 0;
9057dd7cddfSDavid du Colombier 		}else
9067dd7cddfSDavid du Colombier 			p0 = q0 - w->org;
9077dd7cddfSDavid du Colombier 		frdelete(w, p0, p1);
9087dd7cddfSDavid du Colombier 		wfill(w);
9097dd7cddfSDavid du Colombier 	}
9107dd7cddfSDavid du Colombier }
9117dd7cddfSDavid du Colombier 
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier static Window	*clickwin;
9147dd7cddfSDavid du Colombier static uint	clickmsec;
9157dd7cddfSDavid du Colombier static Window	*selectwin;
9167dd7cddfSDavid du Colombier static uint	selectq;
9177dd7cddfSDavid du Colombier 
9187dd7cddfSDavid du Colombier /*
9197dd7cddfSDavid du Colombier  * called from frame library
9207dd7cddfSDavid du Colombier  */
9217dd7cddfSDavid du Colombier void
framescroll(Frame * f,int dl)9227dd7cddfSDavid du Colombier framescroll(Frame *f, int dl)
9237dd7cddfSDavid du Colombier {
9247dd7cddfSDavid du Colombier 	if(f != &selectwin->Frame)
9257dd7cddfSDavid du Colombier 		error("frameselect not right frame");
9267dd7cddfSDavid du Colombier 	wframescroll(selectwin, dl);
9277dd7cddfSDavid du Colombier }
9287dd7cddfSDavid du Colombier 
9297dd7cddfSDavid du Colombier void
wframescroll(Window * w,int dl)9307dd7cddfSDavid du Colombier wframescroll(Window *w, int dl)
9317dd7cddfSDavid du Colombier {
9327dd7cddfSDavid du Colombier 	uint q0;
9337dd7cddfSDavid du Colombier 
9347dd7cddfSDavid du Colombier 	if(dl == 0){
9357dd7cddfSDavid du Colombier 		wscrsleep(w, 100);
9367dd7cddfSDavid du Colombier 		return;
9377dd7cddfSDavid du Colombier 	}
9387dd7cddfSDavid du Colombier 	if(dl < 0){
9397dd7cddfSDavid du Colombier 		q0 = wbacknl(w, w->org, -dl);
9407dd7cddfSDavid du Colombier 		if(selectq > w->org+w->p0)
9417dd7cddfSDavid du Colombier 			wsetselect(w, w->org+w->p0, selectq);
9427dd7cddfSDavid du Colombier 		else
9437dd7cddfSDavid du Colombier 			wsetselect(w, selectq, w->org+w->p0);
9447dd7cddfSDavid du Colombier 	}else{
9457dd7cddfSDavid du Colombier 		if(w->org+w->nchars == w->nr)
9467dd7cddfSDavid du Colombier 			return;
9477dd7cddfSDavid du Colombier 		q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
9487dd7cddfSDavid du Colombier 		if(selectq >= w->org+w->p1)
9497dd7cddfSDavid du Colombier 			wsetselect(w, w->org+w->p1, selectq);
9507dd7cddfSDavid du Colombier 		else
9517dd7cddfSDavid du Colombier 			wsetselect(w, selectq, w->org+w->p1);
9527dd7cddfSDavid du Colombier 	}
9537dd7cddfSDavid du Colombier 	wsetorigin(w, q0, TRUE);
9547dd7cddfSDavid du Colombier }
9557dd7cddfSDavid du Colombier 
9567dd7cddfSDavid du Colombier void
wselect(Window * w)9577dd7cddfSDavid du Colombier wselect(Window *w)
9587dd7cddfSDavid du Colombier {
9597dd7cddfSDavid du Colombier 	uint q0, q1;
9607dd7cddfSDavid du Colombier 	int b, x, y, first;
9617dd7cddfSDavid du Colombier 
9627dd7cddfSDavid du Colombier 	first = 1;
9637dd7cddfSDavid du Colombier 	selectwin = w;
9647dd7cddfSDavid du Colombier 	/*
9657dd7cddfSDavid du Colombier 	 * Double-click immediately if it might make sense.
9667dd7cddfSDavid du Colombier 	 */
9677dd7cddfSDavid du Colombier 	b = w->mc.buttons;
9687dd7cddfSDavid du Colombier 	q0 = w->q0;
9697dd7cddfSDavid du Colombier 	q1 = w->q1;
9707dd7cddfSDavid du Colombier 	selectq = w->org+frcharofpt(w, w->mc.xy);
9717dd7cddfSDavid du Colombier 	if(clickwin==w && w->mc.msec-clickmsec<500)
9727dd7cddfSDavid du Colombier 	if(q0==q1 && selectq==w->q0){
9737dd7cddfSDavid du Colombier 		wdoubleclick(w, &q0, &q1);
9747dd7cddfSDavid du Colombier 		wsetselect(w, q0, q1);
9757dd7cddfSDavid du Colombier 		flushimage(display, 1);
9767dd7cddfSDavid du Colombier 		x = w->mc.xy.x;
9777dd7cddfSDavid du Colombier 		y = w->mc.xy.y;
9787dd7cddfSDavid du Colombier 		/* stay here until something interesting happens */
9797dd7cddfSDavid du Colombier 		do
9807dd7cddfSDavid du Colombier 			readmouse(&w->mc);
9817dd7cddfSDavid du Colombier 		while(w->mc.buttons==b && abs(w->mc.xy.x-x)<3 && abs(w->mc.xy.y-y)<3);
9827dd7cddfSDavid du Colombier 		w->mc.xy.x = x;	/* in case we're calling frselect */
9837dd7cddfSDavid du Colombier 		w->mc.xy.y = y;
9847dd7cddfSDavid du Colombier 		q0 = w->q0;	/* may have changed */
9857dd7cddfSDavid du Colombier 		q1 = w->q1;
9867dd7cddfSDavid du Colombier 		selectq = q0;
9877dd7cddfSDavid du Colombier 	}
9887dd7cddfSDavid du Colombier 	if(w->mc.buttons == b){
9897dd7cddfSDavid du Colombier 		w->scroll = framescroll;
9907dd7cddfSDavid du Colombier 		frselect(w, &w->mc);
9917dd7cddfSDavid du Colombier 		/* horrible botch: while asleep, may have lost selection altogether */
9927dd7cddfSDavid du Colombier 		if(selectq > w->nr)
9937dd7cddfSDavid du Colombier 			selectq = w->org + w->p0;
9947dd7cddfSDavid du Colombier 		w->Frame.scroll = nil;
9957dd7cddfSDavid du Colombier 		if(selectq < w->org)
9967dd7cddfSDavid du Colombier 			q0 = selectq;
9977dd7cddfSDavid du Colombier 		else
9987dd7cddfSDavid du Colombier 			q0 = w->org + w->p0;
9997dd7cddfSDavid du Colombier 		if(selectq > w->org+w->nchars)
10007dd7cddfSDavid du Colombier 			q1 = selectq;
10017dd7cddfSDavid du Colombier 		else
10027dd7cddfSDavid du Colombier 			q1 = w->org+w->p1;
10037dd7cddfSDavid du Colombier 	}
10047dd7cddfSDavid du Colombier 	if(q0 == q1){
10057dd7cddfSDavid du Colombier 		if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500){
10067dd7cddfSDavid du Colombier 			wdoubleclick(w, &q0, &q1);
10077dd7cddfSDavid du Colombier 			clickwin = nil;
10087dd7cddfSDavid du Colombier 		}else{
10097dd7cddfSDavid du Colombier 			clickwin = w;
10107dd7cddfSDavid du Colombier 			clickmsec = w->mc.msec;
10117dd7cddfSDavid du Colombier 		}
10127dd7cddfSDavid du Colombier 	}else
10137dd7cddfSDavid du Colombier 		clickwin = nil;
10147dd7cddfSDavid du Colombier 	wsetselect(w, q0, q1);
10157dd7cddfSDavid du Colombier 	flushimage(display, 1);
10167dd7cddfSDavid du Colombier 	while(w->mc.buttons){
10177dd7cddfSDavid du Colombier 		w->mc.msec = 0;
10187dd7cddfSDavid du Colombier 		b = w->mc.buttons;
10197dd7cddfSDavid du Colombier 		if(b & 6){
10207dd7cddfSDavid du Colombier 			if(b & 2){
10217dd7cddfSDavid du Colombier 				wsnarf(w);
10227dd7cddfSDavid du Colombier 				wcut(w);
10237dd7cddfSDavid du Colombier 			}else{
10247dd7cddfSDavid du Colombier 				if(first){
10257dd7cddfSDavid du Colombier 					first = 0;
10267dd7cddfSDavid du Colombier 					getsnarf();
10277dd7cddfSDavid du Colombier 				}
10287dd7cddfSDavid du Colombier 				wpaste(w);
10297dd7cddfSDavid du Colombier 			}
10307dd7cddfSDavid du Colombier 		}
10317dd7cddfSDavid du Colombier 		wscrdraw(w);
10327dd7cddfSDavid du Colombier 		flushimage(display, 1);
10337dd7cddfSDavid du Colombier 		while(w->mc.buttons == b)
10347dd7cddfSDavid du Colombier 			readmouse(&w->mc);
10357dd7cddfSDavid du Colombier 		clickwin = nil;
10367dd7cddfSDavid du Colombier 	}
10377dd7cddfSDavid du Colombier }
10387dd7cddfSDavid du Colombier 
10397dd7cddfSDavid du Colombier void
wsendctlmesg(Window * w,int type,Rectangle r,Image * image)10407dd7cddfSDavid du Colombier wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
10417dd7cddfSDavid du Colombier {
10427dd7cddfSDavid du Colombier 	Wctlmesg wcm;
10437dd7cddfSDavid du Colombier 
10447dd7cddfSDavid du Colombier 	wcm.type = type;
10457dd7cddfSDavid du Colombier 	wcm.r = r;
10467dd7cddfSDavid du Colombier 	wcm.image = image;
10477dd7cddfSDavid du Colombier 	send(w->cctl, &wcm);
10487dd7cddfSDavid du Colombier }
10497dd7cddfSDavid du Colombier 
10507dd7cddfSDavid du Colombier int
wctlmesg(Window * w,int m,Rectangle r,Image * i)10517dd7cddfSDavid du Colombier wctlmesg(Window *w, int m, Rectangle r, Image *i)
10527dd7cddfSDavid du Colombier {
10537dd7cddfSDavid du Colombier 	char buf[64];
10547dd7cddfSDavid du Colombier 
10557dd7cddfSDavid du Colombier 	switch(m){
10567dd7cddfSDavid du Colombier 	default:
10577dd7cddfSDavid du Colombier 		error("unknown control message");
10587dd7cddfSDavid du Colombier 		break;
10597dd7cddfSDavid du Colombier 	case Wakeup:
10607dd7cddfSDavid du Colombier 		break;
10617dd7cddfSDavid du Colombier 	case Moved:
10627dd7cddfSDavid du Colombier 	case Reshaped:
10637dd7cddfSDavid du Colombier 		if(w->deleted){
10647dd7cddfSDavid du Colombier 			freeimage(i);
10657dd7cddfSDavid du Colombier 			break;
10667dd7cddfSDavid du Colombier 		}
10677dd7cddfSDavid du Colombier 		w->screenr = r;
10687dd7cddfSDavid du Colombier 		strcpy(buf, w->name);
10697dd7cddfSDavid du Colombier 		wresize(w, i, m==Moved);
10709a747e4fSDavid du Colombier 		w->wctlready = 1;
10719a747e4fSDavid du Colombier 		proccreate(deletetimeoutproc, estrdup(buf), 4096);
10727dd7cddfSDavid du Colombier 		if(Dx(r) > 0){
10737dd7cddfSDavid du Colombier 			if(w != input)
10747dd7cddfSDavid du Colombier 				wcurrent(w);
10757dd7cddfSDavid du Colombier 		}else if(w == input)
10767dd7cddfSDavid du Colombier 			wcurrent(nil);
10777dd7cddfSDavid du Colombier 		flushimage(display, 1);
10787dd7cddfSDavid du Colombier 		break;
10797dd7cddfSDavid du Colombier 	case Refresh:
10807dd7cddfSDavid du Colombier 		if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r))
10817dd7cddfSDavid du Colombier 			break;
10827dd7cddfSDavid du Colombier 		if(!w->mouseopen)
10837dd7cddfSDavid du Colombier 			wrefresh(w, r);
10847dd7cddfSDavid du Colombier 		flushimage(display, 1);
10857dd7cddfSDavid du Colombier 		break;
10867dd7cddfSDavid du Colombier 	case Movemouse:
10877dd7cddfSDavid du Colombier 		if(sweeping || !ptinrect(r.min, w->i->r))
10887dd7cddfSDavid du Colombier 			break;
10897dd7cddfSDavid du Colombier 		wmovemouse(w, r.min);
10907dd7cddfSDavid du Colombier 	case Rawon:
10917dd7cddfSDavid du Colombier 		break;
10927dd7cddfSDavid du Colombier 	case Rawoff:
10937dd7cddfSDavid du Colombier 		if(w->deleted)
10947dd7cddfSDavid du Colombier 			break;
10957dd7cddfSDavid du Colombier 		while(w->nraw > 0){
10967dd7cddfSDavid du Colombier 			wkeyctl(w, w->raw[0]);
10977dd7cddfSDavid du Colombier 			--w->nraw;
10987dd7cddfSDavid du Colombier 			runemove(w->raw, w->raw+1, w->nraw);
10997dd7cddfSDavid du Colombier 		}
11007dd7cddfSDavid du Colombier 		break;
11017dd7cddfSDavid du Colombier 	case Holdon:
11027dd7cddfSDavid du Colombier 	case Holdoff:
11037dd7cddfSDavid du Colombier 		if(w->deleted)
11047dd7cddfSDavid du Colombier 			break;
11057dd7cddfSDavid du Colombier 		wrepaint(w);
11067dd7cddfSDavid du Colombier 		flushimage(display, 1);
11077dd7cddfSDavid du Colombier 		break;
11087dd7cddfSDavid du Colombier 	case Deleted:
11097dd7cddfSDavid du Colombier 		if(w->deleted)
11107dd7cddfSDavid du Colombier 			break;
11117dd7cddfSDavid du Colombier 		write(w->notefd, "hangup", 6);
11129a747e4fSDavid du Colombier 		proccreate(deletetimeoutproc, estrdup(w->name), 4096);
11137dd7cddfSDavid du Colombier 		wclosewin(w);
11147dd7cddfSDavid du Colombier 		break;
11157dd7cddfSDavid du Colombier 	case Exited:
111659cc4ca5SDavid du Colombier 		frclear(w, TRUE);
11177dd7cddfSDavid du Colombier 		close(w->notefd);
111859cc4ca5SDavid du Colombier 		chanfree(w->mc.c);
111959cc4ca5SDavid du Colombier 		chanfree(w->ck);
112059cc4ca5SDavid du Colombier 		chanfree(w->cctl);
112159cc4ca5SDavid du Colombier 		chanfree(w->conswrite);
112259cc4ca5SDavid du Colombier 		chanfree(w->consread);
112359cc4ca5SDavid du Colombier 		chanfree(w->mouseread);
112459cc4ca5SDavid du Colombier 		chanfree(w->wctlread);
11257dd7cddfSDavid du Colombier 		free(w->raw);
11267dd7cddfSDavid du Colombier 		free(w->r);
112759cc4ca5SDavid du Colombier 		free(w->dir);
11289a747e4fSDavid du Colombier 		free(w->label);
11297dd7cddfSDavid du Colombier 		free(w);
11307dd7cddfSDavid du Colombier 		break;
11317dd7cddfSDavid du Colombier 	}
11327dd7cddfSDavid du Colombier 	return m;
11337dd7cddfSDavid du Colombier }
11347dd7cddfSDavid du Colombier 
11357dd7cddfSDavid du Colombier /*
11367dd7cddfSDavid du Colombier  * Convert back to physical coordinates
11377dd7cddfSDavid du Colombier  */
11387dd7cddfSDavid du Colombier void
wmovemouse(Window * w,Point p)11397dd7cddfSDavid du Colombier wmovemouse(Window *w, Point p)
11407dd7cddfSDavid du Colombier {
11417dd7cddfSDavid du Colombier 	p.x += w->screenr.min.x-w->i->r.min.x;
11427dd7cddfSDavid du Colombier 	p.y += w->screenr.min.y-w->i->r.min.y;
11437dd7cddfSDavid du Colombier 	moveto(mousectl, p);
11447dd7cddfSDavid du Colombier }
11457dd7cddfSDavid du Colombier 
11467dd7cddfSDavid du Colombier void
wborder(Window * w,int type)11477dd7cddfSDavid du Colombier wborder(Window *w, int type)
11487dd7cddfSDavid du Colombier {
11497dd7cddfSDavid du Colombier 	Image *col;
11507dd7cddfSDavid du Colombier 
11517dd7cddfSDavid du Colombier 	if(w->i == nil)
11527dd7cddfSDavid du Colombier 		return;
11537dd7cddfSDavid du Colombier 	if(w->holding){
11547dd7cddfSDavid du Colombier 		if(type == Selborder)
11557dd7cddfSDavid du Colombier 			col = holdcol;
11567dd7cddfSDavid du Colombier 		else
11577dd7cddfSDavid du Colombier 			col = paleholdcol;
11587dd7cddfSDavid du Colombier 	}else{
11597dd7cddfSDavid du Colombier 		if(type == Selborder)
11607dd7cddfSDavid du Colombier 			col = titlecol;
11617dd7cddfSDavid du Colombier 		else
11627dd7cddfSDavid du Colombier 			col = lighttitlecol;
11637dd7cddfSDavid du Colombier 	}
11647dd7cddfSDavid du Colombier 
11657dd7cddfSDavid du Colombier 	border(w->i, w->i->r, Selborder, col, ZP);
11667dd7cddfSDavid du Colombier }
11677dd7cddfSDavid du Colombier 
11687dd7cddfSDavid du Colombier Window*
wpointto(Point pt)11697dd7cddfSDavid du Colombier wpointto(Point pt)
11707dd7cddfSDavid du Colombier {
11717dd7cddfSDavid du Colombier 	int i;
11727dd7cddfSDavid du Colombier 	Window *v, *w;
11737dd7cddfSDavid du Colombier 
11747dd7cddfSDavid du Colombier 	w = nil;
11757dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++){
11767dd7cddfSDavid du Colombier 		v = window[i];
11777dd7cddfSDavid du Colombier 		if(ptinrect(pt, v->screenr))
11787dd7cddfSDavid du Colombier 		if(!v->deleted)
11797dd7cddfSDavid du Colombier 		if(w==nil || v->topped>w->topped)
11807dd7cddfSDavid du Colombier 			w = v;
11817dd7cddfSDavid du Colombier 	}
11827dd7cddfSDavid du Colombier 	return w;
11837dd7cddfSDavid du Colombier }
11847dd7cddfSDavid du Colombier 
11857dd7cddfSDavid du Colombier void
wcurrent(Window * w)11867dd7cddfSDavid du Colombier wcurrent(Window *w)
11877dd7cddfSDavid du Colombier {
11887dd7cddfSDavid du Colombier 	Window *oi;
11897dd7cddfSDavid du Colombier 
119080ee5cbfSDavid du Colombier 	if(wkeyboard!=nil && w==wkeyboard)
119180ee5cbfSDavid du Colombier 		return;
11927dd7cddfSDavid du Colombier 	oi = input;
11937dd7cddfSDavid du Colombier 	input = w;
11947dd7cddfSDavid du Colombier 	if(oi!=w && oi!=nil)
11957dd7cddfSDavid du Colombier 		wrepaint(oi);
11967dd7cddfSDavid du Colombier 	if(w !=nil){
11977dd7cddfSDavid du Colombier 		wrepaint(w);
11987dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
11997dd7cddfSDavid du Colombier 	}
120080ee5cbfSDavid du Colombier 	if(w != oi){
120180ee5cbfSDavid du Colombier 		if(oi){
120280ee5cbfSDavid du Colombier 			oi->wctlready = 1;
120380ee5cbfSDavid du Colombier 			wsendctlmesg(oi, Wakeup, ZR, nil);
120480ee5cbfSDavid du Colombier 		}
120580ee5cbfSDavid du Colombier 		if(w){
120680ee5cbfSDavid du Colombier 			w->wctlready = 1;
120780ee5cbfSDavid du Colombier 			wsendctlmesg(w, Wakeup, ZR, nil);
120880ee5cbfSDavid du Colombier 		}
120980ee5cbfSDavid du Colombier 	}
12107dd7cddfSDavid du Colombier }
12117dd7cddfSDavid du Colombier 
12127dd7cddfSDavid du Colombier void
wsetcursor(Window * w,int force)12137dd7cddfSDavid du Colombier wsetcursor(Window *w, int force)
12147dd7cddfSDavid du Colombier {
12157dd7cddfSDavid du Colombier 	Cursor *p;
12167dd7cddfSDavid du Colombier 
12177dd7cddfSDavid du Colombier 	if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0)
12187dd7cddfSDavid du Colombier 		p = nil;
12197dd7cddfSDavid du Colombier 	else if(wpointto(mouse->xy) == w){
12207dd7cddfSDavid du Colombier 		p = w->cursorp;
12217dd7cddfSDavid du Colombier 		if(p==nil && w->holding)
12227dd7cddfSDavid du Colombier 			p = &whitearrow;
12237dd7cddfSDavid du Colombier 	}else
12247dd7cddfSDavid du Colombier 		p = nil;
122559cc4ca5SDavid du Colombier 	if(!menuing)
122659cc4ca5SDavid du Colombier 		riosetcursor(p, force && !menuing);
12277dd7cddfSDavid du Colombier }
12287dd7cddfSDavid du Colombier 
12297dd7cddfSDavid du Colombier void
riosetcursor(Cursor * p,int force)12307dd7cddfSDavid du Colombier riosetcursor(Cursor *p, int force)
12317dd7cddfSDavid du Colombier {
12327dd7cddfSDavid du Colombier 	if(!force && p==lastcursor)
12337dd7cddfSDavid du Colombier 		return;
12347dd7cddfSDavid du Colombier 	setcursor(mousectl, p);
12357dd7cddfSDavid du Colombier 	lastcursor = p;
12367dd7cddfSDavid du Colombier }
12377dd7cddfSDavid du Colombier 
12387dd7cddfSDavid du Colombier Window*
wtop(Point pt)12397dd7cddfSDavid du Colombier wtop(Point pt)
12407dd7cddfSDavid du Colombier {
12417dd7cddfSDavid du Colombier 	Window *w;
12427dd7cddfSDavid du Colombier 
12437dd7cddfSDavid du Colombier 	w = wpointto(pt);
12447dd7cddfSDavid du Colombier 	if(w){
124580ee5cbfSDavid du Colombier 		if(w->topped == topped)
124680ee5cbfSDavid du Colombier 			return nil;
12477dd7cddfSDavid du Colombier 		topwindow(w->i);
12487dd7cddfSDavid du Colombier 		wcurrent(w);
12497dd7cddfSDavid du Colombier 		flushimage(display, 1);
12507dd7cddfSDavid du Colombier 		w->topped = ++topped;
12517dd7cddfSDavid du Colombier 	}
12527dd7cddfSDavid du Colombier 	return w;
12537dd7cddfSDavid du Colombier }
12547dd7cddfSDavid du Colombier 
12557dd7cddfSDavid du Colombier void
wtopme(Window * w)12567dd7cddfSDavid du Colombier wtopme(Window *w)
12577dd7cddfSDavid du Colombier {
125880ee5cbfSDavid du Colombier 	if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
12597dd7cddfSDavid du Colombier 		topwindow(w->i);
12607dd7cddfSDavid du Colombier 		flushimage(display, 1);
12617dd7cddfSDavid du Colombier 		w->topped = ++ topped;
12627dd7cddfSDavid du Colombier 	}
12637dd7cddfSDavid du Colombier }
12647dd7cddfSDavid du Colombier 
12657dd7cddfSDavid du Colombier void
wbottomme(Window * w)12667dd7cddfSDavid du Colombier wbottomme(Window *w)
12677dd7cddfSDavid du Colombier {
12687dd7cddfSDavid du Colombier 	if(w!=nil && w->i!=nil && !w->deleted){
12697dd7cddfSDavid du Colombier 		bottomwindow(w->i);
12707dd7cddfSDavid du Colombier 		flushimage(display, 1);
127176f6a3b8SDavid du Colombier 		w->topped = - ++topped;
12727dd7cddfSDavid du Colombier 	}
12737dd7cddfSDavid du Colombier }
12747dd7cddfSDavid du Colombier 
12757dd7cddfSDavid du Colombier Window*
wlookid(int id)12767dd7cddfSDavid du Colombier wlookid(int id)
12777dd7cddfSDavid du Colombier {
12787dd7cddfSDavid du Colombier 	int i;
12797dd7cddfSDavid du Colombier 
12807dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
12817dd7cddfSDavid du Colombier 		if(window[i]->id == id)
12827dd7cddfSDavid du Colombier 			return window[i];
12837dd7cddfSDavid du Colombier 	return nil;
12847dd7cddfSDavid du Colombier }
12857dd7cddfSDavid du Colombier 
12867dd7cddfSDavid du Colombier void
wclosewin(Window * w)12877dd7cddfSDavid du Colombier wclosewin(Window *w)
12887dd7cddfSDavid du Colombier {
12897dd7cddfSDavid du Colombier 	Rectangle r;
12907dd7cddfSDavid du Colombier 	int i;
12917dd7cddfSDavid du Colombier 
12927dd7cddfSDavid du Colombier 	w->deleted = TRUE;
12937dd7cddfSDavid du Colombier 	if(w == input){
12947dd7cddfSDavid du Colombier 		input = nil;
12957dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
12967dd7cddfSDavid du Colombier 	}
129780ee5cbfSDavid du Colombier 	if(w == wkeyboard)
129880ee5cbfSDavid du Colombier 		wkeyboard = nil;
12997dd7cddfSDavid du Colombier 	for(i=0; i<nhidden; i++)
13007dd7cddfSDavid du Colombier 		if(hidden[i] == w){
13017dd7cddfSDavid du Colombier 			--nhidden;
130280ee5cbfSDavid du Colombier 			memmove(hidden+i, hidden+i+1, (nhidden-i)*sizeof(hidden[0]));
1303*cb8c047aSDavid du Colombier 			hidden[nhidden] = nil;
13047dd7cddfSDavid du Colombier 			break;
13057dd7cddfSDavid du Colombier 		}
13067dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
13077dd7cddfSDavid du Colombier 		if(window[i] == w){
13087dd7cddfSDavid du Colombier 			--nwindow;
13097dd7cddfSDavid du Colombier 			memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*));
13107dd7cddfSDavid du Colombier 			w->deleted = TRUE;
13117dd7cddfSDavid du Colombier 			r = w->i->r;
13127dd7cddfSDavid du Colombier 			/* move it off-screen to hide it, in case client is slow in letting it go */
13137dd7cddfSDavid du Colombier 			MOVEIT originwindow(w->i, r.min, view->r.max);
13147dd7cddfSDavid du Colombier 			freeimage(w->i);
13157dd7cddfSDavid du Colombier 			w->i = nil;
13167dd7cddfSDavid du Colombier 			return;
13177dd7cddfSDavid du Colombier 		}
13187dd7cddfSDavid du Colombier 	error("unknown window in closewin");
13197dd7cddfSDavid du Colombier }
13207dd7cddfSDavid du Colombier 
13217dd7cddfSDavid du Colombier void
wsetpid(Window * w,int pid,int dolabel)13229a747e4fSDavid du Colombier wsetpid(Window *w, int pid, int dolabel)
13237dd7cddfSDavid du Colombier {
13247dd7cddfSDavid du Colombier 	char buf[128];
13257dd7cddfSDavid du Colombier 	int fd;
13267dd7cddfSDavid du Colombier 
13277dd7cddfSDavid du Colombier 	w->pid = pid;
13289a747e4fSDavid du Colombier 	if(dolabel){
13299a747e4fSDavid du Colombier 		sprint(buf, "rc %d", pid);
13309a747e4fSDavid du Colombier 		free(w->label);
13319a747e4fSDavid du Colombier 		w->label = estrdup(buf);
13329a747e4fSDavid du Colombier 	}
13337dd7cddfSDavid du Colombier 	sprint(buf, "/proc/%d/notepg", pid);
13347dd7cddfSDavid du Colombier 	fd = open(buf, OWRITE|OCEXEC);
13359a747e4fSDavid du Colombier 	if(w->notefd > 0)
13369a747e4fSDavid du Colombier 		close(w->notefd);
13377dd7cddfSDavid du Colombier 	w->notefd = fd;
13387dd7cddfSDavid du Colombier }
13397dd7cddfSDavid du Colombier 
13407dd7cddfSDavid du Colombier void
winshell(void * args)13417dd7cddfSDavid du Colombier winshell(void *args)
13427dd7cddfSDavid du Colombier {
13437dd7cddfSDavid du Colombier 	Window *w;
13447dd7cddfSDavid du Colombier 	Channel *pidc;
13457dd7cddfSDavid du Colombier 	void **arg;
13467dd7cddfSDavid du Colombier 	char *cmd, *dir;
13477dd7cddfSDavid du Colombier 	char **argv;
13487dd7cddfSDavid du Colombier 
13497dd7cddfSDavid du Colombier 	arg = args;
13507dd7cddfSDavid du Colombier 	w = arg[0];
13517dd7cddfSDavid du Colombier 	pidc = arg[1];
13527dd7cddfSDavid du Colombier 	cmd = arg[2];
13537dd7cddfSDavid du Colombier 	argv = arg[3];
13547dd7cddfSDavid du Colombier 	dir = arg[4];
13557dd7cddfSDavid du Colombier 	rfork(RFNAMEG|RFFDG|RFENVG);
13567dd7cddfSDavid du Colombier 	if(filsysmount(filsys, w->id) < 0){
13579a747e4fSDavid du Colombier 		fprint(2, "mount failed: %r\n");
135880ee5cbfSDavid du Colombier 		sendul(pidc, 0);
13597dd7cddfSDavid du Colombier 		threadexits("mount failed");
13607dd7cddfSDavid du Colombier 	}
13617dd7cddfSDavid du Colombier 	close(0);
13627dd7cddfSDavid du Colombier 	if(open("/dev/cons", OREAD) < 0){
13639a747e4fSDavid du Colombier 		fprint(2, "can't open /dev/cons: %r\n");
136480ee5cbfSDavid du Colombier 		sendul(pidc, 0);
13657dd7cddfSDavid du Colombier 		threadexits("/dev/cons");
13667dd7cddfSDavid du Colombier 	}
13677dd7cddfSDavid du Colombier 	close(1);
13687dd7cddfSDavid du Colombier 	if(open("/dev/cons", OWRITE) < 0){
13699a747e4fSDavid du Colombier 		fprint(2, "can't open /dev/cons: %r\n");
137080ee5cbfSDavid du Colombier 		sendul(pidc, 0);
13717dd7cddfSDavid du Colombier 		threadexits("open");	/* BUG? was terminate() */
13727dd7cddfSDavid du Colombier 	}
13737dd7cddfSDavid du Colombier 	if(wclose(w) == 0){	/* remove extra ref hanging from creation */
13747dd7cddfSDavid du Colombier 		notify(nil);
13757dd7cddfSDavid du Colombier 		dup(1, 2);
13767dd7cddfSDavid du Colombier 		if(dir)
13777dd7cddfSDavid du Colombier 			chdir(dir);
13787dd7cddfSDavid du Colombier 		procexec(pidc, cmd, argv);
13797dd7cddfSDavid du Colombier 		_exits("exec failed");
13807dd7cddfSDavid du Colombier 	}
13817dd7cddfSDavid du Colombier }
13827dd7cddfSDavid du Colombier 
13837dd7cddfSDavid du Colombier static Rune left1[] =  { L'{', L'[', L'(', L'<', L'«', 0 };
13847dd7cddfSDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
13857dd7cddfSDavid du Colombier static Rune left2[] =  { L'\n', 0 };
13867dd7cddfSDavid du Colombier static Rune left3[] =  { L'\'', L'"', L'`', 0 };
13877dd7cddfSDavid du Colombier 
13887dd7cddfSDavid du Colombier Rune *left[] = {
13897dd7cddfSDavid du Colombier 	left1,
13907dd7cddfSDavid du Colombier 	left2,
13917dd7cddfSDavid du Colombier 	left3,
13927dd7cddfSDavid du Colombier 	nil
13937dd7cddfSDavid du Colombier };
13947dd7cddfSDavid du Colombier Rune *right[] = {
13957dd7cddfSDavid du Colombier 	right1,
13967dd7cddfSDavid du Colombier 	left2,
13977dd7cddfSDavid du Colombier 	left3,
13987dd7cddfSDavid du Colombier 	nil
13997dd7cddfSDavid du Colombier };
14007dd7cddfSDavid du Colombier 
14017dd7cddfSDavid du Colombier void
wdoubleclick(Window * w,uint * q0,uint * q1)14027dd7cddfSDavid du Colombier wdoubleclick(Window *w, uint *q0, uint *q1)
14037dd7cddfSDavid du Colombier {
14047dd7cddfSDavid du Colombier 	int c, i;
14057dd7cddfSDavid du Colombier 	Rune *r, *l, *p;
14067dd7cddfSDavid du Colombier 	uint q;
14077dd7cddfSDavid du Colombier 
14087dd7cddfSDavid du Colombier 	for(i=0; left[i]!=nil; i++){
14097dd7cddfSDavid du Colombier 		q = *q0;
14107dd7cddfSDavid du Colombier 		l = left[i];
14117dd7cddfSDavid du Colombier 		r = right[i];
14127dd7cddfSDavid du Colombier 		/* try matching character to left, looking right */
14137dd7cddfSDavid du Colombier 		if(q == 0)
14147dd7cddfSDavid du Colombier 			c = '\n';
14157dd7cddfSDavid du Colombier 		else
14167dd7cddfSDavid du Colombier 			c = w->r[q-1];
14177dd7cddfSDavid du Colombier 		p = strrune(l, c);
14187dd7cddfSDavid du Colombier 		if(p != nil){
14197dd7cddfSDavid du Colombier 			if(wclickmatch(w, c, r[p-l], 1, &q))
14207dd7cddfSDavid du Colombier 				*q1 = q-(c!='\n');
14217dd7cddfSDavid du Colombier 			return;
14227dd7cddfSDavid du Colombier 		}
14237dd7cddfSDavid du Colombier 		/* try matching character to right, looking left */
14247dd7cddfSDavid du Colombier 		if(q == w->nr)
14257dd7cddfSDavid du Colombier 			c = '\n';
14267dd7cddfSDavid du Colombier 		else
14277dd7cddfSDavid du Colombier 			c = w->r[q];
14287dd7cddfSDavid du Colombier 		p = strrune(r, c);
14297dd7cddfSDavid du Colombier 		if(p != nil){
14307dd7cddfSDavid du Colombier 			if(wclickmatch(w, c, l[p-r], -1, &q)){
14317dd7cddfSDavid du Colombier 				*q1 = *q0+(*q0<w->nr && c=='\n');
14327dd7cddfSDavid du Colombier 				*q0 = q;
14337dd7cddfSDavid du Colombier 				if(c!='\n' || q!=0 || w->r[0]=='\n')
14347dd7cddfSDavid du Colombier 					(*q0)++;
14357dd7cddfSDavid du Colombier 			}
14367dd7cddfSDavid du Colombier 			return;
14377dd7cddfSDavid du Colombier 		}
14387dd7cddfSDavid du Colombier 	}
14397dd7cddfSDavid du Colombier 	/* try filling out word to right */
14407dd7cddfSDavid du Colombier 	while(*q1<w->nr && isalnum(w->r[*q1]))
14417dd7cddfSDavid du Colombier 		(*q1)++;
14427dd7cddfSDavid du Colombier 	/* try filling out word to left */
14437dd7cddfSDavid du Colombier 	while(*q0>0 && isalnum(w->r[*q0-1]))
14447dd7cddfSDavid du Colombier 		(*q0)--;
14457dd7cddfSDavid du Colombier }
14467dd7cddfSDavid du Colombier 
14477dd7cddfSDavid du Colombier int
wclickmatch(Window * w,int cl,int cr,int dir,uint * q)14487dd7cddfSDavid du Colombier wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
14497dd7cddfSDavid du Colombier {
14507dd7cddfSDavid du Colombier 	Rune c;
14517dd7cddfSDavid du Colombier 	int nest;
14527dd7cddfSDavid du Colombier 
14537dd7cddfSDavid du Colombier 	nest = 1;
14547dd7cddfSDavid du Colombier 	for(;;){
14557dd7cddfSDavid du Colombier 		if(dir > 0){
14567dd7cddfSDavid du Colombier 			if(*q == w->nr)
14577dd7cddfSDavid du Colombier 				break;
14587dd7cddfSDavid du Colombier 			c = w->r[*q];
14597dd7cddfSDavid du Colombier 			(*q)++;
14607dd7cddfSDavid du Colombier 		}else{
14617dd7cddfSDavid du Colombier 			if(*q == 0)
14627dd7cddfSDavid du Colombier 				break;
14637dd7cddfSDavid du Colombier 			(*q)--;
14647dd7cddfSDavid du Colombier 			c = w->r[*q];
14657dd7cddfSDavid du Colombier 		}
14667dd7cddfSDavid du Colombier 		if(c == cr){
14677dd7cddfSDavid du Colombier 			if(--nest==0)
14687dd7cddfSDavid du Colombier 				return 1;
14697dd7cddfSDavid du Colombier 		}else if(c == cl)
14707dd7cddfSDavid du Colombier 			nest++;
14717dd7cddfSDavid du Colombier 	}
14727dd7cddfSDavid du Colombier 	return cl=='\n' && nest==1;
14737dd7cddfSDavid du Colombier }
14747dd7cddfSDavid du Colombier 
14757dd7cddfSDavid du Colombier 
14767dd7cddfSDavid du Colombier uint
wbacknl(Window * w,uint p,uint n)14777dd7cddfSDavid du Colombier wbacknl(Window *w, uint p, uint n)
14787dd7cddfSDavid du Colombier {
14797dd7cddfSDavid du Colombier 	int i, j;
14807dd7cddfSDavid du Colombier 
14817dd7cddfSDavid du Colombier 	/* look for start of this line if n==0 */
14827dd7cddfSDavid du Colombier 	if(n==0 && p>0 && w->r[p-1]!='\n')
14837dd7cddfSDavid du Colombier 		n = 1;
14847dd7cddfSDavid du Colombier 	i = n;
14857dd7cddfSDavid du Colombier 	while(i-->0 && p>0){
14867dd7cddfSDavid du Colombier 		--p;	/* it's at a newline now; back over it */
14877dd7cddfSDavid du Colombier 		if(p == 0)
14887dd7cddfSDavid du Colombier 			break;
14897dd7cddfSDavid du Colombier 		/* at 128 chars, call it a line anyway */
14907dd7cddfSDavid du Colombier 		for(j=128; --j>0 && p>0; p--)
14917dd7cddfSDavid du Colombier 			if(w->r[p-1]=='\n')
14927dd7cddfSDavid du Colombier 				break;
14937dd7cddfSDavid du Colombier 	}
14947dd7cddfSDavid du Colombier 	return p;
14957dd7cddfSDavid du Colombier }
14967dd7cddfSDavid du Colombier 
14977dd7cddfSDavid du Colombier void
wshow(Window * w,uint q0)14987dd7cddfSDavid du Colombier wshow(Window *w, uint q0)
14997dd7cddfSDavid du Colombier {
15007dd7cddfSDavid du Colombier 	int qe;
15017dd7cddfSDavid du Colombier 	int nl;
15027dd7cddfSDavid du Colombier 	uint q;
15037dd7cddfSDavid du Colombier 
15047dd7cddfSDavid du Colombier 	qe = w->org+w->nchars;
15057dd7cddfSDavid du Colombier 	if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
15067dd7cddfSDavid du Colombier 		wscrdraw(w);
15077dd7cddfSDavid du Colombier 	else{
15087dd7cddfSDavid du Colombier 		nl = 4*w->maxlines/5;
15097dd7cddfSDavid du Colombier 		q = wbacknl(w, q0, nl);
15107dd7cddfSDavid du Colombier 		/* avoid going backwards if trying to go forwards - long lines! */
15117dd7cddfSDavid du Colombier 		if(!(q0>w->org && q<w->org))
15127dd7cddfSDavid du Colombier 			wsetorigin(w, q, TRUE);
15137dd7cddfSDavid du Colombier 		while(q0 > w->org+w->nchars)
15147dd7cddfSDavid du Colombier 			wsetorigin(w, w->org+1, FALSE);
15157dd7cddfSDavid du Colombier 	}
15167dd7cddfSDavid du Colombier }
15177dd7cddfSDavid du Colombier 
15187dd7cddfSDavid du Colombier void
wsetorigin(Window * w,uint org,int exact)15197dd7cddfSDavid du Colombier wsetorigin(Window *w, uint org, int exact)
15207dd7cddfSDavid du Colombier {
15217dd7cddfSDavid du Colombier 	int i, a, fixup;
15227dd7cddfSDavid du Colombier 	Rune *r;
15237dd7cddfSDavid du Colombier 	uint n;
15247dd7cddfSDavid du Colombier 
15257dd7cddfSDavid du Colombier 	if(org>0 && !exact){
15267dd7cddfSDavid du Colombier 		/* org is an estimate of the char posn; find a newline */
15277dd7cddfSDavid du Colombier 		/* don't try harder than 256 chars */
15287dd7cddfSDavid du Colombier 		for(i=0; i<256 && org<w->nr; i++){
15297dd7cddfSDavid du Colombier 			if(w->r[org] == '\n'){
15307dd7cddfSDavid du Colombier 				org++;
15317dd7cddfSDavid du Colombier 				break;
15327dd7cddfSDavid du Colombier 			}
15337dd7cddfSDavid du Colombier 			org++;
15347dd7cddfSDavid du Colombier 		}
15357dd7cddfSDavid du Colombier 	}
15367dd7cddfSDavid du Colombier 	a = org-w->org;
15377dd7cddfSDavid du Colombier 	fixup = 0;
15387dd7cddfSDavid du Colombier 	if(a>=0 && a<w->nchars){
15397dd7cddfSDavid du Colombier 		frdelete(w, 0, a);
15407dd7cddfSDavid du Colombier 		fixup = 1;	/* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
15417dd7cddfSDavid du Colombier 	}else if(a<0 && -a<w->nchars){
15427dd7cddfSDavid du Colombier 		n = w->org - org;
15437dd7cddfSDavid du Colombier 		r = runemalloc(n);
15447dd7cddfSDavid du Colombier 		runemove(r, w->r+org, n);
15457dd7cddfSDavid du Colombier 		frinsert(w, r, r+n, 0);
15467dd7cddfSDavid du Colombier 		free(r);
15477dd7cddfSDavid du Colombier 	}else
15487dd7cddfSDavid du Colombier 		frdelete(w, 0, w->nchars);
15497dd7cddfSDavid du Colombier 	w->org = org;
15507dd7cddfSDavid du Colombier 	wfill(w);
15517dd7cddfSDavid du Colombier 	wscrdraw(w);
15527dd7cddfSDavid du Colombier 	wsetselect(w, w->q0, w->q1);
15537dd7cddfSDavid du Colombier 	if(fixup && w->p1 > w->p0)
15547dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
15557dd7cddfSDavid du Colombier }
15567dd7cddfSDavid du Colombier 
15577dd7cddfSDavid du Colombier void
wsetselect(Window * w,uint q0,uint q1)15587dd7cddfSDavid du Colombier wsetselect(Window *w, uint q0, uint q1)
15597dd7cddfSDavid du Colombier {
15607dd7cddfSDavid du Colombier 	int p0, p1;
15617dd7cddfSDavid du Colombier 
15627dd7cddfSDavid du Colombier 	/* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
15637dd7cddfSDavid du Colombier 	w->q0 = q0;
15647dd7cddfSDavid du Colombier 	w->q1 = q1;
15657dd7cddfSDavid du Colombier 	/* compute desired p0,p1 from q0,q1 */
15667dd7cddfSDavid du Colombier 	p0 = q0-w->org;
15677dd7cddfSDavid du Colombier 	p1 = q1-w->org;
15687dd7cddfSDavid du Colombier 	if(p0 < 0)
15697dd7cddfSDavid du Colombier 		p0 = 0;
15707dd7cddfSDavid du Colombier 	if(p1 < 0)
15717dd7cddfSDavid du Colombier 		p1 = 0;
15727dd7cddfSDavid du Colombier 	if(p0 > w->nchars)
15737dd7cddfSDavid du Colombier 		p0 = w->nchars;
15747dd7cddfSDavid du Colombier 	if(p1 > w->nchars)
15757dd7cddfSDavid du Colombier 		p1 = w->nchars;
15767dd7cddfSDavid du Colombier 	if(p0==w->p0 && p1==w->p1)
15777dd7cddfSDavid du Colombier 		return;
15787dd7cddfSDavid du Colombier 	/* screen disagrees with desired selection */
15797dd7cddfSDavid du Colombier 	if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
15807dd7cddfSDavid du Colombier 		/* no overlap or too easy to bother trying */
15817dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
15827dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
15837dd7cddfSDavid du Colombier 		goto Return;
15847dd7cddfSDavid du Colombier 	}
15857dd7cddfSDavid du Colombier 	/* overlap; avoid unnecessary painting */
15867dd7cddfSDavid du Colombier 	if(p0 < w->p0){
15877dd7cddfSDavid du Colombier 		/* extend selection backwards */
15887dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
15897dd7cddfSDavid du Colombier 	}else if(p0 > w->p0){
15907dd7cddfSDavid du Colombier 		/* trim first part of selection */
15917dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
15927dd7cddfSDavid du Colombier 	}
15937dd7cddfSDavid du Colombier 	if(p1 > w->p1){
15947dd7cddfSDavid du Colombier 		/* extend selection forwards */
15957dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
15967dd7cddfSDavid du Colombier 	}else if(p1 < w->p1){
15977dd7cddfSDavid du Colombier 		/* trim last part of selection */
15987dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
15997dd7cddfSDavid du Colombier 	}
16007dd7cddfSDavid du Colombier 
16017dd7cddfSDavid du Colombier     Return:
16027dd7cddfSDavid du Colombier 	w->p0 = p0;
16037dd7cddfSDavid du Colombier 	w->p1 = p1;
16047dd7cddfSDavid du Colombier }
16057dd7cddfSDavid du Colombier 
16067dd7cddfSDavid du Colombier uint
winsert(Window * w,Rune * r,int n,uint q0)16077dd7cddfSDavid du Colombier winsert(Window *w, Rune *r, int n, uint q0)
16087dd7cddfSDavid du Colombier {
16097dd7cddfSDavid du Colombier 	uint m;
16107dd7cddfSDavid du Colombier 
16117dd7cddfSDavid du Colombier 	if(n == 0)
16127dd7cddfSDavid du Colombier 		return q0;
16137dd7cddfSDavid du Colombier 	if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
16147dd7cddfSDavid du Colombier 		m = min(HiWater-LoWater, min(w->org, w->qh));
16157dd7cddfSDavid du Colombier 		w->org -= m;
16167dd7cddfSDavid du Colombier 		w->qh -= m;
16177dd7cddfSDavid du Colombier 		if(w->q0 > m)
16187dd7cddfSDavid du Colombier 			w->q0 -= m;
16197dd7cddfSDavid du Colombier 		else
16207dd7cddfSDavid du Colombier 			w->q0 = 0;
16217dd7cddfSDavid du Colombier 		if(w->q1 > m)
16227dd7cddfSDavid du Colombier 			w->q1 -= m;
16237dd7cddfSDavid du Colombier 		else
16247dd7cddfSDavid du Colombier 			w->q1 = 0;
16257dd7cddfSDavid du Colombier 		w->nr -= m;
16267dd7cddfSDavid du Colombier 		runemove(w->r, w->r+m, w->nr);
16277dd7cddfSDavid du Colombier 		q0 -= m;
16287dd7cddfSDavid du Colombier 	}
16297dd7cddfSDavid du Colombier 	if(w->nr+n > w->maxr){
16307dd7cddfSDavid du Colombier 		/*
16317dd7cddfSDavid du Colombier 		 * Minimize realloc breakage:
16327dd7cddfSDavid du Colombier 		 *	Allocate at least MinWater
16337dd7cddfSDavid du Colombier 		 * 	Double allocation size each time
16347dd7cddfSDavid du Colombier 		 *	But don't go much above HiWater
16357dd7cddfSDavid du Colombier 		 */
16367dd7cddfSDavid du Colombier 		m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
16377dd7cddfSDavid du Colombier 		if(m > HiWater)
16387dd7cddfSDavid du Colombier 			m = max(HiWater+MinWater, w->nr+n);
16397dd7cddfSDavid du Colombier 		if(m > w->maxr){
16407dd7cddfSDavid du Colombier 			w->r = runerealloc(w->r, m);
16417dd7cddfSDavid du Colombier 			w->maxr = m;
16427dd7cddfSDavid du Colombier 		}
16437dd7cddfSDavid du Colombier 	}
16447dd7cddfSDavid du Colombier 	runemove(w->r+q0+n, w->r+q0, w->nr-q0);
16457dd7cddfSDavid du Colombier 	runemove(w->r+q0, r, n);
16467dd7cddfSDavid du Colombier 	w->nr += n;
16477dd7cddfSDavid du Colombier 	/* if output touches, advance selection, not qh; works best for keyboard and output */
16487dd7cddfSDavid du Colombier 	if(q0 <= w->q1)
16497dd7cddfSDavid du Colombier 		w->q1 += n;
16507dd7cddfSDavid du Colombier 	if(q0 <= w->q0)
16517dd7cddfSDavid du Colombier 		w->q0 += n;
16527dd7cddfSDavid du Colombier 	if(q0 < w->qh)
16537dd7cddfSDavid du Colombier 		w->qh += n;
16547dd7cddfSDavid du Colombier 	if(q0 < w->org)
16557dd7cddfSDavid du Colombier 		w->org += n;
16567dd7cddfSDavid du Colombier 	else if(q0 <= w->org+w->nchars)
16577dd7cddfSDavid du Colombier 		frinsert(w, r, r+n, q0-w->org);
16587dd7cddfSDavid du Colombier 	return q0;
16597dd7cddfSDavid du Colombier }
16607dd7cddfSDavid du Colombier 
16617dd7cddfSDavid du Colombier void
wfill(Window * w)16627dd7cddfSDavid du Colombier wfill(Window *w)
16637dd7cddfSDavid du Colombier {
16647dd7cddfSDavid du Colombier 	Rune *rp;
16657dd7cddfSDavid du Colombier 	int i, n, m, nl;
16667dd7cddfSDavid du Colombier 
16677dd7cddfSDavid du Colombier 	if(w->lastlinefull)
16687dd7cddfSDavid du Colombier 		return;
16699a747e4fSDavid du Colombier 	rp = malloc(messagesize);
16707dd7cddfSDavid du Colombier 	do{
16717dd7cddfSDavid du Colombier 		n = w->nr-(w->org+w->nchars);
16727dd7cddfSDavid du Colombier 		if(n == 0)
16737dd7cddfSDavid du Colombier 			break;
16747dd7cddfSDavid du Colombier 		if(n > 2000)	/* educated guess at reasonable amount */
16757dd7cddfSDavid du Colombier 			n = 2000;
16767dd7cddfSDavid du Colombier 		runemove(rp, w->r+(w->org+w->nchars), n);
16777dd7cddfSDavid du Colombier 		/*
16787dd7cddfSDavid du Colombier 		 * it's expensive to frinsert more than we need, so
16797dd7cddfSDavid du Colombier 		 * count newlines.
16807dd7cddfSDavid du Colombier 		 */
16817dd7cddfSDavid du Colombier 		nl = w->maxlines-w->nlines;
16827dd7cddfSDavid du Colombier 		m = 0;
16837dd7cddfSDavid du Colombier 		for(i=0; i<n; ){
16847dd7cddfSDavid du Colombier 			if(rp[i++] == '\n'){
16857dd7cddfSDavid du Colombier 				m++;
16867dd7cddfSDavid du Colombier 				if(m >= nl)
16877dd7cddfSDavid du Colombier 					break;
16887dd7cddfSDavid du Colombier 			}
16897dd7cddfSDavid du Colombier 		}
16907dd7cddfSDavid du Colombier 		frinsert(w, rp, rp+i, w->nchars);
16917dd7cddfSDavid du Colombier 	}while(w->lastlinefull == FALSE);
16927dd7cddfSDavid du Colombier 	free(rp);
16937dd7cddfSDavid du Colombier }
16947dd7cddfSDavid du Colombier 
16957dd7cddfSDavid du Colombier char*
wcontents(Window * w,int * ip)16967dd7cddfSDavid du Colombier wcontents(Window *w, int *ip)
16977dd7cddfSDavid du Colombier {
16987dd7cddfSDavid du Colombier 	return runetobyte(w->r, w->nr, ip);
16997dd7cddfSDavid du Colombier }
1700