xref: /plan9-contrib/sys/src/cmd/rio/wind.c (revision 6ff5e9135082ce281d25c68a5544eef8249d480c)
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 MOVEIT if(0)
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier enum
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier 	HiWater	= 64000,	/* max size of history */
197dd7cddfSDavid du Colombier 	LoWater	= 33000,	/* min size of history after max'ed */
207dd7cddfSDavid du Colombier 	MinWater	= 2000,	/* room to leave available when reallocating */
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier static	int		topped;
247dd7cddfSDavid du Colombier static	int		id;
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier static	Image	*cols[NCOL];
277dd7cddfSDavid du Colombier static	Image	*grey;
287dd7cddfSDavid du Colombier static	Image	*darkgrey;
297dd7cddfSDavid du Colombier static	Cursor	*lastcursor;
307dd7cddfSDavid du Colombier static	Image	*titlecol;
317dd7cddfSDavid du Colombier static	Image	*lighttitlecol;
327dd7cddfSDavid du Colombier static	Image	*holdcol;
337dd7cddfSDavid du Colombier static	Image	*lightholdcol;
347dd7cddfSDavid du Colombier static	Image	*paleholdcol;
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier Window*
373ff48bf5SDavid du Colombier wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier 	Window *w;
407dd7cddfSDavid du Colombier 	Rectangle r;
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier 	if(cols[0] == nil){
437dd7cddfSDavid du Colombier 		/* greys are multiples of 0x11111100+0xFF, 14* being palest */
447dd7cddfSDavid du Colombier 		grey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
457dd7cddfSDavid du Colombier 		darkgrey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF);
467dd7cddfSDavid du Colombier 		cols[BACK] = display->white;
477dd7cddfSDavid du Colombier 		cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
487dd7cddfSDavid du Colombier 		cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF);
497dd7cddfSDavid du Colombier 		cols[TEXT] = display->black;
507dd7cddfSDavid du Colombier 		cols[HTEXT] = display->black;
517dd7cddfSDavid du Colombier 		titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
527dd7cddfSDavid du Colombier 		lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
537dd7cddfSDavid du Colombier 		holdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
547dd7cddfSDavid du Colombier 		lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
557dd7cddfSDavid du Colombier 		paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
567dd7cddfSDavid du Colombier 	}
577dd7cddfSDavid du Colombier 	w = emalloc(sizeof(Window));
587dd7cddfSDavid du Colombier 	w->screenr = i->r;
597dd7cddfSDavid du Colombier 	r = insetrect(i->r, Selborder+1);
607dd7cddfSDavid du Colombier 	w->i = i;
617dd7cddfSDavid du Colombier 	w->mc = *mc;
627dd7cddfSDavid du Colombier 	w->ck = ck;
637dd7cddfSDavid du Colombier 	w->cctl = cctl;
647dd7cddfSDavid du Colombier 	w->cursorp = nil;
657dd7cddfSDavid du Colombier 	w->conswrite = chancreate(sizeof(Conswritemesg), 0);
667dd7cddfSDavid du Colombier 	w->consread =  chancreate(sizeof(Consreadmesg), 0);
677dd7cddfSDavid du Colombier 	w->mouseread =  chancreate(sizeof(Mousereadmesg), 0);
6859cc4ca5SDavid du Colombier 	w->wctlread =  chancreate(sizeof(Consreadmesg), 0);
697dd7cddfSDavid du Colombier 	w->scrollr = r;
707dd7cddfSDavid du Colombier 	w->scrollr.max.x = r.min.x+Scrollwid;
717dd7cddfSDavid du Colombier 	w->lastsr = ZR;
727dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
737dd7cddfSDavid du Colombier 	frinit(w, r, font, i, cols);
747dd7cddfSDavid du Colombier 	w->maxtab = maxtab*stringwidth(font, "0");
757dd7cddfSDavid du Colombier 	w->topped = ++topped;
767dd7cddfSDavid du Colombier 	w->id = ++id;
777dd7cddfSDavid du Colombier 	w->notefd = -1;
787dd7cddfSDavid du Colombier 	w->scrolling = scrolling;
797dd7cddfSDavid du Colombier 	w->dir = estrdup(startdir);
809a747e4fSDavid du Colombier 	w->label = estrdup("<unnamed>");
817dd7cddfSDavid du Colombier 	r = insetrect(w->i->r, Selborder);
827dd7cddfSDavid du Colombier 	draw(w->i, r, cols[BACK], nil, w->entire.min);
837dd7cddfSDavid du Colombier 	wborder(w, Selborder);
847dd7cddfSDavid du Colombier 	wscrdraw(w);
857dd7cddfSDavid du Colombier 	incref(w);	/* ref will be removed after mounting; avoids delete before ready to be deleted */
867dd7cddfSDavid du Colombier 	return w;
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier void
907dd7cddfSDavid du Colombier wsetname(Window *w)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	int i, n;
939a747e4fSDavid du Colombier 	char err[ERRMAX];
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	n = sprint(w->name, "window.%d.%d", w->id, w->namecount++);
967dd7cddfSDavid du Colombier 	for(i='A'; i<='Z'; i++){
977dd7cddfSDavid du Colombier 		if(nameimage(w->i, w->name, 1) > 0)
987dd7cddfSDavid du Colombier 			return;
999a747e4fSDavid du Colombier 		errstr(err, sizeof err);
1007dd7cddfSDavid du Colombier 		if(strcmp(err, "image name in use") != 0)
1017dd7cddfSDavid du Colombier 			break;
1027dd7cddfSDavid du Colombier 		w->name[n] = i;
1037dd7cddfSDavid du Colombier 		w->name[n+1] = 0;
1047dd7cddfSDavid du Colombier 	}
1057dd7cddfSDavid du Colombier 	w->name[0] = 0;
1069a747e4fSDavid du Colombier 	fprint(2, "rio: setname failed: %s\n", err);
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier void
1107dd7cddfSDavid du Colombier wresize(Window *w, Image *i, int move)
1117dd7cddfSDavid du Colombier {
1127dd7cddfSDavid du Colombier 	Rectangle r, or;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	or = w->i->r;
1157dd7cddfSDavid du Colombier 	if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(i->r)))
1167dd7cddfSDavid du Colombier 		draw(i, i->r, w->i, nil, w->i->r.min);
1177dd7cddfSDavid du Colombier 	freeimage(w->i);
1187dd7cddfSDavid du Colombier 	w->i = i;
1199a747e4fSDavid du Colombier 	wsetname(w);
1207dd7cddfSDavid du Colombier 	w->mc.image = i;
1217dd7cddfSDavid du Colombier 	r = insetrect(i->r, Selborder+1);
1227dd7cddfSDavid du Colombier 	w->scrollr = r;
1237dd7cddfSDavid du Colombier 	w->scrollr.max.x = r.min.x+Scrollwid;
1247dd7cddfSDavid du Colombier 	w->lastsr = ZR;
1257dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
1267dd7cddfSDavid du Colombier 	if(move)
1277dd7cddfSDavid du Colombier 		frsetrects(w, r, w->i);
1287dd7cddfSDavid du Colombier 	else{
1297dd7cddfSDavid du Colombier 		frclear(w, FALSE);
1307dd7cddfSDavid du Colombier 		frinit(w, r, w->font, w->i, cols);
1317dd7cddfSDavid du Colombier 		wsetcols(w);
1327dd7cddfSDavid du Colombier 		w->maxtab = maxtab*stringwidth(w->font, "0");
1337dd7cddfSDavid du Colombier 		r = insetrect(w->i->r, Selborder);
1347dd7cddfSDavid du Colombier 		draw(w->i, r, cols[BACK], nil, w->entire.min);
1357dd7cddfSDavid du Colombier 		wfill(w);
1367dd7cddfSDavid du Colombier 		wsetselect(w, w->q0, w->q1);
1377dd7cddfSDavid du Colombier 		wscrdraw(w);
1387dd7cddfSDavid du Colombier 	}
1397dd7cddfSDavid du Colombier 	wborder(w, Selborder);
1407dd7cddfSDavid du Colombier 	w->topped = ++topped;
1417dd7cddfSDavid du Colombier 	w->resized = TRUE;
1427dd7cddfSDavid du Colombier 	w->mouse.counter++;
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier void
1467dd7cddfSDavid du Colombier wrefresh(Window *w, Rectangle)
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier 	/* BUG: rectangle is ignored */
1497dd7cddfSDavid du Colombier 	if(w == input)
1507dd7cddfSDavid du Colombier 		wborder(w, Selborder);
1517dd7cddfSDavid du Colombier 	else
1527dd7cddfSDavid du Colombier 		wborder(w, Unselborder);
1537dd7cddfSDavid du Colombier 	if(w->mouseopen)
1547dd7cddfSDavid du Colombier 		return;
1557dd7cddfSDavid du Colombier 	draw(w->i, insetrect(w->i->r, Borderwidth), w->cols[BACK], nil, w->i->r.min);
1567dd7cddfSDavid du Colombier 	w->ticked = 0;
1577dd7cddfSDavid du Colombier 	if(w->p0 > 0)
1587dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);
1597dd7cddfSDavid du Colombier 	if(w->p1 < w->nchars)
1607dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);
1617dd7cddfSDavid du Colombier 	frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);
1627dd7cddfSDavid du Colombier 	w->lastsr = ZR;
1637dd7cddfSDavid du Colombier 	wscrdraw(w);
1647dd7cddfSDavid du Colombier }
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier int
1677dd7cddfSDavid du Colombier wclose(Window *w)
1687dd7cddfSDavid du Colombier {
1697dd7cddfSDavid du Colombier 	int i;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	i = decref(w);
1727dd7cddfSDavid du Colombier 	if(i > 0)
1737dd7cddfSDavid du Colombier 		return 0;
1747dd7cddfSDavid du Colombier 	if(i < 0)
1757dd7cddfSDavid du Colombier 		error("negative ref count");
1767dd7cddfSDavid du Colombier 	if(!w->deleted)
1777dd7cddfSDavid du Colombier 		wclosewin(w);
1787dd7cddfSDavid du Colombier 	wsendctlmesg(w, Exited, ZR, nil);
1797dd7cddfSDavid du Colombier 	return 1;
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier void
1847dd7cddfSDavid du Colombier winctl(void *arg)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier 	Rune *rp, *bp, *tp, *up, *kbdr;
1877dd7cddfSDavid du Colombier 	uint qh;
1887dd7cddfSDavid du Colombier 	int nr, nb, c, wid, i, npart, initial, lastb;
18980ee5cbfSDavid du Colombier 	char *s, *t, part[3];
1907dd7cddfSDavid du Colombier 	Window *w;
1917dd7cddfSDavid du Colombier 	Mousestate *mp, m;
19259cc4ca5SDavid du Colombier 	enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT };
1937dd7cddfSDavid du Colombier 	Alt alts[NWALT+1];
1947dd7cddfSDavid du Colombier 	Mousereadmesg mrm;
1957dd7cddfSDavid du Colombier 	Conswritemesg cwm;
1967dd7cddfSDavid du Colombier 	Consreadmesg crm;
19759cc4ca5SDavid du Colombier 	Consreadmesg cwrm;
1987dd7cddfSDavid du Colombier 	Stringpair pair;
1997dd7cddfSDavid du Colombier 	Wctlmesg wcm;
20059cc4ca5SDavid du Colombier 	char buf[4*12+1];
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier 	w = arg;
20359cc4ca5SDavid du Colombier 	snprint(buf, sizeof buf, "winctl-id%d", w->id);
2047dd7cddfSDavid du Colombier 	threadsetname(buf);
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier 	mrm.cm = chancreate(sizeof(Mouse), 0);
2077dd7cddfSDavid du Colombier 	cwm.cw = chancreate(sizeof(Stringpair), 0);
2087dd7cddfSDavid du Colombier 	crm.c1 = chancreate(sizeof(Stringpair), 0);
2097dd7cddfSDavid du Colombier 	crm.c2 = chancreate(sizeof(Stringpair), 0);
21059cc4ca5SDavid du Colombier 	cwrm.c1 = chancreate(sizeof(Stringpair), 0);
21159cc4ca5SDavid du Colombier 	cwrm.c2 = chancreate(sizeof(Stringpair), 0);
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	alts[WKey].c = w->ck;
2157dd7cddfSDavid du Colombier 	alts[WKey].v = &kbdr;
2167dd7cddfSDavid du Colombier 	alts[WKey].op = CHANRCV;
2177dd7cddfSDavid du Colombier 	alts[WMouse].c = w->mc.c;
2187dd7cddfSDavid du Colombier 	alts[WMouse].v = &w->mc.Mouse;
2197dd7cddfSDavid du Colombier 	alts[WMouse].op = CHANRCV;
2207dd7cddfSDavid du Colombier 	alts[WMouseread].c = w->mouseread;
2217dd7cddfSDavid du Colombier 	alts[WMouseread].v = &mrm;
2227dd7cddfSDavid du Colombier 	alts[WMouseread].op = CHANSND;
2237dd7cddfSDavid du Colombier 	alts[WCtl].c = w->cctl;
2247dd7cddfSDavid du Colombier 	alts[WCtl].v = &wcm;
2257dd7cddfSDavid du Colombier 	alts[WCtl].op = CHANRCV;
2267dd7cddfSDavid du Colombier 	alts[WCwrite].c = w->conswrite;
2277dd7cddfSDavid du Colombier 	alts[WCwrite].v = &cwm;
2287dd7cddfSDavid du Colombier 	alts[WCwrite].op = CHANSND;
2297dd7cddfSDavid du Colombier 	alts[WCread].c = w->consread;
2307dd7cddfSDavid du Colombier 	alts[WCread].v = &crm;
2317dd7cddfSDavid du Colombier 	alts[WCread].op = CHANSND;
23259cc4ca5SDavid du Colombier 	alts[WWread].c = w->wctlread;
23359cc4ca5SDavid du Colombier 	alts[WWread].v = &cwrm;
23459cc4ca5SDavid du Colombier 	alts[WWread].op = CHANSND;
2357dd7cddfSDavid du Colombier 	alts[NWALT].op = CHANEND;
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier 	npart = 0;
2387dd7cddfSDavid du Colombier 	lastb = -1;
2397dd7cddfSDavid du Colombier 	for(;;){
2407dd7cddfSDavid du Colombier 		if(w->mouseopen && w->mouse.counter != w->mouse.lastcounter)
2417dd7cddfSDavid du Colombier 			alts[WMouseread].op = CHANSND;
2427dd7cddfSDavid du Colombier 		else
2437dd7cddfSDavid du Colombier 			alts[WMouseread].op = CHANNOP;
2447dd7cddfSDavid du Colombier 		if(!w->scrolling && !w->mouseopen && w->qh>w->org+w->nchars)
2457dd7cddfSDavid du Colombier 			alts[WCwrite].op = CHANNOP;
2467dd7cddfSDavid du Colombier 		else
2477dd7cddfSDavid du Colombier 			alts[WCwrite].op = CHANSND;
24859cc4ca5SDavid du Colombier 		if(w->deleted || !w->wctlready)
24959cc4ca5SDavid du Colombier 			alts[WWread].op = CHANNOP;
25059cc4ca5SDavid du Colombier 		else
25159cc4ca5SDavid du Colombier 			alts[WWread].op = CHANSND;
2527dd7cddfSDavid du Colombier 		/* this code depends on NL and EOT fitting in a single byte */
2537dd7cddfSDavid du Colombier 		/* kind of expensive for each loop; worth precomputing? */
2547dd7cddfSDavid du Colombier 		if(w->holding)
2557dd7cddfSDavid du Colombier 			alts[WCread].op = CHANNOP;
2567dd7cddfSDavid du Colombier 		else if(npart || (w->rawing && w->nraw>0))
2577dd7cddfSDavid du Colombier 			alts[WCread].op = CHANSND;
2587dd7cddfSDavid du Colombier 		else{
2597dd7cddfSDavid du Colombier 			alts[WCread].op = CHANNOP;
2607dd7cddfSDavid du Colombier 			for(i=w->qh; i<w->nr; i++){
2617dd7cddfSDavid du Colombier 				c = w->r[i];
2627dd7cddfSDavid du Colombier 				if(c=='\n' || c=='\004'){
2637dd7cddfSDavid du Colombier 					alts[WCread].op = CHANSND;
2647dd7cddfSDavid du Colombier 					break;
2657dd7cddfSDavid du Colombier 				}
2667dd7cddfSDavid du Colombier 			}
2677dd7cddfSDavid du Colombier 		}
2687dd7cddfSDavid du Colombier 		switch(alt(alts)){
2697dd7cddfSDavid du Colombier 		case WKey:
2707dd7cddfSDavid du Colombier 			for(i=0; kbdr[i]!=L'\0'; i++)
2717dd7cddfSDavid du Colombier 				wkeyctl(w, kbdr[i]);
2727dd7cddfSDavid du Colombier //			wkeyctl(w, r);
2737dd7cddfSDavid du Colombier ///			while(nbrecv(w->ck, &r))
2747dd7cddfSDavid du Colombier //				wkeyctl(w, r);
2757dd7cddfSDavid du Colombier 			break;
2767dd7cddfSDavid du Colombier 		case WMouse:
2777dd7cddfSDavid du Colombier 			if(w->mouseopen) {
2787dd7cddfSDavid du Colombier 				w->mouse.counter++;
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier 				/* queue click events */
2817dd7cddfSDavid du Colombier 				if(!w->mouse.qfull && lastb != w->mc.buttons) {	/* add to ring */
2827dd7cddfSDavid du Colombier 					mp = &w->mouse.queue[w->mouse.wi];
2837dd7cddfSDavid du Colombier 					if(++w->mouse.wi == nelem(w->mouse.queue))
2847dd7cddfSDavid du Colombier 						w->mouse.wi = 0;
2857dd7cddfSDavid du Colombier 					if(w->mouse.wi == w->mouse.ri)
2867dd7cddfSDavid du Colombier 						w->mouse.qfull = TRUE;
2877dd7cddfSDavid du Colombier 					mp->Mouse = w->mc;
2887dd7cddfSDavid du Colombier 					mp->counter = w->mouse.counter;
2897dd7cddfSDavid du Colombier 					lastb = w->mc.buttons;
2907dd7cddfSDavid du Colombier 				}
2917dd7cddfSDavid du Colombier 			} else
2927dd7cddfSDavid du Colombier 				wmousectl(w);
2937dd7cddfSDavid du Colombier 			break;
2947dd7cddfSDavid du Colombier 		case WMouseread:
2957dd7cddfSDavid du Colombier 			/* send a queued event or, if the queue is empty, the current state */
2967dd7cddfSDavid du Colombier 			/* if the queue has filled, we discard all the events it contained. */
2977dd7cddfSDavid du Colombier 			/* the intent is to discard frantic clicking by the user during long latencies. */
2987dd7cddfSDavid du Colombier 			w->mouse.qfull = FALSE;
2997dd7cddfSDavid du Colombier 			if(w->mouse.wi != w->mouse.ri) {
3007dd7cddfSDavid du Colombier 				m = w->mouse.queue[w->mouse.ri];
3017dd7cddfSDavid du Colombier 				if(++w->mouse.ri == nelem(w->mouse.queue))
3027dd7cddfSDavid du Colombier 					w->mouse.ri = 0;
3037dd7cddfSDavid du Colombier 			} else
3047dd7cddfSDavid du Colombier 				m = (Mousestate){w->mc.Mouse, w->mouse.counter};
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier 			w->mouse.lastcounter = m.counter;
3077dd7cddfSDavid du Colombier 			send(mrm.cm, &m.Mouse);
3087dd7cddfSDavid du Colombier 			continue;
3097dd7cddfSDavid du Colombier 		case WCtl:
3107dd7cddfSDavid du Colombier 			if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
31159cc4ca5SDavid du Colombier 				chanfree(crm.c1);
31259cc4ca5SDavid du Colombier 				chanfree(crm.c2);
31359cc4ca5SDavid du Colombier 				chanfree(mrm.cm);
31459cc4ca5SDavid du Colombier 				chanfree(cwm.cw);
31559cc4ca5SDavid du Colombier 				chanfree(cwrm.c1);
31659cc4ca5SDavid du Colombier 				chanfree(cwrm.c2);
3177dd7cddfSDavid du Colombier 				threadexits(nil);
3187dd7cddfSDavid du Colombier 			}
3197dd7cddfSDavid du Colombier 			continue;
3207dd7cddfSDavid du Colombier 		case WCwrite:
3217dd7cddfSDavid du Colombier 			recv(cwm.cw, &pair);
3227dd7cddfSDavid du Colombier 			rp = pair.s;
3237dd7cddfSDavid du Colombier 			nr = pair.ns;
3247dd7cddfSDavid du Colombier 			bp = rp;
3257dd7cddfSDavid du Colombier 			for(i=0; i<nr; i++)
3267dd7cddfSDavid du Colombier 				if(*bp++ == '\b'){
3277dd7cddfSDavid du Colombier 					--bp;
3287dd7cddfSDavid du Colombier 					initial = 0;
3297dd7cddfSDavid du Colombier 					tp = runemalloc(nr);
3307dd7cddfSDavid du Colombier 					runemove(tp, rp, i);
3317dd7cddfSDavid du Colombier 					up = tp+i;
3327dd7cddfSDavid du Colombier 					for(; i<nr; i++){
3337dd7cddfSDavid du Colombier 						*up = *bp++;
3347dd7cddfSDavid du Colombier 						if(*up == '\b')
3357dd7cddfSDavid du Colombier 							if(up == tp)
3367dd7cddfSDavid du Colombier 								initial++;
3377dd7cddfSDavid du Colombier 							else
3387dd7cddfSDavid du Colombier 								--up;
3397dd7cddfSDavid du Colombier 						else
3407dd7cddfSDavid du Colombier 							up++;
3417dd7cddfSDavid du Colombier 					}
3427dd7cddfSDavid du Colombier 					if(initial){
3437dd7cddfSDavid du Colombier 						if(initial > w->qh)
3447dd7cddfSDavid du Colombier 							initial = w->qh;
3457dd7cddfSDavid du Colombier 						qh = w->qh-initial;
3467dd7cddfSDavid du Colombier 						wdelete(w, qh, qh+initial);
3477dd7cddfSDavid du Colombier 						w->qh = qh;
3487dd7cddfSDavid du Colombier 					}
3497dd7cddfSDavid du Colombier 					free(rp);
3507dd7cddfSDavid du Colombier 					rp = tp;
3517dd7cddfSDavid du Colombier 					nr = up-tp;
3527dd7cddfSDavid du Colombier 					rp[nr] = 0;
3537dd7cddfSDavid du Colombier 					break;
3547dd7cddfSDavid du Colombier 				}
3557dd7cddfSDavid du Colombier 			w->qh = winsert(w, rp, nr, w->qh)+nr;
3567dd7cddfSDavid du Colombier 			if(w->scrolling || w->mouseopen)
3577dd7cddfSDavid du Colombier 				wshow(w, w->qh);
3587dd7cddfSDavid du Colombier 			wsetselect(w, w->q0, w->q1);
3597dd7cddfSDavid du Colombier 			wscrdraw(w);
3607dd7cddfSDavid du Colombier 			free(rp);
3617dd7cddfSDavid du Colombier 			break;
3627dd7cddfSDavid du Colombier 		case WCread:
3637dd7cddfSDavid du Colombier 			recv(crm.c1, &pair);
3647dd7cddfSDavid du Colombier 			t = pair.s;
3657dd7cddfSDavid du Colombier 			nb = pair.ns;
3667dd7cddfSDavid du Colombier 			i = npart;
3677dd7cddfSDavid du Colombier 			npart = 0;
3687dd7cddfSDavid du Colombier 			if(i)
3697dd7cddfSDavid du Colombier 				memmove(t, part, i);
3707dd7cddfSDavid du Colombier 			while(i<nb && (w->qh<w->nr || w->nraw>0)){
3717dd7cddfSDavid du Colombier 				if(w->qh == w->nr){
3727dd7cddfSDavid du Colombier 					wid = runetochar(t+i, &w->raw[0]);
3737dd7cddfSDavid du Colombier 					w->nraw--;
3747dd7cddfSDavid du Colombier 					runemove(w->raw, w->raw+1, w->nraw);
3757dd7cddfSDavid du Colombier 				}else
3767dd7cddfSDavid du Colombier 					wid = runetochar(t+i, &w->r[w->qh++]);
3777dd7cddfSDavid du Colombier 				c = t[i];	/* knows break characters fit in a byte */
3787dd7cddfSDavid du Colombier 				i += wid;
3797dd7cddfSDavid du Colombier 				if(!w->rawing && (c == '\n' || c=='\004')){
3807dd7cddfSDavid du Colombier 					if(c == '\004')
3817dd7cddfSDavid du Colombier 						i--;
3827dd7cddfSDavid du Colombier 					break;
3837dd7cddfSDavid du Colombier 				}
3847dd7cddfSDavid du Colombier 			}
3857dd7cddfSDavid du Colombier 			if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')
3867dd7cddfSDavid du Colombier 				w->qh++;
3877dd7cddfSDavid du Colombier 			if(i > nb){
3887dd7cddfSDavid du Colombier 				npart = i-nb;
3897dd7cddfSDavid du Colombier 				memmove(part, t+nb, npart);
3907dd7cddfSDavid du Colombier 				i = nb;
3917dd7cddfSDavid du Colombier 			}
3927dd7cddfSDavid du Colombier 			pair.s = t;
3937dd7cddfSDavid du Colombier 			pair.ns = i;
3947dd7cddfSDavid du Colombier 			send(crm.c2, &pair);
3957dd7cddfSDavid du Colombier 			continue;
39659cc4ca5SDavid du Colombier 		case WWread:
39759cc4ca5SDavid du Colombier 			w->wctlready = 0;
39859cc4ca5SDavid du Colombier 			recv(cwrm.c1, &pair);
39959cc4ca5SDavid du Colombier 			if(w->deleted || w->i==nil)
40059cc4ca5SDavid du Colombier 				pair.ns = sprint(pair.s, "");
40159cc4ca5SDavid du Colombier 			else{
40280ee5cbfSDavid du Colombier 				s = "visible";
40380ee5cbfSDavid du Colombier 				for(i=0; i<nhidden; i++)
40480ee5cbfSDavid du Colombier 					if(hidden[i] == w){
40580ee5cbfSDavid du Colombier 						s = "hidden";
40680ee5cbfSDavid du Colombier 						break;
40780ee5cbfSDavid du Colombier 					}
40880ee5cbfSDavid du Colombier 				t = "notcurrent";
40980ee5cbfSDavid du Colombier 				if(w == input)
41080ee5cbfSDavid du Colombier 					t = "current";
41180ee5cbfSDavid du Colombier 				pair.ns = snprint(pair.s, pair.ns, "%11d %11d %11d %11d %s %s ",
41280ee5cbfSDavid du Colombier 					w->i->r.min.x, w->i->r.min.y, w->i->r.max.x, w->i->r.max.y, t, s);
41359cc4ca5SDavid du Colombier 			}
41459cc4ca5SDavid du Colombier 			send(cwrm.c2, &pair);
41559cc4ca5SDavid du Colombier 			continue;
4167dd7cddfSDavid du Colombier 		}
4177dd7cddfSDavid du Colombier 		if(!w->deleted)
4187dd7cddfSDavid du Colombier 			flushimage(display, 1);
4197dd7cddfSDavid du Colombier 	}
4207dd7cddfSDavid du Colombier }
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier void
4237dd7cddfSDavid du Colombier waddraw(Window *w, Rune *r, int nr)
4247dd7cddfSDavid du Colombier {
4257dd7cddfSDavid du Colombier 	w->raw = runerealloc(w->raw, w->nraw+nr);
4267dd7cddfSDavid du Colombier 	runemove(w->raw+w->nraw, r, nr);
4277dd7cddfSDavid du Colombier 	w->nraw += nr;
4287dd7cddfSDavid du Colombier }
4297dd7cddfSDavid du Colombier 
43059cc4ca5SDavid du Colombier /*
43159cc4ca5SDavid du Colombier  * Need to do this in a separate proc because if process we're interrupting
43259cc4ca5SDavid du Colombier  * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
43359cc4ca5SDavid du Colombier  */
43459cc4ca5SDavid du Colombier void
43559cc4ca5SDavid du Colombier interruptproc(void *v)
43659cc4ca5SDavid du Colombier {
43759cc4ca5SDavid du Colombier 	int *notefd;
43859cc4ca5SDavid du Colombier 
43959cc4ca5SDavid du Colombier 	notefd = v;
44059cc4ca5SDavid du Colombier 	write(*notefd, "interrupt", 9);
44159cc4ca5SDavid du Colombier 	free(notefd);
44259cc4ca5SDavid du Colombier }
44359cc4ca5SDavid du Colombier 
4447dd7cddfSDavid du Colombier void
4457dd7cddfSDavid du Colombier wkeyctl(Window *w, Rune r)
4467dd7cddfSDavid du Colombier {
4477dd7cddfSDavid du Colombier 	uint q0 ,q1;
4487dd7cddfSDavid du Colombier 	int nb;
44959cc4ca5SDavid du Colombier 	int *notefd;
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	if(r == 0)
4527dd7cddfSDavid du Colombier 		return;
4537dd7cddfSDavid du Colombier 	if(w->deleted)
4547dd7cddfSDavid du Colombier 		return;
4557dd7cddfSDavid du Colombier 	/* silly old compatibility: any of the three ←↓→ arrow keys go down */
4567dd7cddfSDavid du Colombier 	if(!w->mouseopen && (r==Kdown || r==Kleft || r==Kright)){
4577dd7cddfSDavid du Colombier 		q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+(w->maxlines/2)*w->font->height));
4587dd7cddfSDavid du Colombier 		wsetorigin(w, q0, TRUE);
4597dd7cddfSDavid du Colombier 		return;
4607dd7cddfSDavid du Colombier 	}
4617dd7cddfSDavid du Colombier 	if(r==Kup && !w->mouseopen){
4627dd7cddfSDavid du Colombier 		q0 = wbacknl(w, w->org, w->maxlines/2);
4637dd7cddfSDavid du Colombier 		wsetorigin(w, q0, TRUE);
4647dd7cddfSDavid du Colombier 		return;
4657dd7cddfSDavid du Colombier 	}
4667dd7cddfSDavid du Colombier 	if(w->rawing && (w->q0==w->nr || w->mouseopen)){
4677dd7cddfSDavid du Colombier 		waddraw(w, &r, 1);
4687dd7cddfSDavid du Colombier 		return;
4697dd7cddfSDavid du Colombier 	}
4707dd7cddfSDavid du Colombier 	if(r==0x1B || (w->holding && r==0x7F)){	/* toggle hold */
4717dd7cddfSDavid du Colombier 		if(w->holding)
4727dd7cddfSDavid du Colombier 			--w->holding;
4737dd7cddfSDavid du Colombier 		else
4747dd7cddfSDavid du Colombier 			w->holding++;
4757dd7cddfSDavid du Colombier 		wrepaint(w);
4767dd7cddfSDavid du Colombier 		if(r == 0x1B)
4777dd7cddfSDavid du Colombier 			return;
4787dd7cddfSDavid du Colombier 	}
4797dd7cddfSDavid du Colombier 	if(r != 0x7F){
4807dd7cddfSDavid du Colombier 		wsnarf(w);
4817dd7cddfSDavid du Colombier 		wcut(w);
4827dd7cddfSDavid du Colombier 	}
4837dd7cddfSDavid du Colombier 	switch(r){
4847dd7cddfSDavid du Colombier 	case 0x7F:		/* send interrupt */
4857dd7cddfSDavid du Colombier 		w->qh = w->nr;
4867dd7cddfSDavid du Colombier 		wshow(w, w->qh);
48759cc4ca5SDavid du Colombier 		notefd = emalloc(sizeof(int));
48859cc4ca5SDavid du Colombier 		*notefd = w->notefd;
48959cc4ca5SDavid du Colombier 		proccreate(interruptproc, notefd, 4096);
4907dd7cddfSDavid du Colombier 		return;
4917dd7cddfSDavid du Colombier 	case 0x08:	/* ^H: erase character */
4927dd7cddfSDavid du Colombier 	case 0x15:	/* ^U: erase line */
4937dd7cddfSDavid du Colombier 	case 0x17:	/* ^W: erase word */
4947dd7cddfSDavid du Colombier 		if(w->q0==0 || w->q0==w->qh)
4957dd7cddfSDavid du Colombier 			return;
4967dd7cddfSDavid du Colombier 		nb = wbswidth(w, r);
4977dd7cddfSDavid du Colombier 		q1 = w->q0;
4987dd7cddfSDavid du Colombier 		q0 = q1-nb;
49980ee5cbfSDavid du Colombier 		if(q0 < w->org){
50080ee5cbfSDavid du Colombier 			q0 = w->org;
50180ee5cbfSDavid du Colombier 			nb = q1-q0;
50280ee5cbfSDavid du Colombier 		}
50380ee5cbfSDavid du Colombier 		if(nb > 0){
5047dd7cddfSDavid du Colombier 			wdelete(w, q0, q0+nb);
5057dd7cddfSDavid du Colombier 			wsetselect(w, q0, q0);
50680ee5cbfSDavid du Colombier 	}
5077dd7cddfSDavid du Colombier 		return;
5087dd7cddfSDavid du Colombier 	}
5097dd7cddfSDavid du Colombier 	/* otherwise ordinary character; just insert */
5107dd7cddfSDavid du Colombier 	q0 = w->q0;
5117dd7cddfSDavid du Colombier 	q0 = winsert(w, &r, 1, q0);
5127dd7cddfSDavid du Colombier 	wshow(w, q0+1);
5137dd7cddfSDavid du Colombier }
5147dd7cddfSDavid du Colombier 
5157dd7cddfSDavid du Colombier void
5167dd7cddfSDavid du Colombier wsetcols(Window *w)
5177dd7cddfSDavid du Colombier {
5187dd7cddfSDavid du Colombier 	if(w->holding)
5197dd7cddfSDavid du Colombier 		if(w == input)
5207dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = holdcol;
5217dd7cddfSDavid du Colombier 		else
5227dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = lightholdcol;
5237dd7cddfSDavid du Colombier 	else
5247dd7cddfSDavid du Colombier 		if(w == input)
5257dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = display->black;
5267dd7cddfSDavid du Colombier 		else
5277dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = darkgrey;
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier 
5307dd7cddfSDavid du Colombier void
5317dd7cddfSDavid du Colombier wrepaint(Window *w)
5327dd7cddfSDavid du Colombier {
5337dd7cddfSDavid du Colombier 	wsetcols(w);
5347dd7cddfSDavid du Colombier 	if(!w->mouseopen)
5357dd7cddfSDavid du Colombier 		_frredraw(w, w->Frame.r.min);
5367dd7cddfSDavid du Colombier 	if(w == input){
5377dd7cddfSDavid du Colombier 		wborder(w, Selborder);
5387dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
5397dd7cddfSDavid du Colombier 	}else
5407dd7cddfSDavid du Colombier 		wborder(w, Unselborder);
5417dd7cddfSDavid du Colombier }
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier int
5447dd7cddfSDavid du Colombier wbswidth(Window *w, Rune c)
5457dd7cddfSDavid du Colombier {
5467dd7cddfSDavid du Colombier 	uint q, eq, stop;
5477dd7cddfSDavid du Colombier 	Rune r;
5487dd7cddfSDavid du Colombier 	int skipping;
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier 	/* there is known to be at least one character to erase */
5517dd7cddfSDavid du Colombier 	if(c == 0x08)	/* ^H: erase character */
5527dd7cddfSDavid du Colombier 		return 1;
5537dd7cddfSDavid du Colombier 	q = w->q0;
5547dd7cddfSDavid du Colombier 	stop = 0;
5557dd7cddfSDavid du Colombier 	if(q > w->qh)
5567dd7cddfSDavid du Colombier 		stop = w->qh;
5577dd7cddfSDavid du Colombier 	skipping = TRUE;
5587dd7cddfSDavid du Colombier 	while(q > stop){
5597dd7cddfSDavid du Colombier 		r = w->r[q-1];
5607dd7cddfSDavid du Colombier 		if(r == '\n'){		/* eat at most one more character */
5617dd7cddfSDavid du Colombier 			if(q == w->q0)	/* eat the newline */
5627dd7cddfSDavid du Colombier 				--q;
5637dd7cddfSDavid du Colombier 			break;
5647dd7cddfSDavid du Colombier 		}
5657dd7cddfSDavid du Colombier 		if(c == 0x17){
5667dd7cddfSDavid du Colombier 			eq = isalnum(r);
5677dd7cddfSDavid du Colombier 			if(eq && skipping)	/* found one; stop skipping */
5687dd7cddfSDavid du Colombier 				skipping = FALSE;
5697dd7cddfSDavid du Colombier 			else if(!eq && !skipping)
5707dd7cddfSDavid du Colombier 				break;
5717dd7cddfSDavid du Colombier 		}
5727dd7cddfSDavid du Colombier 		--q;
5737dd7cddfSDavid du Colombier 	}
5747dd7cddfSDavid du Colombier 	return w->q0-q;
5757dd7cddfSDavid du Colombier }
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier void
5787dd7cddfSDavid du Colombier wsnarf(Window *w)
5797dd7cddfSDavid du Colombier {
5807dd7cddfSDavid du Colombier 	if(w->q1 == w->q0)
5817dd7cddfSDavid du Colombier 		return;
5827dd7cddfSDavid du Colombier 	nsnarf = w->q1-w->q0;
5837dd7cddfSDavid du Colombier 	snarf = runerealloc(snarf, nsnarf);
58480ee5cbfSDavid du Colombier 	snarfversion++;	/* maybe modified by parent */
5857dd7cddfSDavid du Colombier 	runemove(snarf, w->r+w->q0, nsnarf);
5867dd7cddfSDavid du Colombier 	putsnarf();
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier void
5907dd7cddfSDavid du Colombier wcut(Window *w)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier 	if(w->q1 == w->q0)
5937dd7cddfSDavid du Colombier 		return;
5947dd7cddfSDavid du Colombier 	wdelete(w, w->q0, w->q1);
59580ee5cbfSDavid du Colombier 	wsetselect(w, w->q0, w->q0);
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier void
5997dd7cddfSDavid du Colombier wpaste(Window *w)
6007dd7cddfSDavid du Colombier {
6017dd7cddfSDavid du Colombier 	uint q0;
6027dd7cddfSDavid du Colombier 
6037dd7cddfSDavid du Colombier 	if(nsnarf == 0)
6047dd7cddfSDavid du Colombier 		return;
6057dd7cddfSDavid du Colombier 	wcut(w);
6067dd7cddfSDavid du Colombier 	q0 = w->q0;
6077dd7cddfSDavid du Colombier 	if(w->rawing && q0==w->nr){
6087dd7cddfSDavid du Colombier 		waddraw(w, snarf, nsnarf);
6097dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0);
6107dd7cddfSDavid du Colombier 	}else{
611*6ff5e913SDavid du Colombier 		q0 = winsert(w, snarf, nsnarf, w->q0);
6127dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0+nsnarf);
6137dd7cddfSDavid du Colombier 	}
6147dd7cddfSDavid du Colombier }
6157dd7cddfSDavid du Colombier 
6167dd7cddfSDavid du Colombier void
6177dd7cddfSDavid du Colombier wplumb(Window *w)
6187dd7cddfSDavid du Colombier {
6197dd7cddfSDavid du Colombier 	Plumbmsg *m;
6207dd7cddfSDavid du Colombier 	static int fd = -2;
6217dd7cddfSDavid du Colombier 	char buf[32];
6227dd7cddfSDavid du Colombier 	uint p0, p1;
6237dd7cddfSDavid du Colombier 	Cursor *c;
6247dd7cddfSDavid du Colombier 
6257dd7cddfSDavid du Colombier 	if(fd == -2)
6267dd7cddfSDavid du Colombier 		fd = plumbopen("send", OWRITE|OCEXEC);
6277dd7cddfSDavid du Colombier 	if(fd < 0)
6287dd7cddfSDavid du Colombier 		return;
6297dd7cddfSDavid du Colombier 	m = emalloc(sizeof(Plumbmsg));
6307dd7cddfSDavid du Colombier 	m->src = estrdup("rio");
6317dd7cddfSDavid du Colombier 	m->dst = nil;
6327dd7cddfSDavid du Colombier 	m->wdir = estrdup(w->dir);
63359cc4ca5SDavid du Colombier 	m->type = estrdup("text");
6347dd7cddfSDavid du Colombier 	p0 = w->q0;
6357dd7cddfSDavid du Colombier 	p1 = w->q1;
6367dd7cddfSDavid du Colombier 	if(w->q1 > w->q0)
6377dd7cddfSDavid du Colombier 		m->attr = nil;
6387dd7cddfSDavid du Colombier 	else{
6397dd7cddfSDavid du Colombier 		while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
6407dd7cddfSDavid du Colombier 			p0--;
6417dd7cddfSDavid du Colombier 		while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
6427dd7cddfSDavid du Colombier 			p1++;
6437dd7cddfSDavid du Colombier 		sprint(buf, "click=%d", w->q0-p0);
6447dd7cddfSDavid du Colombier 		m->attr = plumbunpackattr(buf);
6457dd7cddfSDavid du Colombier 	}
6469a747e4fSDavid du Colombier 	if(p1-p0 > messagesize-1024){
6477dd7cddfSDavid du Colombier 		plumbfree(m);
6489a747e4fSDavid du Colombier 		return;	/* too large for 9P */
6497dd7cddfSDavid du Colombier 	}
6507dd7cddfSDavid du Colombier 	m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
6517dd7cddfSDavid du Colombier 	if(plumbsend(fd, m) < 0){
6527dd7cddfSDavid du Colombier 		c = lastcursor;
6537dd7cddfSDavid du Colombier 		riosetcursor(&query, 1);
6547dd7cddfSDavid du Colombier 		sleep(300);
6557dd7cddfSDavid du Colombier 		riosetcursor(c, 1);
6567dd7cddfSDavid du Colombier 	}
6577dd7cddfSDavid du Colombier 	plumbfree(m);
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier int
6617dd7cddfSDavid du Colombier winborder(Window *w, Point xy)
6627dd7cddfSDavid du Colombier {
6637dd7cddfSDavid du Colombier 	return ptinrect(xy, w->screenr) && !ptinrect(xy, insetrect(w->screenr, Selborder));
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier 
6667dd7cddfSDavid du Colombier void
6677dd7cddfSDavid du Colombier wmousectl(Window *w)
6687dd7cddfSDavid du Colombier {
6697dd7cddfSDavid du Colombier 	int but;
6707dd7cddfSDavid du Colombier 
6717dd7cddfSDavid du Colombier 	if(w->mc.buttons == 1)
6727dd7cddfSDavid du Colombier 		but = 1;
6737dd7cddfSDavid du Colombier 	else if(w->mc.buttons == 2)
6747dd7cddfSDavid du Colombier 		but = 2;
6757dd7cddfSDavid du Colombier 	else if(w->mc.buttons == 4)
6767dd7cddfSDavid du Colombier 		but = 3;
6777dd7cddfSDavid du Colombier 	else
6787dd7cddfSDavid du Colombier 		return;
6797dd7cddfSDavid du Colombier 	incref(w);		/* hold up window while we track */
6807dd7cddfSDavid du Colombier 	if(w->deleted)
6817dd7cddfSDavid du Colombier 		goto Return;
6827dd7cddfSDavid du Colombier 	if(ptinrect(w->mc.xy, w->scrollr)){
6837dd7cddfSDavid du Colombier 		if(but)
6847dd7cddfSDavid du Colombier 			wscroll(w, but);
6857dd7cddfSDavid du Colombier 		goto Return;
6867dd7cddfSDavid du Colombier 	}
6877dd7cddfSDavid du Colombier 	if(but == 1)
6887dd7cddfSDavid du Colombier 		wselect(w);
6897dd7cddfSDavid du Colombier 	/* else all is handled by main process */
6907dd7cddfSDavid du Colombier    Return:
6917dd7cddfSDavid du Colombier 	wclose(w);
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier 
6947dd7cddfSDavid du Colombier void
6957dd7cddfSDavid du Colombier wdelete(Window *w, uint q0, uint q1)
6967dd7cddfSDavid du Colombier {
6977dd7cddfSDavid du Colombier 	uint n, p0, p1;
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier 	n = q1-q0;
7007dd7cddfSDavid du Colombier 	if(n == 0)
7017dd7cddfSDavid du Colombier 		return;
7027dd7cddfSDavid du Colombier 	runemove(w->r+q0, w->r+q1, w->nr-q1);
7037dd7cddfSDavid du Colombier 	w->nr -= n;
7047dd7cddfSDavid du Colombier 	if(q0 < w->q0)
7057dd7cddfSDavid du Colombier 		w->q0 -= min(n, w->q0-q0);
7067dd7cddfSDavid du Colombier 	if(q0 < w->q1)
7077dd7cddfSDavid du Colombier 		w->q1 -= min(n, w->q1-q0);
7087dd7cddfSDavid du Colombier 	if(q1 < w->qh)
7097dd7cddfSDavid du Colombier 		w->qh -= n;
7107dd7cddfSDavid du Colombier 	else if(q0 < w->qh)
7117dd7cddfSDavid du Colombier 		w->qh = q0;
7127dd7cddfSDavid du Colombier 	if(q1 <= w->org)
7137dd7cddfSDavid du Colombier 		w->org -= n;
7147dd7cddfSDavid du Colombier 	else if(q0 < w->org+w->nchars){
7157dd7cddfSDavid du Colombier 		p1 = q1 - w->org;
7167dd7cddfSDavid du Colombier 		if(p1 > w->nchars)
7177dd7cddfSDavid du Colombier 			p1 = w->nchars;
7187dd7cddfSDavid du Colombier 		if(q0 < w->org){
7197dd7cddfSDavid du Colombier 			w->org = q0;
7207dd7cddfSDavid du Colombier 			p0 = 0;
7217dd7cddfSDavid du Colombier 		}else
7227dd7cddfSDavid du Colombier 			p0 = q0 - w->org;
7237dd7cddfSDavid du Colombier 		frdelete(w, p0, p1);
7247dd7cddfSDavid du Colombier 		wfill(w);
7257dd7cddfSDavid du Colombier 	}
7267dd7cddfSDavid du Colombier }
7277dd7cddfSDavid du Colombier 
7287dd7cddfSDavid du Colombier 
7297dd7cddfSDavid du Colombier static Window	*clickwin;
7307dd7cddfSDavid du Colombier static uint	clickmsec;
7317dd7cddfSDavid du Colombier static Window	*selectwin;
7327dd7cddfSDavid du Colombier static uint	selectq;
7337dd7cddfSDavid du Colombier 
7347dd7cddfSDavid du Colombier /*
7357dd7cddfSDavid du Colombier  * called from frame library
7367dd7cddfSDavid du Colombier  */
7377dd7cddfSDavid du Colombier void
7387dd7cddfSDavid du Colombier framescroll(Frame *f, int dl)
7397dd7cddfSDavid du Colombier {
7407dd7cddfSDavid du Colombier 	if(f != &selectwin->Frame)
7417dd7cddfSDavid du Colombier 		error("frameselect not right frame");
7427dd7cddfSDavid du Colombier 	wframescroll(selectwin, dl);
7437dd7cddfSDavid du Colombier }
7447dd7cddfSDavid du Colombier 
7457dd7cddfSDavid du Colombier void
7467dd7cddfSDavid du Colombier wframescroll(Window *w, int dl)
7477dd7cddfSDavid du Colombier {
7487dd7cddfSDavid du Colombier 	uint q0;
7497dd7cddfSDavid du Colombier 
7507dd7cddfSDavid du Colombier 	if(dl == 0){
7517dd7cddfSDavid du Colombier 		wscrsleep(w, 100);
7527dd7cddfSDavid du Colombier 		return;
7537dd7cddfSDavid du Colombier 	}
7547dd7cddfSDavid du Colombier 	if(dl < 0){
7557dd7cddfSDavid du Colombier 		q0 = wbacknl(w, w->org, -dl);
7567dd7cddfSDavid du Colombier 		if(selectq > w->org+w->p0)
7577dd7cddfSDavid du Colombier 			wsetselect(w, w->org+w->p0, selectq);
7587dd7cddfSDavid du Colombier 		else
7597dd7cddfSDavid du Colombier 			wsetselect(w, selectq, w->org+w->p0);
7607dd7cddfSDavid du Colombier 	}else{
7617dd7cddfSDavid du Colombier 		if(w->org+w->nchars == w->nr)
7627dd7cddfSDavid du Colombier 			return;
7637dd7cddfSDavid du Colombier 		q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
7647dd7cddfSDavid du Colombier 		if(selectq >= w->org+w->p1)
7657dd7cddfSDavid du Colombier 			wsetselect(w, w->org+w->p1, selectq);
7667dd7cddfSDavid du Colombier 		else
7677dd7cddfSDavid du Colombier 			wsetselect(w, selectq, w->org+w->p1);
7687dd7cddfSDavid du Colombier 	}
7697dd7cddfSDavid du Colombier 	wsetorigin(w, q0, TRUE);
7707dd7cddfSDavid du Colombier }
7717dd7cddfSDavid du Colombier 
7727dd7cddfSDavid du Colombier void
7737dd7cddfSDavid du Colombier wselect(Window *w)
7747dd7cddfSDavid du Colombier {
7757dd7cddfSDavid du Colombier 	uint q0, q1;
7767dd7cddfSDavid du Colombier 	int b, x, y, first;
7777dd7cddfSDavid du Colombier 
7787dd7cddfSDavid du Colombier 	first = 1;
7797dd7cddfSDavid du Colombier 	selectwin = w;
7807dd7cddfSDavid du Colombier 	/*
7817dd7cddfSDavid du Colombier 	 * Double-click immediately if it might make sense.
7827dd7cddfSDavid du Colombier 	 */
7837dd7cddfSDavid du Colombier 	b = w->mc.buttons;
7847dd7cddfSDavid du Colombier 	q0 = w->q0;
7857dd7cddfSDavid du Colombier 	q1 = w->q1;
7867dd7cddfSDavid du Colombier 	selectq = w->org+frcharofpt(w, w->mc.xy);
7877dd7cddfSDavid du Colombier 	if(clickwin==w && w->mc.msec-clickmsec<500)
7887dd7cddfSDavid du Colombier 	if(q0==q1 && selectq==w->q0){
7897dd7cddfSDavid du Colombier 		wdoubleclick(w, &q0, &q1);
7907dd7cddfSDavid du Colombier 		wsetselect(w, q0, q1);
7917dd7cddfSDavid du Colombier 		flushimage(display, 1);
7927dd7cddfSDavid du Colombier 		x = w->mc.xy.x;
7937dd7cddfSDavid du Colombier 		y = w->mc.xy.y;
7947dd7cddfSDavid du Colombier 		/* stay here until something interesting happens */
7957dd7cddfSDavid du Colombier 		do
7967dd7cddfSDavid du Colombier 			readmouse(&w->mc);
7977dd7cddfSDavid du Colombier 		while(w->mc.buttons==b && abs(w->mc.xy.x-x)<3 && abs(w->mc.xy.y-y)<3);
7987dd7cddfSDavid du Colombier 		w->mc.xy.x = x;	/* in case we're calling frselect */
7997dd7cddfSDavid du Colombier 		w->mc.xy.y = y;
8007dd7cddfSDavid du Colombier 		q0 = w->q0;	/* may have changed */
8017dd7cddfSDavid du Colombier 		q1 = w->q1;
8027dd7cddfSDavid du Colombier 		selectq = q0;
8037dd7cddfSDavid du Colombier 	}
8047dd7cddfSDavid du Colombier 	if(w->mc.buttons == b){
8057dd7cddfSDavid du Colombier 		w->scroll = framescroll;
8067dd7cddfSDavid du Colombier 		frselect(w, &w->mc);
8077dd7cddfSDavid du Colombier 		/* horrible botch: while asleep, may have lost selection altogether */
8087dd7cddfSDavid du Colombier 		if(selectq > w->nr)
8097dd7cddfSDavid du Colombier 			selectq = w->org + w->p0;
8107dd7cddfSDavid du Colombier 		w->Frame.scroll = nil;
8117dd7cddfSDavid du Colombier 		if(selectq < w->org)
8127dd7cddfSDavid du Colombier 			q0 = selectq;
8137dd7cddfSDavid du Colombier 		else
8147dd7cddfSDavid du Colombier 			q0 = w->org + w->p0;
8157dd7cddfSDavid du Colombier 		if(selectq > w->org+w->nchars)
8167dd7cddfSDavid du Colombier 			q1 = selectq;
8177dd7cddfSDavid du Colombier 		else
8187dd7cddfSDavid du Colombier 			q1 = w->org+w->p1;
8197dd7cddfSDavid du Colombier 	}
8207dd7cddfSDavid du Colombier 	if(q0 == q1){
8217dd7cddfSDavid du Colombier 		if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500){
8227dd7cddfSDavid du Colombier 			wdoubleclick(w, &q0, &q1);
8237dd7cddfSDavid du Colombier 			clickwin = nil;
8247dd7cddfSDavid du Colombier 		}else{
8257dd7cddfSDavid du Colombier 			clickwin = w;
8267dd7cddfSDavid du Colombier 			clickmsec = w->mc.msec;
8277dd7cddfSDavid du Colombier 		}
8287dd7cddfSDavid du Colombier 	}else
8297dd7cddfSDavid du Colombier 		clickwin = nil;
8307dd7cddfSDavid du Colombier 	wsetselect(w, q0, q1);
8317dd7cddfSDavid du Colombier 	flushimage(display, 1);
8327dd7cddfSDavid du Colombier 	while(w->mc.buttons){
8337dd7cddfSDavid du Colombier 		w->mc.msec = 0;
8347dd7cddfSDavid du Colombier 		b = w->mc.buttons;
8357dd7cddfSDavid du Colombier 		if(b & 6){
8367dd7cddfSDavid du Colombier 			if(b & 2){
8377dd7cddfSDavid du Colombier 				wsnarf(w);
8387dd7cddfSDavid du Colombier 				wcut(w);
8397dd7cddfSDavid du Colombier 			}else{
8407dd7cddfSDavid du Colombier 				if(first){
8417dd7cddfSDavid du Colombier 					first = 0;
8427dd7cddfSDavid du Colombier 					getsnarf();
8437dd7cddfSDavid du Colombier 				}
8447dd7cddfSDavid du Colombier 				wpaste(w);
8457dd7cddfSDavid du Colombier 			}
8467dd7cddfSDavid du Colombier 		}
8477dd7cddfSDavid du Colombier 		wscrdraw(w);
8487dd7cddfSDavid du Colombier 		flushimage(display, 1);
8497dd7cddfSDavid du Colombier 		while(w->mc.buttons == b)
8507dd7cddfSDavid du Colombier 			readmouse(&w->mc);
8517dd7cddfSDavid du Colombier 		clickwin = nil;
8527dd7cddfSDavid du Colombier 	}
8537dd7cddfSDavid du Colombier }
8547dd7cddfSDavid du Colombier 
8557dd7cddfSDavid du Colombier void
8567dd7cddfSDavid du Colombier wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
8577dd7cddfSDavid du Colombier {
8587dd7cddfSDavid du Colombier 	Wctlmesg wcm;
8597dd7cddfSDavid du Colombier 
8607dd7cddfSDavid du Colombier 	wcm.type = type;
8617dd7cddfSDavid du Colombier 	wcm.r = r;
8627dd7cddfSDavid du Colombier 	wcm.image = image;
8637dd7cddfSDavid du Colombier 	send(w->cctl, &wcm);
8647dd7cddfSDavid du Colombier }
8657dd7cddfSDavid du Colombier 
8667dd7cddfSDavid du Colombier int
8677dd7cddfSDavid du Colombier wctlmesg(Window *w, int m, Rectangle r, Image *i)
8687dd7cddfSDavid du Colombier {
8697dd7cddfSDavid du Colombier 	char buf[64];
8707dd7cddfSDavid du Colombier 
8717dd7cddfSDavid du Colombier 	switch(m){
8727dd7cddfSDavid du Colombier 	default:
8737dd7cddfSDavid du Colombier 		error("unknown control message");
8747dd7cddfSDavid du Colombier 		break;
8757dd7cddfSDavid du Colombier 	case Wakeup:
8767dd7cddfSDavid du Colombier 		break;
8777dd7cddfSDavid du Colombier 	case Moved:
8787dd7cddfSDavid du Colombier 	case Reshaped:
8797dd7cddfSDavid du Colombier 		if(w->deleted){
8807dd7cddfSDavid du Colombier 			freeimage(i);
8817dd7cddfSDavid du Colombier 			break;
8827dd7cddfSDavid du Colombier 		}
8837dd7cddfSDavid du Colombier 		w->screenr = r;
8847dd7cddfSDavid du Colombier 		strcpy(buf, w->name);
8857dd7cddfSDavid du Colombier 		wresize(w, i, m==Moved);
8869a747e4fSDavid du Colombier 		w->wctlready = 1;
8879a747e4fSDavid du Colombier 		proccreate(deletetimeoutproc, estrdup(buf), 4096);
8887dd7cddfSDavid du Colombier 		if(Dx(r) > 0){
8897dd7cddfSDavid du Colombier 			if(w != input)
8907dd7cddfSDavid du Colombier 				wcurrent(w);
8917dd7cddfSDavid du Colombier 		}else if(w == input)
8927dd7cddfSDavid du Colombier 			wcurrent(nil);
8937dd7cddfSDavid du Colombier 		flushimage(display, 1);
8947dd7cddfSDavid du Colombier 		break;
8957dd7cddfSDavid du Colombier 	case Refresh:
8967dd7cddfSDavid du Colombier 		if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r))
8977dd7cddfSDavid du Colombier 			break;
8987dd7cddfSDavid du Colombier 		if(!w->mouseopen)
8997dd7cddfSDavid du Colombier 			wrefresh(w, r);
9007dd7cddfSDavid du Colombier 		flushimage(display, 1);
9017dd7cddfSDavid du Colombier 		break;
9027dd7cddfSDavid du Colombier 	case Movemouse:
9037dd7cddfSDavid du Colombier 		if(sweeping || !ptinrect(r.min, w->i->r))
9047dd7cddfSDavid du Colombier 			break;
9057dd7cddfSDavid du Colombier 		wmovemouse(w, r.min);
9067dd7cddfSDavid du Colombier 	case Rawon:
9077dd7cddfSDavid du Colombier 		break;
9087dd7cddfSDavid du Colombier 	case Rawoff:
9097dd7cddfSDavid du Colombier 		if(w->deleted)
9107dd7cddfSDavid du Colombier 			break;
9117dd7cddfSDavid du Colombier 		while(w->nraw > 0){
9127dd7cddfSDavid du Colombier 			wkeyctl(w, w->raw[0]);
9137dd7cddfSDavid du Colombier 			--w->nraw;
9147dd7cddfSDavid du Colombier 			runemove(w->raw, w->raw+1, w->nraw);
9157dd7cddfSDavid du Colombier 		}
9167dd7cddfSDavid du Colombier 		break;
9177dd7cddfSDavid du Colombier 	case Holdon:
9187dd7cddfSDavid du Colombier 	case Holdoff:
9197dd7cddfSDavid du Colombier 		if(w->deleted)
9207dd7cddfSDavid du Colombier 			break;
9217dd7cddfSDavid du Colombier 		wrepaint(w);
9227dd7cddfSDavid du Colombier 		flushimage(display, 1);
9237dd7cddfSDavid du Colombier 		break;
9247dd7cddfSDavid du Colombier 	case Deleted:
9257dd7cddfSDavid du Colombier 		if(w->deleted)
9267dd7cddfSDavid du Colombier 			break;
9277dd7cddfSDavid du Colombier 		write(w->notefd, "hangup", 6);
9289a747e4fSDavid du Colombier 		proccreate(deletetimeoutproc, estrdup(w->name), 4096);
9297dd7cddfSDavid du Colombier 		wclosewin(w);
9307dd7cddfSDavid du Colombier 		break;
9317dd7cddfSDavid du Colombier 	case Exited:
93259cc4ca5SDavid du Colombier 		frclear(w, TRUE);
9337dd7cddfSDavid du Colombier 		close(w->notefd);
93459cc4ca5SDavid du Colombier 		chanfree(w->mc.c);
93559cc4ca5SDavid du Colombier 		chanfree(w->ck);
93659cc4ca5SDavid du Colombier 		chanfree(w->cctl);
93759cc4ca5SDavid du Colombier 		chanfree(w->conswrite);
93859cc4ca5SDavid du Colombier 		chanfree(w->consread);
93959cc4ca5SDavid du Colombier 		chanfree(w->mouseread);
94059cc4ca5SDavid du Colombier 		chanfree(w->wctlread);
9417dd7cddfSDavid du Colombier 		free(w->raw);
9427dd7cddfSDavid du Colombier 		free(w->r);
94359cc4ca5SDavid du Colombier 		free(w->dir);
9449a747e4fSDavid du Colombier 		free(w->label);
9457dd7cddfSDavid du Colombier 		free(w);
9467dd7cddfSDavid du Colombier 		break;
9477dd7cddfSDavid du Colombier 	}
9487dd7cddfSDavid du Colombier 	return m;
9497dd7cddfSDavid du Colombier }
9507dd7cddfSDavid du Colombier 
9517dd7cddfSDavid du Colombier /*
9527dd7cddfSDavid du Colombier  * Convert back to physical coordinates
9537dd7cddfSDavid du Colombier  */
9547dd7cddfSDavid du Colombier void
9557dd7cddfSDavid du Colombier wmovemouse(Window *w, Point p)
9567dd7cddfSDavid du Colombier {
9577dd7cddfSDavid du Colombier 	p.x += w->screenr.min.x-w->i->r.min.x;
9587dd7cddfSDavid du Colombier 	p.y += w->screenr.min.y-w->i->r.min.y;
9597dd7cddfSDavid du Colombier 	moveto(mousectl, p);
9607dd7cddfSDavid du Colombier }
9617dd7cddfSDavid du Colombier 
9627dd7cddfSDavid du Colombier void
9637dd7cddfSDavid du Colombier wborder(Window *w, int type)
9647dd7cddfSDavid du Colombier {
9657dd7cddfSDavid du Colombier 	Image *col;
9667dd7cddfSDavid du Colombier 
9677dd7cddfSDavid du Colombier 	if(w->i == nil)
9687dd7cddfSDavid du Colombier 		return;
9697dd7cddfSDavid du Colombier 	if(w->holding){
9707dd7cddfSDavid du Colombier 		if(type == Selborder)
9717dd7cddfSDavid du Colombier 			col = holdcol;
9727dd7cddfSDavid du Colombier 		else
9737dd7cddfSDavid du Colombier 			col = paleholdcol;
9747dd7cddfSDavid du Colombier 	}else{
9757dd7cddfSDavid du Colombier 		if(type == Selborder)
9767dd7cddfSDavid du Colombier 			col = titlecol;
9777dd7cddfSDavid du Colombier 		else
9787dd7cddfSDavid du Colombier 			col = lighttitlecol;
9797dd7cddfSDavid du Colombier 	}
9807dd7cddfSDavid du Colombier 
9817dd7cddfSDavid du Colombier 	border(w->i, w->i->r, Selborder, col, ZP);
9827dd7cddfSDavid du Colombier }
9837dd7cddfSDavid du Colombier 
9847dd7cddfSDavid du Colombier Window*
9857dd7cddfSDavid du Colombier wpointto(Point pt)
9867dd7cddfSDavid du Colombier {
9877dd7cddfSDavid du Colombier 	int i;
9887dd7cddfSDavid du Colombier 	Window *v, *w;
9897dd7cddfSDavid du Colombier 
9907dd7cddfSDavid du Colombier 	w = nil;
9917dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++){
9927dd7cddfSDavid du Colombier 		v = window[i];
9937dd7cddfSDavid du Colombier 		if(ptinrect(pt, v->screenr))
9947dd7cddfSDavid du Colombier 		if(!v->deleted)
9957dd7cddfSDavid du Colombier 		if(w==nil || v->topped>w->topped)
9967dd7cddfSDavid du Colombier 			w = v;
9977dd7cddfSDavid du Colombier 	}
9987dd7cddfSDavid du Colombier 	return w;
9997dd7cddfSDavid du Colombier }
10007dd7cddfSDavid du Colombier 
10017dd7cddfSDavid du Colombier void
10027dd7cddfSDavid du Colombier wcurrent(Window *w)
10037dd7cddfSDavid du Colombier {
10047dd7cddfSDavid du Colombier 	Window *oi;
10057dd7cddfSDavid du Colombier 
100680ee5cbfSDavid du Colombier 	if(wkeyboard!=nil && w==wkeyboard)
100780ee5cbfSDavid du Colombier 		return;
10087dd7cddfSDavid du Colombier 	oi = input;
10097dd7cddfSDavid du Colombier 	input = w;
10107dd7cddfSDavid du Colombier 	if(oi!=w && oi!=nil)
10117dd7cddfSDavid du Colombier 		wrepaint(oi);
10127dd7cddfSDavid du Colombier 	if(w !=nil){
10137dd7cddfSDavid du Colombier 		wrepaint(w);
10147dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
10157dd7cddfSDavid du Colombier 	}
101680ee5cbfSDavid du Colombier 	if(w != oi){
101780ee5cbfSDavid du Colombier 		if(oi){
101880ee5cbfSDavid du Colombier 			oi->wctlready = 1;
101980ee5cbfSDavid du Colombier 			wsendctlmesg(oi, Wakeup, ZR, nil);
102080ee5cbfSDavid du Colombier 		}
102180ee5cbfSDavid du Colombier 		if(w){
102280ee5cbfSDavid du Colombier 			w->wctlready = 1;
102380ee5cbfSDavid du Colombier 			wsendctlmesg(w, Wakeup, ZR, nil);
102480ee5cbfSDavid du Colombier 		}
102580ee5cbfSDavid du Colombier 	}
10267dd7cddfSDavid du Colombier }
10277dd7cddfSDavid du Colombier 
10287dd7cddfSDavid du Colombier void
10297dd7cddfSDavid du Colombier wsetcursor(Window *w, int force)
10307dd7cddfSDavid du Colombier {
10317dd7cddfSDavid du Colombier 	Cursor *p;
10327dd7cddfSDavid du Colombier 
10337dd7cddfSDavid du Colombier 	if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0)
10347dd7cddfSDavid du Colombier 		p = nil;
10357dd7cddfSDavid du Colombier 	else if(wpointto(mouse->xy) == w){
10367dd7cddfSDavid du Colombier 		p = w->cursorp;
10377dd7cddfSDavid du Colombier 		if(p==nil && w->holding)
10387dd7cddfSDavid du Colombier 			p = &whitearrow;
10397dd7cddfSDavid du Colombier 	}else
10407dd7cddfSDavid du Colombier 		p = nil;
104159cc4ca5SDavid du Colombier 	if(!menuing)
104259cc4ca5SDavid du Colombier 		riosetcursor(p, force && !menuing);
10437dd7cddfSDavid du Colombier }
10447dd7cddfSDavid du Colombier 
10457dd7cddfSDavid du Colombier void
10467dd7cddfSDavid du Colombier riosetcursor(Cursor *p, int force)
10477dd7cddfSDavid du Colombier {
10487dd7cddfSDavid du Colombier 	if(!force && p==lastcursor)
10497dd7cddfSDavid du Colombier 		return;
10507dd7cddfSDavid du Colombier 	setcursor(mousectl, p);
10517dd7cddfSDavid du Colombier 	lastcursor = p;
10527dd7cddfSDavid du Colombier }
10537dd7cddfSDavid du Colombier 
10547dd7cddfSDavid du Colombier Window*
10557dd7cddfSDavid du Colombier wtop(Point pt)
10567dd7cddfSDavid du Colombier {
10577dd7cddfSDavid du Colombier 	Window *w;
10587dd7cddfSDavid du Colombier 
10597dd7cddfSDavid du Colombier 	w = wpointto(pt);
10607dd7cddfSDavid du Colombier 	if(w){
106180ee5cbfSDavid du Colombier 		if(w->topped == topped)
106280ee5cbfSDavid du Colombier 			return nil;
10637dd7cddfSDavid du Colombier 		topwindow(w->i);
10647dd7cddfSDavid du Colombier 		wcurrent(w);
10657dd7cddfSDavid du Colombier 		flushimage(display, 1);
10667dd7cddfSDavid du Colombier 		w->topped = ++topped;
10677dd7cddfSDavid du Colombier 	}
10687dd7cddfSDavid du Colombier 	return w;
10697dd7cddfSDavid du Colombier }
10707dd7cddfSDavid du Colombier 
10717dd7cddfSDavid du Colombier void
10727dd7cddfSDavid du Colombier wtopme(Window *w)
10737dd7cddfSDavid du Colombier {
107480ee5cbfSDavid du Colombier 	if(w!=nil && w->i!=nil && !w->deleted && w->topped!=topped){
10757dd7cddfSDavid du Colombier 		topwindow(w->i);
10767dd7cddfSDavid du Colombier 		flushimage(display, 1);
10777dd7cddfSDavid du Colombier 		w->topped = ++ topped;
10787dd7cddfSDavid du Colombier 	}
10797dd7cddfSDavid du Colombier }
10807dd7cddfSDavid du Colombier 
10817dd7cddfSDavid du Colombier void
10827dd7cddfSDavid du Colombier wbottomme(Window *w)
10837dd7cddfSDavid du Colombier {
10847dd7cddfSDavid du Colombier 	if(w!=nil && w->i!=nil && !w->deleted){
10857dd7cddfSDavid du Colombier 		bottomwindow(w->i);
10867dd7cddfSDavid du Colombier 		flushimage(display, 1);
10877dd7cddfSDavid du Colombier 		w->topped = 0;
10887dd7cddfSDavid du Colombier 	}
10897dd7cddfSDavid du Colombier }
10907dd7cddfSDavid du Colombier 
10917dd7cddfSDavid du Colombier Window*
10927dd7cddfSDavid du Colombier wlookid(int id)
10937dd7cddfSDavid du Colombier {
10947dd7cddfSDavid du Colombier 	int i;
10957dd7cddfSDavid du Colombier 
10967dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
10977dd7cddfSDavid du Colombier 		if(window[i]->id == id)
10987dd7cddfSDavid du Colombier 			return window[i];
10997dd7cddfSDavid du Colombier 	return nil;
11007dd7cddfSDavid du Colombier }
11017dd7cddfSDavid du Colombier 
11027dd7cddfSDavid du Colombier void
11037dd7cddfSDavid du Colombier wclosewin(Window *w)
11047dd7cddfSDavid du Colombier {
11057dd7cddfSDavid du Colombier 	Rectangle r;
11067dd7cddfSDavid du Colombier 	int i;
11077dd7cddfSDavid du Colombier 
11087dd7cddfSDavid du Colombier 	w->deleted = TRUE;
11097dd7cddfSDavid du Colombier 	if(w == input){
11107dd7cddfSDavid du Colombier 		input = nil;
11117dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
11127dd7cddfSDavid du Colombier 	}
111380ee5cbfSDavid du Colombier 	if(w == wkeyboard)
111480ee5cbfSDavid du Colombier 		wkeyboard = nil;
11157dd7cddfSDavid du Colombier 	for(i=0; i<nhidden; i++)
11167dd7cddfSDavid du Colombier 		if(hidden[i] == w){
11177dd7cddfSDavid du Colombier 			--nhidden;
111880ee5cbfSDavid du Colombier 			memmove(hidden+i, hidden+i+1, (nhidden-i)*sizeof(hidden[0]));
11197dd7cddfSDavid du Colombier 			break;
11207dd7cddfSDavid du Colombier 		}
11217dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
11227dd7cddfSDavid du Colombier 		if(window[i] == w){
11237dd7cddfSDavid du Colombier 			--nwindow;
11247dd7cddfSDavid du Colombier 			memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*));
11257dd7cddfSDavid du Colombier 			w->deleted = TRUE;
11267dd7cddfSDavid du Colombier 			r = w->i->r;
11277dd7cddfSDavid du Colombier 			/* move it off-screen to hide it, in case client is slow in letting it go */
11287dd7cddfSDavid du Colombier 			MOVEIT originwindow(w->i, r.min, view->r.max);
11297dd7cddfSDavid du Colombier 			freeimage(w->i);
11307dd7cddfSDavid du Colombier 			w->i = nil;
11317dd7cddfSDavid du Colombier 			return;
11327dd7cddfSDavid du Colombier 		}
11337dd7cddfSDavid du Colombier 	error("unknown window in closewin");
11347dd7cddfSDavid du Colombier }
11357dd7cddfSDavid du Colombier 
11367dd7cddfSDavid du Colombier void
11379a747e4fSDavid du Colombier wsetpid(Window *w, int pid, int dolabel)
11387dd7cddfSDavid du Colombier {
11397dd7cddfSDavid du Colombier 	char buf[128];
11407dd7cddfSDavid du Colombier 	int fd;
11417dd7cddfSDavid du Colombier 
11427dd7cddfSDavid du Colombier 	w->pid = pid;
11439a747e4fSDavid du Colombier 	if(dolabel){
11449a747e4fSDavid du Colombier 		sprint(buf, "rc %d", pid);
11459a747e4fSDavid du Colombier 		free(w->label);
11469a747e4fSDavid du Colombier 		w->label = estrdup(buf);
11479a747e4fSDavid du Colombier 	}
11487dd7cddfSDavid du Colombier 	sprint(buf, "/proc/%d/notepg", pid);
11497dd7cddfSDavid du Colombier 	fd = open(buf, OWRITE|OCEXEC);
11509a747e4fSDavid du Colombier 	if(w->notefd > 0)
11519a747e4fSDavid du Colombier 		close(w->notefd);
11527dd7cddfSDavid du Colombier 	w->notefd = fd;
11537dd7cddfSDavid du Colombier }
11547dd7cddfSDavid du Colombier 
11557dd7cddfSDavid du Colombier void
11567dd7cddfSDavid du Colombier winshell(void *args)
11577dd7cddfSDavid du Colombier {
11587dd7cddfSDavid du Colombier 	Window *w;
11597dd7cddfSDavid du Colombier 	Channel *pidc;
11607dd7cddfSDavid du Colombier 	void **arg;
11617dd7cddfSDavid du Colombier 	char *cmd, *dir;
11627dd7cddfSDavid du Colombier 	char **argv;
11637dd7cddfSDavid du Colombier 
11647dd7cddfSDavid du Colombier 	arg = args;
11657dd7cddfSDavid du Colombier 	w = arg[0];
11667dd7cddfSDavid du Colombier 	pidc = arg[1];
11677dd7cddfSDavid du Colombier 	cmd = arg[2];
11687dd7cddfSDavid du Colombier 	argv = arg[3];
11697dd7cddfSDavid du Colombier 	dir = arg[4];
11707dd7cddfSDavid du Colombier 	rfork(RFNAMEG|RFFDG|RFENVG);
11717dd7cddfSDavid du Colombier 	if(filsysmount(filsys, w->id) < 0){
11729a747e4fSDavid du Colombier 		fprint(2, "mount failed: %r\n");
117380ee5cbfSDavid du Colombier 		sendul(pidc, 0);
11747dd7cddfSDavid du Colombier 		threadexits("mount failed");
11757dd7cddfSDavid du Colombier 	}
11767dd7cddfSDavid du Colombier 	close(0);
11777dd7cddfSDavid du Colombier 	if(open("/dev/cons", OREAD) < 0){
11789a747e4fSDavid du Colombier 		fprint(2, "can't open /dev/cons: %r\n");
117980ee5cbfSDavid du Colombier 		sendul(pidc, 0);
11807dd7cddfSDavid du Colombier 		threadexits("/dev/cons");
11817dd7cddfSDavid du Colombier 	}
11827dd7cddfSDavid du Colombier 	close(1);
11837dd7cddfSDavid du Colombier 	if(open("/dev/cons", OWRITE) < 0){
11849a747e4fSDavid du Colombier 		fprint(2, "can't open /dev/cons: %r\n");
118580ee5cbfSDavid du Colombier 		sendul(pidc, 0);
11867dd7cddfSDavid du Colombier 		threadexits("open");	/* BUG? was terminate() */
11877dd7cddfSDavid du Colombier 	}
11887dd7cddfSDavid du Colombier 	if(wclose(w) == 0){	/* remove extra ref hanging from creation */
11897dd7cddfSDavid du Colombier 		notify(nil);
11907dd7cddfSDavid du Colombier 		dup(1, 2);
11917dd7cddfSDavid du Colombier 		if(dir)
11927dd7cddfSDavid du Colombier 			chdir(dir);
11937dd7cddfSDavid du Colombier 		procexec(pidc, cmd, argv);
11947dd7cddfSDavid du Colombier 		_exits("exec failed");
11957dd7cddfSDavid du Colombier 	}
11967dd7cddfSDavid du Colombier }
11977dd7cddfSDavid du Colombier 
11987dd7cddfSDavid du Colombier static Rune left1[] =  { L'{', L'[', L'(', L'<', L'«', 0 };
11997dd7cddfSDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
12007dd7cddfSDavid du Colombier static Rune left2[] =  { L'\n', 0 };
12017dd7cddfSDavid du Colombier static Rune left3[] =  { L'\'', L'"', L'`', 0 };
12027dd7cddfSDavid du Colombier 
12037dd7cddfSDavid du Colombier Rune *left[] = {
12047dd7cddfSDavid du Colombier 	left1,
12057dd7cddfSDavid du Colombier 	left2,
12067dd7cddfSDavid du Colombier 	left3,
12077dd7cddfSDavid du Colombier 	nil
12087dd7cddfSDavid du Colombier };
12097dd7cddfSDavid du Colombier Rune *right[] = {
12107dd7cddfSDavid du Colombier 	right1,
12117dd7cddfSDavid du Colombier 	left2,
12127dd7cddfSDavid du Colombier 	left3,
12137dd7cddfSDavid du Colombier 	nil
12147dd7cddfSDavid du Colombier };
12157dd7cddfSDavid du Colombier 
12167dd7cddfSDavid du Colombier void
12177dd7cddfSDavid du Colombier wdoubleclick(Window *w, uint *q0, uint *q1)
12187dd7cddfSDavid du Colombier {
12197dd7cddfSDavid du Colombier 	int c, i;
12207dd7cddfSDavid du Colombier 	Rune *r, *l, *p;
12217dd7cddfSDavid du Colombier 	uint q;
12227dd7cddfSDavid du Colombier 
12237dd7cddfSDavid du Colombier 	for(i=0; left[i]!=nil; i++){
12247dd7cddfSDavid du Colombier 		q = *q0;
12257dd7cddfSDavid du Colombier 		l = left[i];
12267dd7cddfSDavid du Colombier 		r = right[i];
12277dd7cddfSDavid du Colombier 		/* try matching character to left, looking right */
12287dd7cddfSDavid du Colombier 		if(q == 0)
12297dd7cddfSDavid du Colombier 			c = '\n';
12307dd7cddfSDavid du Colombier 		else
12317dd7cddfSDavid du Colombier 			c = w->r[q-1];
12327dd7cddfSDavid du Colombier 		p = strrune(l, c);
12337dd7cddfSDavid du Colombier 		if(p != nil){
12347dd7cddfSDavid du Colombier 			if(wclickmatch(w, c, r[p-l], 1, &q))
12357dd7cddfSDavid du Colombier 				*q1 = q-(c!='\n');
12367dd7cddfSDavid du Colombier 			return;
12377dd7cddfSDavid du Colombier 		}
12387dd7cddfSDavid du Colombier 		/* try matching character to right, looking left */
12397dd7cddfSDavid du Colombier 		if(q == w->nr)
12407dd7cddfSDavid du Colombier 			c = '\n';
12417dd7cddfSDavid du Colombier 		else
12427dd7cddfSDavid du Colombier 			c = w->r[q];
12437dd7cddfSDavid du Colombier 		p = strrune(r, c);
12447dd7cddfSDavid du Colombier 		if(p != nil){
12457dd7cddfSDavid du Colombier 			if(wclickmatch(w, c, l[p-r], -1, &q)){
12467dd7cddfSDavid du Colombier 				*q1 = *q0+(*q0<w->nr && c=='\n');
12477dd7cddfSDavid du Colombier 				*q0 = q;
12487dd7cddfSDavid du Colombier 				if(c!='\n' || q!=0 || w->r[0]=='\n')
12497dd7cddfSDavid du Colombier 					(*q0)++;
12507dd7cddfSDavid du Colombier 			}
12517dd7cddfSDavid du Colombier 			return;
12527dd7cddfSDavid du Colombier 		}
12537dd7cddfSDavid du Colombier 	}
12547dd7cddfSDavid du Colombier 	/* try filling out word to right */
12557dd7cddfSDavid du Colombier 	while(*q1<w->nr && isalnum(w->r[*q1]))
12567dd7cddfSDavid du Colombier 		(*q1)++;
12577dd7cddfSDavid du Colombier 	/* try filling out word to left */
12587dd7cddfSDavid du Colombier 	while(*q0>0 && isalnum(w->r[*q0-1]))
12597dd7cddfSDavid du Colombier 		(*q0)--;
12607dd7cddfSDavid du Colombier }
12617dd7cddfSDavid du Colombier 
12627dd7cddfSDavid du Colombier int
12637dd7cddfSDavid du Colombier wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
12647dd7cddfSDavid du Colombier {
12657dd7cddfSDavid du Colombier 	Rune c;
12667dd7cddfSDavid du Colombier 	int nest;
12677dd7cddfSDavid du Colombier 
12687dd7cddfSDavid du Colombier 	nest = 1;
12697dd7cddfSDavid du Colombier 	for(;;){
12707dd7cddfSDavid du Colombier 		if(dir > 0){
12717dd7cddfSDavid du Colombier 			if(*q == w->nr)
12727dd7cddfSDavid du Colombier 				break;
12737dd7cddfSDavid du Colombier 			c = w->r[*q];
12747dd7cddfSDavid du Colombier 			(*q)++;
12757dd7cddfSDavid du Colombier 		}else{
12767dd7cddfSDavid du Colombier 			if(*q == 0)
12777dd7cddfSDavid du Colombier 				break;
12787dd7cddfSDavid du Colombier 			(*q)--;
12797dd7cddfSDavid du Colombier 			c = w->r[*q];
12807dd7cddfSDavid du Colombier 		}
12817dd7cddfSDavid du Colombier 		if(c == cr){
12827dd7cddfSDavid du Colombier 			if(--nest==0)
12837dd7cddfSDavid du Colombier 				return 1;
12847dd7cddfSDavid du Colombier 		}else if(c == cl)
12857dd7cddfSDavid du Colombier 			nest++;
12867dd7cddfSDavid du Colombier 	}
12877dd7cddfSDavid du Colombier 	return cl=='\n' && nest==1;
12887dd7cddfSDavid du Colombier }
12897dd7cddfSDavid du Colombier 
12907dd7cddfSDavid du Colombier 
12917dd7cddfSDavid du Colombier uint
12927dd7cddfSDavid du Colombier wbacknl(Window *w, uint p, uint n)
12937dd7cddfSDavid du Colombier {
12947dd7cddfSDavid du Colombier 	int i, j;
12957dd7cddfSDavid du Colombier 
12967dd7cddfSDavid du Colombier 	/* look for start of this line if n==0 */
12977dd7cddfSDavid du Colombier 	if(n==0 && p>0 && w->r[p-1]!='\n')
12987dd7cddfSDavid du Colombier 		n = 1;
12997dd7cddfSDavid du Colombier 	i = n;
13007dd7cddfSDavid du Colombier 	while(i-->0 && p>0){
13017dd7cddfSDavid du Colombier 		--p;	/* it's at a newline now; back over it */
13027dd7cddfSDavid du Colombier 		if(p == 0)
13037dd7cddfSDavid du Colombier 			break;
13047dd7cddfSDavid du Colombier 		/* at 128 chars, call it a line anyway */
13057dd7cddfSDavid du Colombier 		for(j=128; --j>0 && p>0; p--)
13067dd7cddfSDavid du Colombier 			if(w->r[p-1]=='\n')
13077dd7cddfSDavid du Colombier 				break;
13087dd7cddfSDavid du Colombier 	}
13097dd7cddfSDavid du Colombier 	return p;
13107dd7cddfSDavid du Colombier }
13117dd7cddfSDavid du Colombier 
13127dd7cddfSDavid du Colombier void
13137dd7cddfSDavid du Colombier wshow(Window *w, uint q0)
13147dd7cddfSDavid du Colombier {
13157dd7cddfSDavid du Colombier 	int qe;
13167dd7cddfSDavid du Colombier 	int nl;
13177dd7cddfSDavid du Colombier 	uint q;
13187dd7cddfSDavid du Colombier 
13197dd7cddfSDavid du Colombier 	qe = w->org+w->nchars;
13207dd7cddfSDavid du Colombier 	if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
13217dd7cddfSDavid du Colombier 		wscrdraw(w);
13227dd7cddfSDavid du Colombier 	else{
13237dd7cddfSDavid du Colombier 		nl = 4*w->maxlines/5;
13247dd7cddfSDavid du Colombier 		q = wbacknl(w, q0, nl);
13257dd7cddfSDavid du Colombier 		/* avoid going backwards if trying to go forwards - long lines! */
13267dd7cddfSDavid du Colombier 		if(!(q0>w->org && q<w->org))
13277dd7cddfSDavid du Colombier 			wsetorigin(w, q, TRUE);
13287dd7cddfSDavid du Colombier 		while(q0 > w->org+w->nchars)
13297dd7cddfSDavid du Colombier 			wsetorigin(w, w->org+1, FALSE);
13307dd7cddfSDavid du Colombier 	}
13317dd7cddfSDavid du Colombier }
13327dd7cddfSDavid du Colombier 
13337dd7cddfSDavid du Colombier void
13347dd7cddfSDavid du Colombier wsetorigin(Window *w, uint org, int exact)
13357dd7cddfSDavid du Colombier {
13367dd7cddfSDavid du Colombier 	int i, a, fixup;
13377dd7cddfSDavid du Colombier 	Rune *r;
13387dd7cddfSDavid du Colombier 	uint n;
13397dd7cddfSDavid du Colombier 
13407dd7cddfSDavid du Colombier 	if(org>0 && !exact){
13417dd7cddfSDavid du Colombier 		/* org is an estimate of the char posn; find a newline */
13427dd7cddfSDavid du Colombier 		/* don't try harder than 256 chars */
13437dd7cddfSDavid du Colombier 		for(i=0; i<256 && org<w->nr; i++){
13447dd7cddfSDavid du Colombier 			if(w->r[org] == '\n'){
13457dd7cddfSDavid du Colombier 				org++;
13467dd7cddfSDavid du Colombier 				break;
13477dd7cddfSDavid du Colombier 			}
13487dd7cddfSDavid du Colombier 			org++;
13497dd7cddfSDavid du Colombier 		}
13507dd7cddfSDavid du Colombier 	}
13517dd7cddfSDavid du Colombier 	a = org-w->org;
13527dd7cddfSDavid du Colombier 	fixup = 0;
13537dd7cddfSDavid du Colombier 	if(a>=0 && a<w->nchars){
13547dd7cddfSDavid du Colombier 		frdelete(w, 0, a);
13557dd7cddfSDavid du Colombier 		fixup = 1;	/* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
13567dd7cddfSDavid du Colombier 	}else if(a<0 && -a<w->nchars){
13577dd7cddfSDavid du Colombier 		n = w->org - org;
13587dd7cddfSDavid du Colombier 		r = runemalloc(n);
13597dd7cddfSDavid du Colombier 		runemove(r, w->r+org, n);
13607dd7cddfSDavid du Colombier 		frinsert(w, r, r+n, 0);
13617dd7cddfSDavid du Colombier 		free(r);
13627dd7cddfSDavid du Colombier 	}else
13637dd7cddfSDavid du Colombier 		frdelete(w, 0, w->nchars);
13647dd7cddfSDavid du Colombier 	w->org = org;
13657dd7cddfSDavid du Colombier 	wfill(w);
13667dd7cddfSDavid du Colombier 	wscrdraw(w);
13677dd7cddfSDavid du Colombier 	wsetselect(w, w->q0, w->q1);
13687dd7cddfSDavid du Colombier 	if(fixup && w->p1 > w->p0)
13697dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
13707dd7cddfSDavid du Colombier }
13717dd7cddfSDavid du Colombier 
13727dd7cddfSDavid du Colombier void
13737dd7cddfSDavid du Colombier wsetselect(Window *w, uint q0, uint q1)
13747dd7cddfSDavid du Colombier {
13757dd7cddfSDavid du Colombier 	int p0, p1;
13767dd7cddfSDavid du Colombier 
13777dd7cddfSDavid du Colombier 	/* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
13787dd7cddfSDavid du Colombier 	w->q0 = q0;
13797dd7cddfSDavid du Colombier 	w->q1 = q1;
13807dd7cddfSDavid du Colombier 	/* compute desired p0,p1 from q0,q1 */
13817dd7cddfSDavid du Colombier 	p0 = q0-w->org;
13827dd7cddfSDavid du Colombier 	p1 = q1-w->org;
13837dd7cddfSDavid du Colombier 	if(p0 < 0)
13847dd7cddfSDavid du Colombier 		p0 = 0;
13857dd7cddfSDavid du Colombier 	if(p1 < 0)
13867dd7cddfSDavid du Colombier 		p1 = 0;
13877dd7cddfSDavid du Colombier 	if(p0 > w->nchars)
13887dd7cddfSDavid du Colombier 		p0 = w->nchars;
13897dd7cddfSDavid du Colombier 	if(p1 > w->nchars)
13907dd7cddfSDavid du Colombier 		p1 = w->nchars;
13917dd7cddfSDavid du Colombier 	if(p0==w->p0 && p1==w->p1)
13927dd7cddfSDavid du Colombier 		return;
13937dd7cddfSDavid du Colombier 	/* screen disagrees with desired selection */
13947dd7cddfSDavid du Colombier 	if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
13957dd7cddfSDavid du Colombier 		/* no overlap or too easy to bother trying */
13967dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
13977dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
13987dd7cddfSDavid du Colombier 		goto Return;
13997dd7cddfSDavid du Colombier 	}
14007dd7cddfSDavid du Colombier 	/* overlap; avoid unnecessary painting */
14017dd7cddfSDavid du Colombier 	if(p0 < w->p0){
14027dd7cddfSDavid du Colombier 		/* extend selection backwards */
14037dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
14047dd7cddfSDavid du Colombier 	}else if(p0 > w->p0){
14057dd7cddfSDavid du Colombier 		/* trim first part of selection */
14067dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
14077dd7cddfSDavid du Colombier 	}
14087dd7cddfSDavid du Colombier 	if(p1 > w->p1){
14097dd7cddfSDavid du Colombier 		/* extend selection forwards */
14107dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
14117dd7cddfSDavid du Colombier 	}else if(p1 < w->p1){
14127dd7cddfSDavid du Colombier 		/* trim last part of selection */
14137dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
14147dd7cddfSDavid du Colombier 	}
14157dd7cddfSDavid du Colombier 
14167dd7cddfSDavid du Colombier     Return:
14177dd7cddfSDavid du Colombier 	w->p0 = p0;
14187dd7cddfSDavid du Colombier 	w->p1 = p1;
14197dd7cddfSDavid du Colombier }
14207dd7cddfSDavid du Colombier 
14217dd7cddfSDavid du Colombier uint
14227dd7cddfSDavid du Colombier winsert(Window *w, Rune *r, int n, uint q0)
14237dd7cddfSDavid du Colombier {
14247dd7cddfSDavid du Colombier 	uint m;
14257dd7cddfSDavid du Colombier 
14267dd7cddfSDavid du Colombier 	if(n == 0)
14277dd7cddfSDavid du Colombier 		return q0;
14287dd7cddfSDavid du Colombier 	if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
14297dd7cddfSDavid du Colombier 		m = min(HiWater-LoWater, min(w->org, w->qh));
14307dd7cddfSDavid du Colombier 		w->org -= m;
14317dd7cddfSDavid du Colombier 		w->qh -= m;
14327dd7cddfSDavid du Colombier 		if(w->q0 > m)
14337dd7cddfSDavid du Colombier 			w->q0 -= m;
14347dd7cddfSDavid du Colombier 		else
14357dd7cddfSDavid du Colombier 			w->q0 = 0;
14367dd7cddfSDavid du Colombier 		if(w->q1 > m)
14377dd7cddfSDavid du Colombier 			w->q1 -= m;
14387dd7cddfSDavid du Colombier 		else
14397dd7cddfSDavid du Colombier 			w->q1 = 0;
14407dd7cddfSDavid du Colombier 		w->nr -= m;
14417dd7cddfSDavid du Colombier 		runemove(w->r, w->r+m, w->nr);
14427dd7cddfSDavid du Colombier 		q0 -= m;
14437dd7cddfSDavid du Colombier 	}
14447dd7cddfSDavid du Colombier 	if(w->nr+n > w->maxr){
14457dd7cddfSDavid du Colombier 		/*
14467dd7cddfSDavid du Colombier 		 * Minimize realloc breakage:
14477dd7cddfSDavid du Colombier 		 *	Allocate at least MinWater
14487dd7cddfSDavid du Colombier 		 * 	Double allocation size each time
14497dd7cddfSDavid du Colombier 		 *	But don't go much above HiWater
14507dd7cddfSDavid du Colombier 		 */
14517dd7cddfSDavid du Colombier 		m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
14527dd7cddfSDavid du Colombier 		if(m > HiWater)
14537dd7cddfSDavid du Colombier 			m = max(HiWater+MinWater, w->nr+n);
14547dd7cddfSDavid du Colombier 		if(m > w->maxr){
14557dd7cddfSDavid du Colombier 			w->r = runerealloc(w->r, m);
14567dd7cddfSDavid du Colombier 			w->maxr = m;
14577dd7cddfSDavid du Colombier 		}
14587dd7cddfSDavid du Colombier 	}
14597dd7cddfSDavid du Colombier 	runemove(w->r+q0+n, w->r+q0, w->nr-q0);
14607dd7cddfSDavid du Colombier 	runemove(w->r+q0, r, n);
14617dd7cddfSDavid du Colombier 	w->nr += n;
14627dd7cddfSDavid du Colombier 	/* if output touches, advance selection, not qh; works best for keyboard and output */
14637dd7cddfSDavid du Colombier 	if(q0 <= w->q1)
14647dd7cddfSDavid du Colombier 		w->q1 += n;
14657dd7cddfSDavid du Colombier 	if(q0 <= w->q0)
14667dd7cddfSDavid du Colombier 		w->q0 += n;
14677dd7cddfSDavid du Colombier 	if(q0 < w->qh)
14687dd7cddfSDavid du Colombier 		w->qh += n;
14697dd7cddfSDavid du Colombier 	if(q0 < w->org)
14707dd7cddfSDavid du Colombier 		w->org += n;
14717dd7cddfSDavid du Colombier 	else if(q0 <= w->org+w->nchars)
14727dd7cddfSDavid du Colombier 		frinsert(w, r, r+n, q0-w->org);
14737dd7cddfSDavid du Colombier 	return q0;
14747dd7cddfSDavid du Colombier }
14757dd7cddfSDavid du Colombier 
14767dd7cddfSDavid du Colombier void
14777dd7cddfSDavid du Colombier wfill(Window *w)
14787dd7cddfSDavid du Colombier {
14797dd7cddfSDavid du Colombier 	Rune *rp;
14807dd7cddfSDavid du Colombier 	int i, n, m, nl;
14817dd7cddfSDavid du Colombier 
14827dd7cddfSDavid du Colombier 	if(w->lastlinefull)
14837dd7cddfSDavid du Colombier 		return;
14849a747e4fSDavid du Colombier 	rp = malloc(messagesize);
14857dd7cddfSDavid du Colombier 	do{
14867dd7cddfSDavid du Colombier 		n = w->nr-(w->org+w->nchars);
14877dd7cddfSDavid du Colombier 		if(n == 0)
14887dd7cddfSDavid du Colombier 			break;
14897dd7cddfSDavid du Colombier 		if(n > 2000)	/* educated guess at reasonable amount */
14907dd7cddfSDavid du Colombier 			n = 2000;
14917dd7cddfSDavid du Colombier 		runemove(rp, w->r+(w->org+w->nchars), n);
14927dd7cddfSDavid du Colombier 		/*
14937dd7cddfSDavid du Colombier 		 * it's expensive to frinsert more than we need, so
14947dd7cddfSDavid du Colombier 		 * count newlines.
14957dd7cddfSDavid du Colombier 		 */
14967dd7cddfSDavid du Colombier 		nl = w->maxlines-w->nlines;
14977dd7cddfSDavid du Colombier 		m = 0;
14987dd7cddfSDavid du Colombier 		for(i=0; i<n; ){
14997dd7cddfSDavid du Colombier 			if(rp[i++] == '\n'){
15007dd7cddfSDavid du Colombier 				m++;
15017dd7cddfSDavid du Colombier 				if(m >= nl)
15027dd7cddfSDavid du Colombier 					break;
15037dd7cddfSDavid du Colombier 			}
15047dd7cddfSDavid du Colombier 		}
15057dd7cddfSDavid du Colombier 		frinsert(w, rp, rp+i, w->nchars);
15067dd7cddfSDavid du Colombier 	}while(w->lastlinefull == FALSE);
15077dd7cddfSDavid du Colombier 	free(rp);
15087dd7cddfSDavid du Colombier }
15097dd7cddfSDavid du Colombier 
15107dd7cddfSDavid du Colombier char*
15117dd7cddfSDavid du Colombier wcontents(Window *w, int *ip)
15127dd7cddfSDavid du Colombier {
15137dd7cddfSDavid du Colombier 	return runetobyte(w->r, w->nr, ip);
15147dd7cddfSDavid du Colombier }
1515