xref: /plan9/sys/src/cmd/rio/wind.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include <u.h>
2*7dd7cddfSDavid du Colombier #include <libc.h>
3*7dd7cddfSDavid du Colombier #include <draw.h>
4*7dd7cddfSDavid du Colombier #include <thread.h>
5*7dd7cddfSDavid du Colombier #include <cursor.h>
6*7dd7cddfSDavid du Colombier #include <mouse.h>
7*7dd7cddfSDavid du Colombier #include <keyboard.h>
8*7dd7cddfSDavid du Colombier #include <frame.h>
9*7dd7cddfSDavid du Colombier #include <auth.h>
10*7dd7cddfSDavid du Colombier #include <fcall.h>
11*7dd7cddfSDavid du Colombier #include <plumb.h>
12*7dd7cddfSDavid du Colombier #include "dat.h"
13*7dd7cddfSDavid du Colombier #include "fns.h"
14*7dd7cddfSDavid du Colombier 
15*7dd7cddfSDavid du Colombier #define MOVEIT if(0)
16*7dd7cddfSDavid du Colombier 
17*7dd7cddfSDavid du Colombier enum
18*7dd7cddfSDavid du Colombier {
19*7dd7cddfSDavid du Colombier 	HiWater	= 64000,	/* max size of history */
20*7dd7cddfSDavid du Colombier 	LoWater	= 33000,	/* min size of history after max'ed */
21*7dd7cddfSDavid du Colombier 	MinWater	= 2000,	/* room to leave available when reallocating */
22*7dd7cddfSDavid du Colombier };
23*7dd7cddfSDavid du Colombier 
24*7dd7cddfSDavid du Colombier static	int		topped;
25*7dd7cddfSDavid du Colombier static	int		id;
26*7dd7cddfSDavid du Colombier 
27*7dd7cddfSDavid du Colombier static	Image	*cols[NCOL];
28*7dd7cddfSDavid du Colombier static	Image	*grey;
29*7dd7cddfSDavid du Colombier static	Image	*darkgrey;
30*7dd7cddfSDavid du Colombier static	Cursor	*lastcursor;
31*7dd7cddfSDavid du Colombier static	Image	*titlecol;
32*7dd7cddfSDavid du Colombier static	Image	*lighttitlecol;
33*7dd7cddfSDavid du Colombier static	Image	*holdcol;
34*7dd7cddfSDavid du Colombier static	Image	*lightholdcol;
35*7dd7cddfSDavid du Colombier static	Image	*paleholdcol;
36*7dd7cddfSDavid du Colombier 
37*7dd7cddfSDavid du Colombier Window*
38*7dd7cddfSDavid du Colombier wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl)
39*7dd7cddfSDavid du Colombier {
40*7dd7cddfSDavid du Colombier 	Window *w;
41*7dd7cddfSDavid du Colombier 	Rectangle r;
42*7dd7cddfSDavid du Colombier 
43*7dd7cddfSDavid du Colombier 	if(cols[0] == nil){
44*7dd7cddfSDavid du Colombier 		/* greys are multiples of 0x11111100+0xFF, 14* being palest */
45*7dd7cddfSDavid du Colombier 		grey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
46*7dd7cddfSDavid du Colombier 		darkgrey = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF);
47*7dd7cddfSDavid du Colombier 		cols[BACK] = display->white;
48*7dd7cddfSDavid du Colombier 		cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
49*7dd7cddfSDavid du Colombier 		cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF);
50*7dd7cddfSDavid du Colombier 		cols[TEXT] = display->black;
51*7dd7cddfSDavid du Colombier 		cols[HTEXT] = display->black;
52*7dd7cddfSDavid du Colombier 		titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
53*7dd7cddfSDavid du Colombier 		lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
54*7dd7cddfSDavid du Colombier 		holdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
55*7dd7cddfSDavid du Colombier 		lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
56*7dd7cddfSDavid du Colombier 		paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
57*7dd7cddfSDavid du Colombier 	}
58*7dd7cddfSDavid du Colombier 	w = emalloc(sizeof(Window));
59*7dd7cddfSDavid du Colombier 	w->screenr = i->r;
60*7dd7cddfSDavid du Colombier 	r = insetrect(i->r, Selborder+1);
61*7dd7cddfSDavid du Colombier 	w->i = i;
62*7dd7cddfSDavid du Colombier 	w->mc = *mc;
63*7dd7cddfSDavid du Colombier 	w->ck = ck;
64*7dd7cddfSDavid du Colombier 	w->cctl = cctl;
65*7dd7cddfSDavid du Colombier 	w->cursorp = nil;
66*7dd7cddfSDavid du Colombier 	w->conswrite = chancreate(sizeof(Conswritemesg), 0);
67*7dd7cddfSDavid du Colombier 	w->consread =  chancreate(sizeof(Consreadmesg), 0);
68*7dd7cddfSDavid du Colombier 	w->mouseread =  chancreate(sizeof(Mousereadmesg), 0);
69*7dd7cddfSDavid du Colombier 	w->scrollr = r;
70*7dd7cddfSDavid du Colombier 	w->scrollr.max.x = r.min.x+Scrollwid;
71*7dd7cddfSDavid du Colombier 	w->lastsr = ZR;
72*7dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
73*7dd7cddfSDavid du Colombier 	frinit(w, r, font, i, cols);
74*7dd7cddfSDavid du Colombier 	w->maxtab = maxtab*stringwidth(font, "0");
75*7dd7cddfSDavid du Colombier 	w->topped = ++topped;
76*7dd7cddfSDavid du Colombier 	w->id = ++id;
77*7dd7cddfSDavid du Colombier 	w->notefd = -1;
78*7dd7cddfSDavid du Colombier 	w->scrolling = scrolling;
79*7dd7cddfSDavid du Colombier 	w->dir = estrdup(startdir);
80*7dd7cddfSDavid du Colombier 	r = insetrect(w->i->r, Selborder);
81*7dd7cddfSDavid du Colombier 	draw(w->i, r, cols[BACK], nil, w->entire.min);
82*7dd7cddfSDavid du Colombier 	wborder(w, Selborder);
83*7dd7cddfSDavid du Colombier 	wscrdraw(w);
84*7dd7cddfSDavid du Colombier 	incref(w);	/* ref will be removed after mounting; avoids delete before ready to be deleted */
85*7dd7cddfSDavid du Colombier 	return w;
86*7dd7cddfSDavid du Colombier }
87*7dd7cddfSDavid du Colombier 
88*7dd7cddfSDavid du Colombier void
89*7dd7cddfSDavid du Colombier wsetname(Window *w)
90*7dd7cddfSDavid du Colombier {
91*7dd7cddfSDavid du Colombier 	int i, n;
92*7dd7cddfSDavid du Colombier 	char err[ERRLEN];
93*7dd7cddfSDavid du Colombier 
94*7dd7cddfSDavid du Colombier 	n = sprint(w->name, "window.%d.%d", w->id, w->namecount++);
95*7dd7cddfSDavid du Colombier 	for(i='A'; i<='Z'; i++){
96*7dd7cddfSDavid du Colombier 		if(nameimage(w->i, w->name, 1) > 0)
97*7dd7cddfSDavid du Colombier 			return;
98*7dd7cddfSDavid du Colombier 		errstr(err);
99*7dd7cddfSDavid du Colombier 		if(strcmp(err, "image name in use") != 0)
100*7dd7cddfSDavid du Colombier 			break;
101*7dd7cddfSDavid du Colombier 		w->name[n] = i;
102*7dd7cddfSDavid du Colombier 		w->name[n+1] = 0;
103*7dd7cddfSDavid du Colombier 	}
104*7dd7cddfSDavid du Colombier 	w->name[0] = 0;
105*7dd7cddfSDavid du Colombier 	threadprint(2, "rio: setname failed: %s\n", err);
106*7dd7cddfSDavid du Colombier }
107*7dd7cddfSDavid du Colombier 
108*7dd7cddfSDavid du Colombier void
109*7dd7cddfSDavid du Colombier wresize(Window *w, Image *i, int move)
110*7dd7cddfSDavid du Colombier {
111*7dd7cddfSDavid du Colombier 	Rectangle r, or;
112*7dd7cddfSDavid du Colombier 
113*7dd7cddfSDavid du Colombier 	or = w->i->r;
114*7dd7cddfSDavid du Colombier 	if(move || (Dx(or)==Dx(i->r) && Dy(or)==Dy(i->r)))
115*7dd7cddfSDavid du Colombier 		draw(i, i->r, w->i, nil, w->i->r.min);
116*7dd7cddfSDavid du Colombier 	freeimage(w->i);
117*7dd7cddfSDavid du Colombier 	w->i = i;
118*7dd7cddfSDavid du Colombier 	w->mc.image = i;
119*7dd7cddfSDavid du Colombier 	r = insetrect(i->r, Selborder+1);
120*7dd7cddfSDavid du Colombier 	w->scrollr = r;
121*7dd7cddfSDavid du Colombier 	w->scrollr.max.x = r.min.x+Scrollwid;
122*7dd7cddfSDavid du Colombier 	w->lastsr = ZR;
123*7dd7cddfSDavid du Colombier 	r.min.x += Scrollwid+Scrollgap;
124*7dd7cddfSDavid du Colombier 	if(move)
125*7dd7cddfSDavid du Colombier 		frsetrects(w, r, w->i);
126*7dd7cddfSDavid du Colombier 	else{
127*7dd7cddfSDavid du Colombier 		frclear(w, FALSE);
128*7dd7cddfSDavid du Colombier 		frinit(w, r, w->font, w->i, cols);
129*7dd7cddfSDavid du Colombier 		wsetcols(w);
130*7dd7cddfSDavid du Colombier 		w->maxtab = maxtab*stringwidth(w->font, "0");
131*7dd7cddfSDavid du Colombier 		r = insetrect(w->i->r, Selborder);
132*7dd7cddfSDavid du Colombier 		draw(w->i, r, cols[BACK], nil, w->entire.min);
133*7dd7cddfSDavid du Colombier 		wfill(w);
134*7dd7cddfSDavid du Colombier 		wsetselect(w, w->q0, w->q1);
135*7dd7cddfSDavid du Colombier 		wscrdraw(w);
136*7dd7cddfSDavid du Colombier 	}
137*7dd7cddfSDavid du Colombier 	wborder(w, Selborder);
138*7dd7cddfSDavid du Colombier 	w->topped = ++topped;
139*7dd7cddfSDavid du Colombier 	wsetname(w);
140*7dd7cddfSDavid du Colombier 	w->resized = TRUE;
141*7dd7cddfSDavid du Colombier 	w->mouse.counter++;
142*7dd7cddfSDavid du Colombier }
143*7dd7cddfSDavid du Colombier 
144*7dd7cddfSDavid du Colombier void
145*7dd7cddfSDavid du Colombier wrefresh(Window *w, Rectangle)
146*7dd7cddfSDavid du Colombier {
147*7dd7cddfSDavid du Colombier 	/* BUG: rectangle is ignored */
148*7dd7cddfSDavid du Colombier 	if(w == input)
149*7dd7cddfSDavid du Colombier 		wborder(w, Selborder);
150*7dd7cddfSDavid du Colombier 	else
151*7dd7cddfSDavid du Colombier 		wborder(w, Unselborder);
152*7dd7cddfSDavid du Colombier 	if(w->mouseopen)
153*7dd7cddfSDavid du Colombier 		return;
154*7dd7cddfSDavid du Colombier 	draw(w->i, insetrect(w->i->r, Borderwidth), w->cols[BACK], nil, w->i->r.min);
155*7dd7cddfSDavid du Colombier 	w->ticked = 0;
156*7dd7cddfSDavid du Colombier 	if(w->p0 > 0)
157*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, 0), 0, w->p0, 0);
158*7dd7cddfSDavid du Colombier 	if(w->p1 < w->nchars)
159*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1), w->p1, w->nchars, 0);
160*7dd7cddfSDavid du Colombier 	frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 1);
161*7dd7cddfSDavid du Colombier 	w->lastsr = ZR;
162*7dd7cddfSDavid du Colombier 	wscrdraw(w);
163*7dd7cddfSDavid du Colombier }
164*7dd7cddfSDavid du Colombier 
165*7dd7cddfSDavid du Colombier int
166*7dd7cddfSDavid du Colombier wclose(Window *w)
167*7dd7cddfSDavid du Colombier {
168*7dd7cddfSDavid du Colombier 	int i;
169*7dd7cddfSDavid du Colombier 
170*7dd7cddfSDavid du Colombier 	i = decref(w);
171*7dd7cddfSDavid du Colombier 	if(i > 0)
172*7dd7cddfSDavid du Colombier 		return 0;
173*7dd7cddfSDavid du Colombier 	if(i < 0)
174*7dd7cddfSDavid du Colombier 		error("negative ref count");
175*7dd7cddfSDavid du Colombier 	if(!w->deleted)
176*7dd7cddfSDavid du Colombier 		wclosewin(w);
177*7dd7cddfSDavid du Colombier 	wsendctlmesg(w, Exited, ZR, nil);
178*7dd7cddfSDavid du Colombier 	return 1;
179*7dd7cddfSDavid du Colombier }
180*7dd7cddfSDavid du Colombier 
181*7dd7cddfSDavid du Colombier 
182*7dd7cddfSDavid du Colombier void
183*7dd7cddfSDavid du Colombier winctl(void *arg)
184*7dd7cddfSDavid du Colombier {
185*7dd7cddfSDavid du Colombier 	Rune *rp, *bp, *tp, *up, *kbdr;
186*7dd7cddfSDavid du Colombier 	uint qh;
187*7dd7cddfSDavid du Colombier 	int nr, nb, c, wid, i, npart, initial, lastb;
188*7dd7cddfSDavid du Colombier 	char *t, part[3];
189*7dd7cddfSDavid du Colombier 	Window *w;
190*7dd7cddfSDavid du Colombier 	Mousestate *mp, m;
191*7dd7cddfSDavid du Colombier 	enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, NWALT };
192*7dd7cddfSDavid du Colombier 	Alt alts[NWALT+1];
193*7dd7cddfSDavid du Colombier 	Mousereadmesg mrm;
194*7dd7cddfSDavid du Colombier 	Conswritemesg cwm;
195*7dd7cddfSDavid du Colombier 	Consreadmesg crm;
196*7dd7cddfSDavid du Colombier 	Stringpair pair;
197*7dd7cddfSDavid du Colombier 	Wctlmesg wcm;
198*7dd7cddfSDavid du Colombier 	char buf[32];
199*7dd7cddfSDavid du Colombier 
200*7dd7cddfSDavid du Colombier 	w = arg;
201*7dd7cddfSDavid du Colombier 	sprint(buf, "winctl id=%d", w->id);
202*7dd7cddfSDavid du Colombier 	threadsetname(buf);
203*7dd7cddfSDavid du Colombier 
204*7dd7cddfSDavid du Colombier 	mrm.cm = chancreate(sizeof(Mouse), 0);
205*7dd7cddfSDavid du Colombier 	mrm.isflush = FALSE;
206*7dd7cddfSDavid du Colombier 	cwm.cw = chancreate(sizeof(Stringpair), 0);
207*7dd7cddfSDavid du Colombier 	cwm.isflush = FALSE;
208*7dd7cddfSDavid du Colombier 	crm.c1 = chancreate(sizeof(Stringpair), 0);
209*7dd7cddfSDavid du Colombier 	crm.c2 = chancreate(sizeof(Stringpair), 0);
210*7dd7cddfSDavid du Colombier 	crm.isflush = FALSE;
211*7dd7cddfSDavid du Colombier 
212*7dd7cddfSDavid du Colombier 
213*7dd7cddfSDavid du Colombier 	alts[WKey].c = w->ck;
214*7dd7cddfSDavid du Colombier 	alts[WKey].v = &kbdr;
215*7dd7cddfSDavid du Colombier 	alts[WKey].op = CHANRCV;
216*7dd7cddfSDavid du Colombier 	alts[WMouse].c = w->mc.c;
217*7dd7cddfSDavid du Colombier 	alts[WMouse].v = &w->mc.Mouse;
218*7dd7cddfSDavid du Colombier 	alts[WMouse].op = CHANRCV;
219*7dd7cddfSDavid du Colombier 	alts[WMouseread].c = w->mouseread;
220*7dd7cddfSDavid du Colombier 	alts[WMouseread].v = &mrm;
221*7dd7cddfSDavid du Colombier 	alts[WMouseread].op = CHANSND;
222*7dd7cddfSDavid du Colombier 	alts[WCtl].c = w->cctl;
223*7dd7cddfSDavid du Colombier 	alts[WCtl].v = &wcm;
224*7dd7cddfSDavid du Colombier 	alts[WCtl].op = CHANRCV;
225*7dd7cddfSDavid du Colombier 	alts[WCwrite].c = w->conswrite;
226*7dd7cddfSDavid du Colombier 	alts[WCwrite].v = &cwm;
227*7dd7cddfSDavid du Colombier 	alts[WCwrite].op = CHANSND;
228*7dd7cddfSDavid du Colombier 	alts[WCread].c = w->consread;
229*7dd7cddfSDavid du Colombier 	alts[WCread].v = &crm;
230*7dd7cddfSDavid du Colombier 	alts[WCread].op = CHANSND;
231*7dd7cddfSDavid du Colombier 	alts[NWALT].op = CHANEND;
232*7dd7cddfSDavid du Colombier 
233*7dd7cddfSDavid du Colombier 	npart = 0;
234*7dd7cddfSDavid du Colombier 	lastb = -1;
235*7dd7cddfSDavid du Colombier 	for(;;){
236*7dd7cddfSDavid du Colombier 		if(w->mouseopen && w->mouse.counter != w->mouse.lastcounter)
237*7dd7cddfSDavid du Colombier 			alts[WMouseread].op = CHANSND;
238*7dd7cddfSDavid du Colombier 		else
239*7dd7cddfSDavid du Colombier 			alts[WMouseread].op = CHANNOP;
240*7dd7cddfSDavid du Colombier 		if(!w->scrolling && !w->mouseopen && w->qh>w->org+w->nchars)
241*7dd7cddfSDavid du Colombier 			alts[WCwrite].op = CHANNOP;
242*7dd7cddfSDavid du Colombier 		else
243*7dd7cddfSDavid du Colombier 			alts[WCwrite].op = CHANSND;
244*7dd7cddfSDavid du Colombier 		/* this code depends on NL and EOT fitting in a single byte */
245*7dd7cddfSDavid du Colombier 		/* kind of expensive for each loop; worth precomputing? */
246*7dd7cddfSDavid du Colombier 		if(w->holding)
247*7dd7cddfSDavid du Colombier 			alts[WCread].op = CHANNOP;
248*7dd7cddfSDavid du Colombier 		else if(npart || (w->rawing && w->nraw>0))
249*7dd7cddfSDavid du Colombier 			alts[WCread].op = CHANSND;
250*7dd7cddfSDavid du Colombier 		else{
251*7dd7cddfSDavid du Colombier 			alts[WCread].op = CHANNOP;
252*7dd7cddfSDavid du Colombier 			for(i=w->qh; i<w->nr; i++){
253*7dd7cddfSDavid du Colombier 				c = w->r[i];
254*7dd7cddfSDavid du Colombier 				if(c=='\n' || c=='\004'){
255*7dd7cddfSDavid du Colombier 					alts[WCread].op = CHANSND;
256*7dd7cddfSDavid du Colombier 					break;
257*7dd7cddfSDavid du Colombier 				}
258*7dd7cddfSDavid du Colombier 			}
259*7dd7cddfSDavid du Colombier 		}
260*7dd7cddfSDavid du Colombier 		switch(alt(alts)){
261*7dd7cddfSDavid du Colombier 		case WKey:
262*7dd7cddfSDavid du Colombier 			for(i=0; kbdr[i]!=L'\0'; i++)
263*7dd7cddfSDavid du Colombier 				wkeyctl(w, kbdr[i]);
264*7dd7cddfSDavid du Colombier //			wkeyctl(w, r);
265*7dd7cddfSDavid du Colombier ///			while(nbrecv(w->ck, &r))
266*7dd7cddfSDavid du Colombier //				wkeyctl(w, r);
267*7dd7cddfSDavid du Colombier 			break;
268*7dd7cddfSDavid du Colombier 		case WMouse:
269*7dd7cddfSDavid du Colombier 			if(w->mouseopen) {
270*7dd7cddfSDavid du Colombier 				w->mouse.counter++;
271*7dd7cddfSDavid du Colombier 
272*7dd7cddfSDavid du Colombier 				/* queue click events */
273*7dd7cddfSDavid du Colombier 				if(!w->mouse.qfull && lastb != w->mc.buttons) {	/* add to ring */
274*7dd7cddfSDavid du Colombier 					mp = &w->mouse.queue[w->mouse.wi];
275*7dd7cddfSDavid du Colombier 					if(++w->mouse.wi == nelem(w->mouse.queue))
276*7dd7cddfSDavid du Colombier 						w->mouse.wi = 0;
277*7dd7cddfSDavid du Colombier 					if(w->mouse.wi == w->mouse.ri)
278*7dd7cddfSDavid du Colombier 						w->mouse.qfull = TRUE;
279*7dd7cddfSDavid du Colombier 					mp->Mouse = w->mc;
280*7dd7cddfSDavid du Colombier 					mp->counter = w->mouse.counter;
281*7dd7cddfSDavid du Colombier 					lastb = w->mc.buttons;
282*7dd7cddfSDavid du Colombier 				}
283*7dd7cddfSDavid du Colombier 			} else
284*7dd7cddfSDavid du Colombier 				wmousectl(w);
285*7dd7cddfSDavid du Colombier 			break;
286*7dd7cddfSDavid du Colombier 		case WMouseread:
287*7dd7cddfSDavid du Colombier 			/* send a queued event or, if the queue is empty, the current state */
288*7dd7cddfSDavid du Colombier 			/* if the queue has filled, we discard all the events it contained. */
289*7dd7cddfSDavid du Colombier 			/* the intent is to discard frantic clicking by the user during long latencies. */
290*7dd7cddfSDavid du Colombier 			w->mouse.qfull = FALSE;
291*7dd7cddfSDavid du Colombier 			if(w->mouse.wi != w->mouse.ri) {
292*7dd7cddfSDavid du Colombier 				m = w->mouse.queue[w->mouse.ri];
293*7dd7cddfSDavid du Colombier 				if(++w->mouse.ri == nelem(w->mouse.queue))
294*7dd7cddfSDavid du Colombier 					w->mouse.ri = 0;
295*7dd7cddfSDavid du Colombier 			} else
296*7dd7cddfSDavid du Colombier 				m = (Mousestate){w->mc.Mouse, w->mouse.counter};
297*7dd7cddfSDavid du Colombier 
298*7dd7cddfSDavid du Colombier 			w->mouse.lastcounter = m.counter;
299*7dd7cddfSDavid du Colombier 			send(mrm.cm, &m.Mouse);
300*7dd7cddfSDavid du Colombier 			continue;
301*7dd7cddfSDavid du Colombier 		case WCtl:
302*7dd7cddfSDavid du Colombier 			if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){
303*7dd7cddfSDavid du Colombier 				free(crm.c1);
304*7dd7cddfSDavid du Colombier 				free(crm.c2);
305*7dd7cddfSDavid du Colombier 				free(mrm.cm);
306*7dd7cddfSDavid du Colombier 				free(cwm.cw);
307*7dd7cddfSDavid du Colombier 				threadexits(nil);
308*7dd7cddfSDavid du Colombier 			}
309*7dd7cddfSDavid du Colombier 			continue;
310*7dd7cddfSDavid du Colombier 		case WCwrite:
311*7dd7cddfSDavid du Colombier 			recv(cwm.cw, &pair);
312*7dd7cddfSDavid du Colombier 			rp = pair.s;
313*7dd7cddfSDavid du Colombier 			nr = pair.ns;
314*7dd7cddfSDavid du Colombier 			bp = rp;
315*7dd7cddfSDavid du Colombier 			for(i=0; i<nr; i++)
316*7dd7cddfSDavid du Colombier 				if(*bp++ == '\b'){
317*7dd7cddfSDavid du Colombier 					--bp;
318*7dd7cddfSDavid du Colombier 					initial = 0;
319*7dd7cddfSDavid du Colombier 					tp = runemalloc(nr);
320*7dd7cddfSDavid du Colombier 					runemove(tp, rp, i);
321*7dd7cddfSDavid du Colombier 					up = tp+i;
322*7dd7cddfSDavid du Colombier 					for(; i<nr; i++){
323*7dd7cddfSDavid du Colombier 						*up = *bp++;
324*7dd7cddfSDavid du Colombier 						if(*up == '\b')
325*7dd7cddfSDavid du Colombier 							if(up == tp)
326*7dd7cddfSDavid du Colombier 								initial++;
327*7dd7cddfSDavid du Colombier 							else
328*7dd7cddfSDavid du Colombier 								--up;
329*7dd7cddfSDavid du Colombier 						else
330*7dd7cddfSDavid du Colombier 							up++;
331*7dd7cddfSDavid du Colombier 					}
332*7dd7cddfSDavid du Colombier 					if(initial){
333*7dd7cddfSDavid du Colombier 						if(initial > w->qh)
334*7dd7cddfSDavid du Colombier 							initial = w->qh;
335*7dd7cddfSDavid du Colombier 						qh = w->qh-initial;
336*7dd7cddfSDavid du Colombier 						wdelete(w, qh, qh+initial);
337*7dd7cddfSDavid du Colombier 						w->qh = qh;
338*7dd7cddfSDavid du Colombier 					}
339*7dd7cddfSDavid du Colombier 					free(rp);
340*7dd7cddfSDavid du Colombier 					rp = tp;
341*7dd7cddfSDavid du Colombier 					nr = up-tp;
342*7dd7cddfSDavid du Colombier 					rp[nr] = 0;
343*7dd7cddfSDavid du Colombier 					break;
344*7dd7cddfSDavid du Colombier 				}
345*7dd7cddfSDavid du Colombier 			w->qh = winsert(w, rp, nr, w->qh)+nr;
346*7dd7cddfSDavid du Colombier 			if(w->scrolling || w->mouseopen)
347*7dd7cddfSDavid du Colombier 				wshow(w, w->qh);
348*7dd7cddfSDavid du Colombier 			wsetselect(w, w->q0, w->q1);
349*7dd7cddfSDavid du Colombier 			wscrdraw(w);
350*7dd7cddfSDavid du Colombier 			free(rp);
351*7dd7cddfSDavid du Colombier 			break;
352*7dd7cddfSDavid du Colombier 		case WCread:
353*7dd7cddfSDavid du Colombier 			recv(crm.c1, &pair);
354*7dd7cddfSDavid du Colombier 			t = pair.s;
355*7dd7cddfSDavid du Colombier 			nb = pair.ns;
356*7dd7cddfSDavid du Colombier 			i = npart;
357*7dd7cddfSDavid du Colombier 			npart = 0;
358*7dd7cddfSDavid du Colombier 			if(i)
359*7dd7cddfSDavid du Colombier 				memmove(t, part, i);
360*7dd7cddfSDavid du Colombier 			while(i<nb && (w->qh<w->nr || w->nraw>0)){
361*7dd7cddfSDavid du Colombier 				if(w->qh == w->nr){
362*7dd7cddfSDavid du Colombier 					wid = runetochar(t+i, &w->raw[0]);
363*7dd7cddfSDavid du Colombier 					w->nraw--;
364*7dd7cddfSDavid du Colombier 					runemove(w->raw, w->raw+1, w->nraw);
365*7dd7cddfSDavid du Colombier 				}else
366*7dd7cddfSDavid du Colombier 					wid = runetochar(t+i, &w->r[w->qh++]);
367*7dd7cddfSDavid du Colombier 				c = t[i];	/* knows break characters fit in a byte */
368*7dd7cddfSDavid du Colombier 				i += wid;
369*7dd7cddfSDavid du Colombier 				if(!w->rawing && (c == '\n' || c=='\004')){
370*7dd7cddfSDavid du Colombier 					if(c == '\004')
371*7dd7cddfSDavid du Colombier 						i--;
372*7dd7cddfSDavid du Colombier 					break;
373*7dd7cddfSDavid du Colombier 				}
374*7dd7cddfSDavid du Colombier 			}
375*7dd7cddfSDavid du Colombier 			if(i==nb && w->qh<w->nr && w->r[w->qh]=='\004')
376*7dd7cddfSDavid du Colombier 				w->qh++;
377*7dd7cddfSDavid du Colombier 			if(i > nb){
378*7dd7cddfSDavid du Colombier 				npart = i-nb;
379*7dd7cddfSDavid du Colombier 				memmove(part, t+nb, npart);
380*7dd7cddfSDavid du Colombier 				i = nb;
381*7dd7cddfSDavid du Colombier 			}
382*7dd7cddfSDavid du Colombier 			pair.s = t;
383*7dd7cddfSDavid du Colombier 			pair.ns = i;
384*7dd7cddfSDavid du Colombier 			send(crm.c2, &pair);
385*7dd7cddfSDavid du Colombier 			continue;
386*7dd7cddfSDavid du Colombier 		}
387*7dd7cddfSDavid du Colombier 		if(!w->deleted)
388*7dd7cddfSDavid du Colombier 			flushimage(display, 1);
389*7dd7cddfSDavid du Colombier 	}
390*7dd7cddfSDavid du Colombier }
391*7dd7cddfSDavid du Colombier 
392*7dd7cddfSDavid du Colombier void
393*7dd7cddfSDavid du Colombier waddraw(Window *w, Rune *r, int nr)
394*7dd7cddfSDavid du Colombier {
395*7dd7cddfSDavid du Colombier 	w->raw = runerealloc(w->raw, w->nraw+nr);
396*7dd7cddfSDavid du Colombier 	runemove(w->raw+w->nraw, r, nr);
397*7dd7cddfSDavid du Colombier 	w->nraw += nr;
398*7dd7cddfSDavid du Colombier }
399*7dd7cddfSDavid du Colombier 
400*7dd7cddfSDavid du Colombier void
401*7dd7cddfSDavid du Colombier wkeyctl(Window *w, Rune r)
402*7dd7cddfSDavid du Colombier {
403*7dd7cddfSDavid du Colombier 	uint q0 ,q1;
404*7dd7cddfSDavid du Colombier 	int nb;
405*7dd7cddfSDavid du Colombier 
406*7dd7cddfSDavid du Colombier 	if(r == 0)
407*7dd7cddfSDavid du Colombier 		return;
408*7dd7cddfSDavid du Colombier 	if(w->deleted)
409*7dd7cddfSDavid du Colombier 		return;
410*7dd7cddfSDavid du Colombier 	/* silly old compatibility: any of the three ←↓→ arrow keys go down */
411*7dd7cddfSDavid du Colombier 	if(!w->mouseopen && (r==Kdown || r==Kleft || r==Kright)){
412*7dd7cddfSDavid du Colombier 		q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+(w->maxlines/2)*w->font->height));
413*7dd7cddfSDavid du Colombier 		wsetorigin(w, q0, TRUE);
414*7dd7cddfSDavid du Colombier 		return;
415*7dd7cddfSDavid du Colombier 	}
416*7dd7cddfSDavid du Colombier 	if(r==Kup && !w->mouseopen){
417*7dd7cddfSDavid du Colombier 		q0 = wbacknl(w, w->org, w->maxlines/2);
418*7dd7cddfSDavid du Colombier 		wsetorigin(w, q0, TRUE);
419*7dd7cddfSDavid du Colombier 		return;
420*7dd7cddfSDavid du Colombier 	}
421*7dd7cddfSDavid du Colombier 	if(w->rawing && (w->q0==w->nr || w->mouseopen)){
422*7dd7cddfSDavid du Colombier 		waddraw(w, &r, 1);
423*7dd7cddfSDavid du Colombier 		return;
424*7dd7cddfSDavid du Colombier 	}
425*7dd7cddfSDavid du Colombier 	if(r==0x1B || (w->holding && r==0x7F)){	/* toggle hold */
426*7dd7cddfSDavid du Colombier 		if(w->holding)
427*7dd7cddfSDavid du Colombier 			--w->holding;
428*7dd7cddfSDavid du Colombier 		else
429*7dd7cddfSDavid du Colombier 			w->holding++;
430*7dd7cddfSDavid du Colombier 		wrepaint(w);
431*7dd7cddfSDavid du Colombier 		if(r == 0x1B)
432*7dd7cddfSDavid du Colombier 			return;
433*7dd7cddfSDavid du Colombier 	}
434*7dd7cddfSDavid du Colombier 	if(r != 0x7F){
435*7dd7cddfSDavid du Colombier 		wsnarf(w);
436*7dd7cddfSDavid du Colombier 		wcut(w);
437*7dd7cddfSDavid du Colombier 	}
438*7dd7cddfSDavid du Colombier 	switch(r){
439*7dd7cddfSDavid du Colombier 	case 0x7F:		/* send interrupt */
440*7dd7cddfSDavid du Colombier 		w->qh = w->nr;
441*7dd7cddfSDavid du Colombier 		wshow(w, w->qh);
442*7dd7cddfSDavid du Colombier 		write(w->notefd, "interrupt", 9);
443*7dd7cddfSDavid du Colombier 		return;
444*7dd7cddfSDavid du Colombier 	case 0x08:	/* ^H: erase character */
445*7dd7cddfSDavid du Colombier 	case 0x15:	/* ^U: erase line */
446*7dd7cddfSDavid du Colombier 	case 0x17:	/* ^W: erase word */
447*7dd7cddfSDavid du Colombier 		if(w->q0==0 || w->q0==w->qh)
448*7dd7cddfSDavid du Colombier 			return;
449*7dd7cddfSDavid du Colombier 		nb = wbswidth(w, r);
450*7dd7cddfSDavid du Colombier 		q1 = w->q0;
451*7dd7cddfSDavid du Colombier 		q0 = q1-nb;
452*7dd7cddfSDavid du Colombier 		if(nb)
453*7dd7cddfSDavid du Colombier 			wdelete(w, q0, q0+nb);
454*7dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0);
455*7dd7cddfSDavid du Colombier 		return;
456*7dd7cddfSDavid du Colombier 	}
457*7dd7cddfSDavid du Colombier 	/* otherwise ordinary character; just insert */
458*7dd7cddfSDavid du Colombier 	q0 = w->q0;
459*7dd7cddfSDavid du Colombier 	q0 = winsert(w, &r, 1, q0);
460*7dd7cddfSDavid du Colombier 	wshow(w, q0+1);
461*7dd7cddfSDavid du Colombier }
462*7dd7cddfSDavid du Colombier 
463*7dd7cddfSDavid du Colombier void
464*7dd7cddfSDavid du Colombier wsetcols(Window *w)
465*7dd7cddfSDavid du Colombier {
466*7dd7cddfSDavid du Colombier 	if(w->holding)
467*7dd7cddfSDavid du Colombier 		if(w == input)
468*7dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = holdcol;
469*7dd7cddfSDavid du Colombier 		else
470*7dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = lightholdcol;
471*7dd7cddfSDavid du Colombier 	else
472*7dd7cddfSDavid du Colombier 		if(w == input)
473*7dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = display->black;
474*7dd7cddfSDavid du Colombier 		else
475*7dd7cddfSDavid du Colombier 			w->cols[TEXT] = w->cols[HTEXT] = darkgrey;
476*7dd7cddfSDavid du Colombier }
477*7dd7cddfSDavid du Colombier 
478*7dd7cddfSDavid du Colombier void
479*7dd7cddfSDavid du Colombier wrepaint(Window *w)
480*7dd7cddfSDavid du Colombier {
481*7dd7cddfSDavid du Colombier 	wsetcols(w);
482*7dd7cddfSDavid du Colombier 	if(!w->mouseopen)
483*7dd7cddfSDavid du Colombier 		_frredraw(w, w->Frame.r.min);
484*7dd7cddfSDavid du Colombier 	if(w == input){
485*7dd7cddfSDavid du Colombier 		wborder(w, Selborder);
486*7dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
487*7dd7cddfSDavid du Colombier 	}else
488*7dd7cddfSDavid du Colombier 		wborder(w, Unselborder);
489*7dd7cddfSDavid du Colombier }
490*7dd7cddfSDavid du Colombier 
491*7dd7cddfSDavid du Colombier int
492*7dd7cddfSDavid du Colombier wbswidth(Window *w, Rune c)
493*7dd7cddfSDavid du Colombier {
494*7dd7cddfSDavid du Colombier 	uint q, eq, stop;
495*7dd7cddfSDavid du Colombier 	Rune r;
496*7dd7cddfSDavid du Colombier 	int skipping;
497*7dd7cddfSDavid du Colombier 
498*7dd7cddfSDavid du Colombier 	/* there is known to be at least one character to erase */
499*7dd7cddfSDavid du Colombier 	if(c == 0x08)	/* ^H: erase character */
500*7dd7cddfSDavid du Colombier 		return 1;
501*7dd7cddfSDavid du Colombier 	q = w->q0;
502*7dd7cddfSDavid du Colombier 	stop = 0;
503*7dd7cddfSDavid du Colombier 	if(q > w->qh)
504*7dd7cddfSDavid du Colombier 		stop = w->qh;
505*7dd7cddfSDavid du Colombier 	skipping = TRUE;
506*7dd7cddfSDavid du Colombier 	while(q > stop){
507*7dd7cddfSDavid du Colombier 		r = w->r[q-1];
508*7dd7cddfSDavid du Colombier 		if(r == '\n'){		/* eat at most one more character */
509*7dd7cddfSDavid du Colombier 			if(q == w->q0)	/* eat the newline */
510*7dd7cddfSDavid du Colombier 				--q;
511*7dd7cddfSDavid du Colombier 			break;
512*7dd7cddfSDavid du Colombier 		}
513*7dd7cddfSDavid du Colombier 		if(c == 0x17){
514*7dd7cddfSDavid du Colombier 			eq = isalnum(r);
515*7dd7cddfSDavid du Colombier 			if(eq && skipping)	/* found one; stop skipping */
516*7dd7cddfSDavid du Colombier 				skipping = FALSE;
517*7dd7cddfSDavid du Colombier 			else if(!eq && !skipping)
518*7dd7cddfSDavid du Colombier 				break;
519*7dd7cddfSDavid du Colombier 		}
520*7dd7cddfSDavid du Colombier 		--q;
521*7dd7cddfSDavid du Colombier 	}
522*7dd7cddfSDavid du Colombier 	return w->q0-q;
523*7dd7cddfSDavid du Colombier }
524*7dd7cddfSDavid du Colombier 
525*7dd7cddfSDavid du Colombier void
526*7dd7cddfSDavid du Colombier wsnarf(Window *w)
527*7dd7cddfSDavid du Colombier {
528*7dd7cddfSDavid du Colombier 	if(w->q1 == w->q0)
529*7dd7cddfSDavid du Colombier 		return;
530*7dd7cddfSDavid du Colombier 	nsnarf = w->q1-w->q0;
531*7dd7cddfSDavid du Colombier 	snarf = runerealloc(snarf, nsnarf);
532*7dd7cddfSDavid du Colombier 	runemove(snarf, w->r+w->q0, nsnarf);
533*7dd7cddfSDavid du Colombier 	putsnarf();
534*7dd7cddfSDavid du Colombier }
535*7dd7cddfSDavid du Colombier 
536*7dd7cddfSDavid du Colombier void
537*7dd7cddfSDavid du Colombier wcut(Window *w)
538*7dd7cddfSDavid du Colombier {
539*7dd7cddfSDavid du Colombier 	if(w->q1 == w->q0)
540*7dd7cddfSDavid du Colombier 		return;
541*7dd7cddfSDavid du Colombier 	wdelete(w, w->q0, w->q1);
542*7dd7cddfSDavid du Colombier }
543*7dd7cddfSDavid du Colombier 
544*7dd7cddfSDavid du Colombier void
545*7dd7cddfSDavid du Colombier wpaste(Window *w)
546*7dd7cddfSDavid du Colombier {
547*7dd7cddfSDavid du Colombier 	uint q0;
548*7dd7cddfSDavid du Colombier 
549*7dd7cddfSDavid du Colombier 	if(nsnarf == 0)
550*7dd7cddfSDavid du Colombier 		return;
551*7dd7cddfSDavid du Colombier 	wcut(w);
552*7dd7cddfSDavid du Colombier 	q0 = w->q0;
553*7dd7cddfSDavid du Colombier 	if(w->rawing && q0==w->nr){
554*7dd7cddfSDavid du Colombier 		waddraw(w, snarf, nsnarf);
555*7dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0);
556*7dd7cddfSDavid du Colombier 	}else{
557*7dd7cddfSDavid du Colombier 		winsert(w, snarf, nsnarf, w->q0);
558*7dd7cddfSDavid du Colombier 		wsetselect(w, q0, q0+nsnarf);
559*7dd7cddfSDavid du Colombier 	}
560*7dd7cddfSDavid du Colombier }
561*7dd7cddfSDavid du Colombier 
562*7dd7cddfSDavid du Colombier void
563*7dd7cddfSDavid du Colombier wplumb(Window *w)
564*7dd7cddfSDavid du Colombier {
565*7dd7cddfSDavid du Colombier 	Plumbmsg *m;
566*7dd7cddfSDavid du Colombier 	static int fd = -2;
567*7dd7cddfSDavid du Colombier 	char buf[32];
568*7dd7cddfSDavid du Colombier 	uint p0, p1;
569*7dd7cddfSDavid du Colombier 	Cursor *c;
570*7dd7cddfSDavid du Colombier 
571*7dd7cddfSDavid du Colombier 	if(fd == -2)
572*7dd7cddfSDavid du Colombier 		fd = plumbopen("send", OWRITE|OCEXEC);
573*7dd7cddfSDavid du Colombier 	if(fd < 0)
574*7dd7cddfSDavid du Colombier 		return;
575*7dd7cddfSDavid du Colombier 	m = emalloc(sizeof(Plumbmsg));
576*7dd7cddfSDavid du Colombier 	m->src = estrdup("rio");
577*7dd7cddfSDavid du Colombier 	m->dst = nil;
578*7dd7cddfSDavid du Colombier 	m->wdir = estrdup(w->dir);
579*7dd7cddfSDavid du Colombier 	m->type = strdup("text");
580*7dd7cddfSDavid du Colombier 	p0 = w->q0;
581*7dd7cddfSDavid du Colombier 	p1 = w->q1;
582*7dd7cddfSDavid du Colombier 	if(w->q1 > w->q0)
583*7dd7cddfSDavid du Colombier 		m->attr = nil;
584*7dd7cddfSDavid du Colombier 	else{
585*7dd7cddfSDavid du Colombier 		while(p0>0 && w->r[p0-1]!=' ' && w->r[p0-1]!='\t' && w->r[p0-1]!='\n')
586*7dd7cddfSDavid du Colombier 			p0--;
587*7dd7cddfSDavid du Colombier 		while(p1<w->nr && w->r[p1]!=' ' && w->r[p1]!='\t' && w->r[p1]!='\n')
588*7dd7cddfSDavid du Colombier 			p1++;
589*7dd7cddfSDavid du Colombier 		sprint(buf, "click=%d", w->q0-p0);
590*7dd7cddfSDavid du Colombier 		m->attr = plumbunpackattr(buf);
591*7dd7cddfSDavid du Colombier 	}
592*7dd7cddfSDavid du Colombier 	if(p1-p0 > MAXFDATA-256){
593*7dd7cddfSDavid du Colombier 		plumbfree(m);
594*7dd7cddfSDavid du Colombier 		return;	/* too large for 9P; how to paramaterize this? */
595*7dd7cddfSDavid du Colombier 	}
596*7dd7cddfSDavid du Colombier 	m->data = runetobyte(w->r+p0, p1-p0, &m->ndata);
597*7dd7cddfSDavid du Colombier 	if(plumbsend(fd, m) < 0){
598*7dd7cddfSDavid du Colombier 		c = lastcursor;
599*7dd7cddfSDavid du Colombier 		riosetcursor(&query, 1);
600*7dd7cddfSDavid du Colombier 		sleep(300);
601*7dd7cddfSDavid du Colombier 		riosetcursor(c, 1);
602*7dd7cddfSDavid du Colombier 	}
603*7dd7cddfSDavid du Colombier 	plumbfree(m);
604*7dd7cddfSDavid du Colombier }
605*7dd7cddfSDavid du Colombier 
606*7dd7cddfSDavid du Colombier int
607*7dd7cddfSDavid du Colombier winborder(Window *w, Point xy)
608*7dd7cddfSDavid du Colombier {
609*7dd7cddfSDavid du Colombier 	return ptinrect(xy, w->screenr) && !ptinrect(xy, insetrect(w->screenr, Selborder));
610*7dd7cddfSDavid du Colombier }
611*7dd7cddfSDavid du Colombier 
612*7dd7cddfSDavid du Colombier void
613*7dd7cddfSDavid du Colombier wmousectl(Window *w)
614*7dd7cddfSDavid du Colombier {
615*7dd7cddfSDavid du Colombier 	int but;
616*7dd7cddfSDavid du Colombier 
617*7dd7cddfSDavid du Colombier 	if(w->mc.buttons == 1)
618*7dd7cddfSDavid du Colombier 		but = 1;
619*7dd7cddfSDavid du Colombier 	else if(w->mc.buttons == 2)
620*7dd7cddfSDavid du Colombier 		but = 2;
621*7dd7cddfSDavid du Colombier 	else if(w->mc.buttons == 4)
622*7dd7cddfSDavid du Colombier 		but = 3;
623*7dd7cddfSDavid du Colombier 	else
624*7dd7cddfSDavid du Colombier 		return;
625*7dd7cddfSDavid du Colombier 	incref(w);		/* hold up window while we track */
626*7dd7cddfSDavid du Colombier 	if(w->deleted)
627*7dd7cddfSDavid du Colombier 		goto Return;
628*7dd7cddfSDavid du Colombier 	if(ptinrect(w->mc.xy, w->scrollr)){
629*7dd7cddfSDavid du Colombier 		if(but)
630*7dd7cddfSDavid du Colombier 			wscroll(w, but);
631*7dd7cddfSDavid du Colombier 		goto Return;
632*7dd7cddfSDavid du Colombier 	}
633*7dd7cddfSDavid du Colombier 	if(but == 1)
634*7dd7cddfSDavid du Colombier 		wselect(w);
635*7dd7cddfSDavid du Colombier 	/* else all is handled by main process */
636*7dd7cddfSDavid du Colombier    Return:
637*7dd7cddfSDavid du Colombier 	wclose(w);
638*7dd7cddfSDavid du Colombier }
639*7dd7cddfSDavid du Colombier 
640*7dd7cddfSDavid du Colombier void
641*7dd7cddfSDavid du Colombier wdelete(Window *w, uint q0, uint q1)
642*7dd7cddfSDavid du Colombier {
643*7dd7cddfSDavid du Colombier 	uint n, p0, p1;
644*7dd7cddfSDavid du Colombier 
645*7dd7cddfSDavid du Colombier 	n = q1-q0;
646*7dd7cddfSDavid du Colombier 	if(n == 0)
647*7dd7cddfSDavid du Colombier 		return;
648*7dd7cddfSDavid du Colombier 	runemove(w->r+q0, w->r+q1, w->nr-q1);
649*7dd7cddfSDavid du Colombier 	w->nr -= n;
650*7dd7cddfSDavid du Colombier 	if(q0 < w->q0)
651*7dd7cddfSDavid du Colombier 		w->q0 -= min(n, w->q0-q0);
652*7dd7cddfSDavid du Colombier 	if(q0 < w->q1)
653*7dd7cddfSDavid du Colombier 		w->q1 -= min(n, w->q1-q0);
654*7dd7cddfSDavid du Colombier 	if(q1 < w->qh)
655*7dd7cddfSDavid du Colombier 		w->qh -= n;
656*7dd7cddfSDavid du Colombier 	else if(q0 < w->qh)
657*7dd7cddfSDavid du Colombier 		w->qh = q0;
658*7dd7cddfSDavid du Colombier 	if(q1 <= w->org)
659*7dd7cddfSDavid du Colombier 		w->org -= n;
660*7dd7cddfSDavid du Colombier 	else if(q0 < w->org+w->nchars){
661*7dd7cddfSDavid du Colombier 		p1 = q1 - w->org;
662*7dd7cddfSDavid du Colombier 		if(p1 > w->nchars)
663*7dd7cddfSDavid du Colombier 			p1 = w->nchars;
664*7dd7cddfSDavid du Colombier 		if(q0 < w->org){
665*7dd7cddfSDavid du Colombier 			w->org = q0;
666*7dd7cddfSDavid du Colombier 			p0 = 0;
667*7dd7cddfSDavid du Colombier 		}else
668*7dd7cddfSDavid du Colombier 			p0 = q0 - w->org;
669*7dd7cddfSDavid du Colombier 		frdelete(w, p0, p1);
670*7dd7cddfSDavid du Colombier 		wfill(w);
671*7dd7cddfSDavid du Colombier 	}
672*7dd7cddfSDavid du Colombier }
673*7dd7cddfSDavid du Colombier 
674*7dd7cddfSDavid du Colombier 
675*7dd7cddfSDavid du Colombier static Window	*clickwin;
676*7dd7cddfSDavid du Colombier static uint	clickmsec;
677*7dd7cddfSDavid du Colombier static Window	*selectwin;
678*7dd7cddfSDavid du Colombier static uint	selectq;
679*7dd7cddfSDavid du Colombier 
680*7dd7cddfSDavid du Colombier /*
681*7dd7cddfSDavid du Colombier  * called from frame library
682*7dd7cddfSDavid du Colombier  */
683*7dd7cddfSDavid du Colombier void
684*7dd7cddfSDavid du Colombier framescroll(Frame *f, int dl)
685*7dd7cddfSDavid du Colombier {
686*7dd7cddfSDavid du Colombier 	if(f != &selectwin->Frame)
687*7dd7cddfSDavid du Colombier 		error("frameselect not right frame");
688*7dd7cddfSDavid du Colombier 	wframescroll(selectwin, dl);
689*7dd7cddfSDavid du Colombier }
690*7dd7cddfSDavid du Colombier 
691*7dd7cddfSDavid du Colombier void
692*7dd7cddfSDavid du Colombier wframescroll(Window *w, int dl)
693*7dd7cddfSDavid du Colombier {
694*7dd7cddfSDavid du Colombier 	uint q0;
695*7dd7cddfSDavid du Colombier 
696*7dd7cddfSDavid du Colombier 	if(dl == 0){
697*7dd7cddfSDavid du Colombier 		wscrsleep(w, 100);
698*7dd7cddfSDavid du Colombier 		return;
699*7dd7cddfSDavid du Colombier 	}
700*7dd7cddfSDavid du Colombier 	if(dl < 0){
701*7dd7cddfSDavid du Colombier 		q0 = wbacknl(w, w->org, -dl);
702*7dd7cddfSDavid du Colombier 		if(selectq > w->org+w->p0)
703*7dd7cddfSDavid du Colombier 			wsetselect(w, w->org+w->p0, selectq);
704*7dd7cddfSDavid du Colombier 		else
705*7dd7cddfSDavid du Colombier 			wsetselect(w, selectq, w->org+w->p0);
706*7dd7cddfSDavid du Colombier 	}else{
707*7dd7cddfSDavid du Colombier 		if(w->org+w->nchars == w->nr)
708*7dd7cddfSDavid du Colombier 			return;
709*7dd7cddfSDavid du Colombier 		q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+dl*w->font->height));
710*7dd7cddfSDavid du Colombier 		if(selectq >= w->org+w->p1)
711*7dd7cddfSDavid du Colombier 			wsetselect(w, w->org+w->p1, selectq);
712*7dd7cddfSDavid du Colombier 		else
713*7dd7cddfSDavid du Colombier 			wsetselect(w, selectq, w->org+w->p1);
714*7dd7cddfSDavid du Colombier 	}
715*7dd7cddfSDavid du Colombier 	wsetorigin(w, q0, TRUE);
716*7dd7cddfSDavid du Colombier }
717*7dd7cddfSDavid du Colombier 
718*7dd7cddfSDavid du Colombier void
719*7dd7cddfSDavid du Colombier wselect(Window *w)
720*7dd7cddfSDavid du Colombier {
721*7dd7cddfSDavid du Colombier 	uint q0, q1;
722*7dd7cddfSDavid du Colombier 	int b, x, y, first;
723*7dd7cddfSDavid du Colombier 
724*7dd7cddfSDavid du Colombier 	first = 1;
725*7dd7cddfSDavid du Colombier 	selectwin = w;
726*7dd7cddfSDavid du Colombier 	/*
727*7dd7cddfSDavid du Colombier 	 * Double-click immediately if it might make sense.
728*7dd7cddfSDavid du Colombier 	 */
729*7dd7cddfSDavid du Colombier 	b = w->mc.buttons;
730*7dd7cddfSDavid du Colombier 	q0 = w->q0;
731*7dd7cddfSDavid du Colombier 	q1 = w->q1;
732*7dd7cddfSDavid du Colombier 	selectq = w->org+frcharofpt(w, w->mc.xy);
733*7dd7cddfSDavid du Colombier 	if(clickwin==w && w->mc.msec-clickmsec<500)
734*7dd7cddfSDavid du Colombier 	if(q0==q1 && selectq==w->q0){
735*7dd7cddfSDavid du Colombier 		wdoubleclick(w, &q0, &q1);
736*7dd7cddfSDavid du Colombier 		wsetselect(w, q0, q1);
737*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
738*7dd7cddfSDavid du Colombier 		x = w->mc.xy.x;
739*7dd7cddfSDavid du Colombier 		y = w->mc.xy.y;
740*7dd7cddfSDavid du Colombier 		/* stay here until something interesting happens */
741*7dd7cddfSDavid du Colombier 		do
742*7dd7cddfSDavid du Colombier 			readmouse(&w->mc);
743*7dd7cddfSDavid du Colombier 		while(w->mc.buttons==b && abs(w->mc.xy.x-x)<3 && abs(w->mc.xy.y-y)<3);
744*7dd7cddfSDavid du Colombier 		w->mc.xy.x = x;	/* in case we're calling frselect */
745*7dd7cddfSDavid du Colombier 		w->mc.xy.y = y;
746*7dd7cddfSDavid du Colombier 		q0 = w->q0;	/* may have changed */
747*7dd7cddfSDavid du Colombier 		q1 = w->q1;
748*7dd7cddfSDavid du Colombier 		selectq = q0;
749*7dd7cddfSDavid du Colombier 	}
750*7dd7cddfSDavid du Colombier 	if(w->mc.buttons == b){
751*7dd7cddfSDavid du Colombier 		w->scroll = framescroll;
752*7dd7cddfSDavid du Colombier 		frselect(w, &w->mc);
753*7dd7cddfSDavid du Colombier 		/* horrible botch: while asleep, may have lost selection altogether */
754*7dd7cddfSDavid du Colombier 		if(selectq > w->nr)
755*7dd7cddfSDavid du Colombier 			selectq = w->org + w->p0;
756*7dd7cddfSDavid du Colombier 		w->Frame.scroll = nil;
757*7dd7cddfSDavid du Colombier 		if(selectq < w->org)
758*7dd7cddfSDavid du Colombier 			q0 = selectq;
759*7dd7cddfSDavid du Colombier 		else
760*7dd7cddfSDavid du Colombier 			q0 = w->org + w->p0;
761*7dd7cddfSDavid du Colombier 		if(selectq > w->org+w->nchars)
762*7dd7cddfSDavid du Colombier 			q1 = selectq;
763*7dd7cddfSDavid du Colombier 		else
764*7dd7cddfSDavid du Colombier 			q1 = w->org+w->p1;
765*7dd7cddfSDavid du Colombier 	}
766*7dd7cddfSDavid du Colombier 	if(q0 == q1){
767*7dd7cddfSDavid du Colombier 		if(q0==w->q0 && clickwin==w && w->mc.msec-clickmsec<500){
768*7dd7cddfSDavid du Colombier 			wdoubleclick(w, &q0, &q1);
769*7dd7cddfSDavid du Colombier 			clickwin = nil;
770*7dd7cddfSDavid du Colombier 		}else{
771*7dd7cddfSDavid du Colombier 			clickwin = w;
772*7dd7cddfSDavid du Colombier 			clickmsec = w->mc.msec;
773*7dd7cddfSDavid du Colombier 		}
774*7dd7cddfSDavid du Colombier 	}else
775*7dd7cddfSDavid du Colombier 		clickwin = nil;
776*7dd7cddfSDavid du Colombier 	wsetselect(w, q0, q1);
777*7dd7cddfSDavid du Colombier 	flushimage(display, 1);
778*7dd7cddfSDavid du Colombier 	while(w->mc.buttons){
779*7dd7cddfSDavid du Colombier 		w->mc.msec = 0;
780*7dd7cddfSDavid du Colombier 		b = w->mc.buttons;
781*7dd7cddfSDavid du Colombier 		if(b & 6){
782*7dd7cddfSDavid du Colombier 			if(b & 2){
783*7dd7cddfSDavid du Colombier 				wsnarf(w);
784*7dd7cddfSDavid du Colombier 				wcut(w);
785*7dd7cddfSDavid du Colombier 			}else{
786*7dd7cddfSDavid du Colombier 				if(first){
787*7dd7cddfSDavid du Colombier 					first = 0;
788*7dd7cddfSDavid du Colombier 					getsnarf();
789*7dd7cddfSDavid du Colombier 				}
790*7dd7cddfSDavid du Colombier 				wpaste(w);
791*7dd7cddfSDavid du Colombier 			}
792*7dd7cddfSDavid du Colombier 		}
793*7dd7cddfSDavid du Colombier 		wscrdraw(w);
794*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
795*7dd7cddfSDavid du Colombier 		while(w->mc.buttons == b)
796*7dd7cddfSDavid du Colombier 			readmouse(&w->mc);
797*7dd7cddfSDavid du Colombier 		clickwin = nil;
798*7dd7cddfSDavid du Colombier 	}
799*7dd7cddfSDavid du Colombier }
800*7dd7cddfSDavid du Colombier 
801*7dd7cddfSDavid du Colombier void
802*7dd7cddfSDavid du Colombier wsendctlmesg(Window *w, int type, Rectangle r, Image *image)
803*7dd7cddfSDavid du Colombier {
804*7dd7cddfSDavid du Colombier 	Wctlmesg wcm;
805*7dd7cddfSDavid du Colombier 
806*7dd7cddfSDavid du Colombier 	wcm.type = type;
807*7dd7cddfSDavid du Colombier 	wcm.r = r;
808*7dd7cddfSDavid du Colombier 	wcm.image = image;
809*7dd7cddfSDavid du Colombier 	send(w->cctl, &wcm);
810*7dd7cddfSDavid du Colombier }
811*7dd7cddfSDavid du Colombier 
812*7dd7cddfSDavid du Colombier int
813*7dd7cddfSDavid du Colombier wctlmesg(Window *w, int m, Rectangle r, Image *i)
814*7dd7cddfSDavid du Colombier {
815*7dd7cddfSDavid du Colombier 	char buf[64];
816*7dd7cddfSDavid du Colombier 
817*7dd7cddfSDavid du Colombier 	switch(m){
818*7dd7cddfSDavid du Colombier 	default:
819*7dd7cddfSDavid du Colombier 		error("unknown control message");
820*7dd7cddfSDavid du Colombier 		break;
821*7dd7cddfSDavid du Colombier 	case Wakeup:
822*7dd7cddfSDavid du Colombier 		break;
823*7dd7cddfSDavid du Colombier 	case Moved:
824*7dd7cddfSDavid du Colombier 	case Reshaped:
825*7dd7cddfSDavid du Colombier 		if(w->deleted){
826*7dd7cddfSDavid du Colombier 			freeimage(i);
827*7dd7cddfSDavid du Colombier 			break;
828*7dd7cddfSDavid du Colombier 		}
829*7dd7cddfSDavid du Colombier 		w->screenr = r;
830*7dd7cddfSDavid du Colombier 		strcpy(buf, w->name);
831*7dd7cddfSDavid du Colombier 		wresize(w, i, m==Moved);
832*7dd7cddfSDavid du Colombier 		proccreate(deletetimeoutproc, buf, 4096);
833*7dd7cddfSDavid du Colombier 		if(Dx(r) > 0){
834*7dd7cddfSDavid du Colombier 			if(w != input)
835*7dd7cddfSDavid du Colombier 				wcurrent(w);
836*7dd7cddfSDavid du Colombier 		}else if(w == input)
837*7dd7cddfSDavid du Colombier 			wcurrent(nil);
838*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
839*7dd7cddfSDavid du Colombier 		break;
840*7dd7cddfSDavid du Colombier 	case Refresh:
841*7dd7cddfSDavid du Colombier 		if(w->deleted || Dx(w->screenr)<=0 || !rectclip(&r, w->i->r))
842*7dd7cddfSDavid du Colombier 			break;
843*7dd7cddfSDavid du Colombier 		if(!w->mouseopen)
844*7dd7cddfSDavid du Colombier 			wrefresh(w, r);
845*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
846*7dd7cddfSDavid du Colombier 		break;
847*7dd7cddfSDavid du Colombier 	case Movemouse:
848*7dd7cddfSDavid du Colombier 		if(sweeping || !ptinrect(r.min, w->i->r))
849*7dd7cddfSDavid du Colombier 			break;
850*7dd7cddfSDavid du Colombier 		wmovemouse(w, r.min);
851*7dd7cddfSDavid du Colombier 	case Rawon:
852*7dd7cddfSDavid du Colombier 		break;
853*7dd7cddfSDavid du Colombier 	case Rawoff:
854*7dd7cddfSDavid du Colombier 		if(w->deleted)
855*7dd7cddfSDavid du Colombier 			break;
856*7dd7cddfSDavid du Colombier 		while(w->nraw > 0){
857*7dd7cddfSDavid du Colombier 			wkeyctl(w, w->raw[0]);
858*7dd7cddfSDavid du Colombier 			--w->nraw;
859*7dd7cddfSDavid du Colombier 			runemove(w->raw, w->raw+1, w->nraw);
860*7dd7cddfSDavid du Colombier 		}
861*7dd7cddfSDavid du Colombier 		break;
862*7dd7cddfSDavid du Colombier 	case Holdon:
863*7dd7cddfSDavid du Colombier 	case Holdoff:
864*7dd7cddfSDavid du Colombier 		if(w->deleted)
865*7dd7cddfSDavid du Colombier 			break;
866*7dd7cddfSDavid du Colombier 		wrepaint(w);
867*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
868*7dd7cddfSDavid du Colombier 		break;
869*7dd7cddfSDavid du Colombier 	case Deleted:
870*7dd7cddfSDavid du Colombier 		if(w->deleted)
871*7dd7cddfSDavid du Colombier 			break;
872*7dd7cddfSDavid du Colombier 		write(w->notefd, "hangup", 6);
873*7dd7cddfSDavid du Colombier 		proccreate(deletetimeoutproc, w->name, 4096);
874*7dd7cddfSDavid du Colombier 		wclosewin(w);
875*7dd7cddfSDavid du Colombier 		break;
876*7dd7cddfSDavid du Colombier 	case Exited:
877*7dd7cddfSDavid du Colombier 		frclear(w, FALSE);
878*7dd7cddfSDavid du Colombier 		close(w->notefd);
879*7dd7cddfSDavid du Colombier 		free(w->mc.c);
880*7dd7cddfSDavid du Colombier 		free(w->ck);
881*7dd7cddfSDavid du Colombier 		free(w->cctl);
882*7dd7cddfSDavid du Colombier 		free(w->conswrite);
883*7dd7cddfSDavid du Colombier 		free(w->consread);
884*7dd7cddfSDavid du Colombier 		free(w->mouseread);
885*7dd7cddfSDavid du Colombier 		free(w->raw);
886*7dd7cddfSDavid du Colombier 		free(w->r);
887*7dd7cddfSDavid du Colombier 		free(w);
888*7dd7cddfSDavid du Colombier 		break;
889*7dd7cddfSDavid du Colombier 	}
890*7dd7cddfSDavid du Colombier 	return m;
891*7dd7cddfSDavid du Colombier }
892*7dd7cddfSDavid du Colombier 
893*7dd7cddfSDavid du Colombier /*
894*7dd7cddfSDavid du Colombier  * Convert back to physical coordinates
895*7dd7cddfSDavid du Colombier  */
896*7dd7cddfSDavid du Colombier void
897*7dd7cddfSDavid du Colombier wmovemouse(Window *w, Point p)
898*7dd7cddfSDavid du Colombier {
899*7dd7cddfSDavid du Colombier 	p.x += w->screenr.min.x-w->i->r.min.x;
900*7dd7cddfSDavid du Colombier 	p.y += w->screenr.min.y-w->i->r.min.y;
901*7dd7cddfSDavid du Colombier 	moveto(mousectl, p);
902*7dd7cddfSDavid du Colombier }
903*7dd7cddfSDavid du Colombier 
904*7dd7cddfSDavid du Colombier void
905*7dd7cddfSDavid du Colombier wborder(Window *w, int type)
906*7dd7cddfSDavid du Colombier {
907*7dd7cddfSDavid du Colombier 	Image *col;
908*7dd7cddfSDavid du Colombier 
909*7dd7cddfSDavid du Colombier 	if(w->i == nil)
910*7dd7cddfSDavid du Colombier 		return;
911*7dd7cddfSDavid du Colombier 	if(w->holding){
912*7dd7cddfSDavid du Colombier 		if(type == Selborder)
913*7dd7cddfSDavid du Colombier 			col = holdcol;
914*7dd7cddfSDavid du Colombier 		else
915*7dd7cddfSDavid du Colombier 			col = paleholdcol;
916*7dd7cddfSDavid du Colombier 	}else{
917*7dd7cddfSDavid du Colombier 		if(type == Selborder)
918*7dd7cddfSDavid du Colombier 			col = titlecol;
919*7dd7cddfSDavid du Colombier 		else
920*7dd7cddfSDavid du Colombier 			col = lighttitlecol;
921*7dd7cddfSDavid du Colombier 	}
922*7dd7cddfSDavid du Colombier 
923*7dd7cddfSDavid du Colombier 	border(w->i, w->i->r, Selborder, col, ZP);
924*7dd7cddfSDavid du Colombier }
925*7dd7cddfSDavid du Colombier 
926*7dd7cddfSDavid du Colombier Window*
927*7dd7cddfSDavid du Colombier wpointto(Point pt)
928*7dd7cddfSDavid du Colombier {
929*7dd7cddfSDavid du Colombier 	int i;
930*7dd7cddfSDavid du Colombier 	Window *v, *w;
931*7dd7cddfSDavid du Colombier 
932*7dd7cddfSDavid du Colombier 	w = nil;
933*7dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++){
934*7dd7cddfSDavid du Colombier 		v = window[i];
935*7dd7cddfSDavid du Colombier 		if(ptinrect(pt, v->screenr))
936*7dd7cddfSDavid du Colombier 		if(!v->deleted)
937*7dd7cddfSDavid du Colombier 		if(w==nil || v->topped>w->topped)
938*7dd7cddfSDavid du Colombier 			w = v;
939*7dd7cddfSDavid du Colombier 	}
940*7dd7cddfSDavid du Colombier 	return w;
941*7dd7cddfSDavid du Colombier }
942*7dd7cddfSDavid du Colombier 
943*7dd7cddfSDavid du Colombier void
944*7dd7cddfSDavid du Colombier wcurrent(Window *w)
945*7dd7cddfSDavid du Colombier {
946*7dd7cddfSDavid du Colombier 	Window *oi;
947*7dd7cddfSDavid du Colombier 
948*7dd7cddfSDavid du Colombier 	oi = input;
949*7dd7cddfSDavid du Colombier 	input = w;
950*7dd7cddfSDavid du Colombier 	if(oi!=w && oi!=nil)
951*7dd7cddfSDavid du Colombier 		wrepaint(oi);
952*7dd7cddfSDavid du Colombier 	if(w !=nil){
953*7dd7cddfSDavid du Colombier 		wrepaint(w);
954*7dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
955*7dd7cddfSDavid du Colombier 	}
956*7dd7cddfSDavid du Colombier }
957*7dd7cddfSDavid du Colombier 
958*7dd7cddfSDavid du Colombier void
959*7dd7cddfSDavid du Colombier wsetcursor(Window *w, int force)
960*7dd7cddfSDavid du Colombier {
961*7dd7cddfSDavid du Colombier 	Cursor *p;
962*7dd7cddfSDavid du Colombier 
963*7dd7cddfSDavid du Colombier 	if(w==nil || /*w!=input || */ w->i==nil || Dx(w->screenr)<=0)
964*7dd7cddfSDavid du Colombier 		p = nil;
965*7dd7cddfSDavid du Colombier 	else if(wpointto(mouse->xy) == w){
966*7dd7cddfSDavid du Colombier 		p = w->cursorp;
967*7dd7cddfSDavid du Colombier 		if(p==nil && w->holding)
968*7dd7cddfSDavid du Colombier 			p = &whitearrow;
969*7dd7cddfSDavid du Colombier 	}else
970*7dd7cddfSDavid du Colombier 		p = nil;
971*7dd7cddfSDavid du Colombier 	riosetcursor(p, force);
972*7dd7cddfSDavid du Colombier }
973*7dd7cddfSDavid du Colombier 
974*7dd7cddfSDavid du Colombier void
975*7dd7cddfSDavid du Colombier riosetcursor(Cursor *p, int force)
976*7dd7cddfSDavid du Colombier {
977*7dd7cddfSDavid du Colombier 	if(!force && p==lastcursor)
978*7dd7cddfSDavid du Colombier 		return;
979*7dd7cddfSDavid du Colombier 	setcursor(mousectl, p);
980*7dd7cddfSDavid du Colombier 	lastcursor = p;
981*7dd7cddfSDavid du Colombier }
982*7dd7cddfSDavid du Colombier 
983*7dd7cddfSDavid du Colombier Window*
984*7dd7cddfSDavid du Colombier wtop(Point pt)
985*7dd7cddfSDavid du Colombier {
986*7dd7cddfSDavid du Colombier 	Window *w;
987*7dd7cddfSDavid du Colombier 
988*7dd7cddfSDavid du Colombier 	w = wpointto(pt);
989*7dd7cddfSDavid du Colombier 	if(w){
990*7dd7cddfSDavid du Colombier 		topwindow(w->i);
991*7dd7cddfSDavid du Colombier 		wcurrent(w);
992*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
993*7dd7cddfSDavid du Colombier 		w->topped = ++topped;
994*7dd7cddfSDavid du Colombier 	}
995*7dd7cddfSDavid du Colombier 	return w;
996*7dd7cddfSDavid du Colombier }
997*7dd7cddfSDavid du Colombier 
998*7dd7cddfSDavid du Colombier void
999*7dd7cddfSDavid du Colombier wtopme(Window *w)
1000*7dd7cddfSDavid du Colombier {
1001*7dd7cddfSDavid du Colombier 	if(w!=nil && w->i!=nil && !w->deleted){
1002*7dd7cddfSDavid du Colombier 		topwindow(w->i);
1003*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
1004*7dd7cddfSDavid du Colombier 		w->topped = ++ topped;
1005*7dd7cddfSDavid du Colombier 	}
1006*7dd7cddfSDavid du Colombier }
1007*7dd7cddfSDavid du Colombier 
1008*7dd7cddfSDavid du Colombier void
1009*7dd7cddfSDavid du Colombier wbottomme(Window *w)
1010*7dd7cddfSDavid du Colombier {
1011*7dd7cddfSDavid du Colombier 	if(w!=nil && w->i!=nil && !w->deleted){
1012*7dd7cddfSDavid du Colombier 		bottomwindow(w->i);
1013*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
1014*7dd7cddfSDavid du Colombier 		w->topped = 0;
1015*7dd7cddfSDavid du Colombier 	}
1016*7dd7cddfSDavid du Colombier }
1017*7dd7cddfSDavid du Colombier 
1018*7dd7cddfSDavid du Colombier Window*
1019*7dd7cddfSDavid du Colombier wlookid(int id)
1020*7dd7cddfSDavid du Colombier {
1021*7dd7cddfSDavid du Colombier 	int i;
1022*7dd7cddfSDavid du Colombier 
1023*7dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
1024*7dd7cddfSDavid du Colombier 		if(window[i]->id == id)
1025*7dd7cddfSDavid du Colombier 			return window[i];
1026*7dd7cddfSDavid du Colombier 	return nil;
1027*7dd7cddfSDavid du Colombier }
1028*7dd7cddfSDavid du Colombier 
1029*7dd7cddfSDavid du Colombier void
1030*7dd7cddfSDavid du Colombier wclosewin(Window *w)
1031*7dd7cddfSDavid du Colombier {
1032*7dd7cddfSDavid du Colombier 	Rectangle r;
1033*7dd7cddfSDavid du Colombier 	int i;
1034*7dd7cddfSDavid du Colombier 
1035*7dd7cddfSDavid du Colombier 	w->deleted = TRUE;
1036*7dd7cddfSDavid du Colombier 	if(w == input){
1037*7dd7cddfSDavid du Colombier 		input = nil;
1038*7dd7cddfSDavid du Colombier 		wsetcursor(w, 0);
1039*7dd7cddfSDavid du Colombier 	}
1040*7dd7cddfSDavid du Colombier 	for(i=0; i<nhidden; i++)
1041*7dd7cddfSDavid du Colombier 		if(hidden[i] == w){
1042*7dd7cddfSDavid du Colombier 			--nhidden;
1043*7dd7cddfSDavid du Colombier 			memmove(hidden+i, hidden+i+1, nhidden-i);
1044*7dd7cddfSDavid du Colombier 			break;
1045*7dd7cddfSDavid du Colombier 		}
1046*7dd7cddfSDavid du Colombier 	for(i=0; i<nwindow; i++)
1047*7dd7cddfSDavid du Colombier 		if(window[i] == w){
1048*7dd7cddfSDavid du Colombier 			--nwindow;
1049*7dd7cddfSDavid du Colombier 			memmove(window+i, window+i+1, (nwindow-i)*sizeof(Window*));
1050*7dd7cddfSDavid du Colombier 			w->deleted = TRUE;
1051*7dd7cddfSDavid du Colombier 			r = w->i->r;
1052*7dd7cddfSDavid du Colombier 			/* move it off-screen to hide it, in case client is slow in letting it go */
1053*7dd7cddfSDavid du Colombier 			MOVEIT originwindow(w->i, r.min, view->r.max);
1054*7dd7cddfSDavid du Colombier 			freeimage(w->i);
1055*7dd7cddfSDavid du Colombier 			w->i = nil;
1056*7dd7cddfSDavid du Colombier 			return;
1057*7dd7cddfSDavid du Colombier 		}
1058*7dd7cddfSDavid du Colombier 	error("unknown window in closewin");
1059*7dd7cddfSDavid du Colombier }
1060*7dd7cddfSDavid du Colombier 
1061*7dd7cddfSDavid du Colombier void
1062*7dd7cddfSDavid du Colombier wsetpid(Window *w, int pid)
1063*7dd7cddfSDavid du Colombier {
1064*7dd7cddfSDavid du Colombier 	char buf[128];
1065*7dd7cddfSDavid du Colombier 	int fd;
1066*7dd7cddfSDavid du Colombier 
1067*7dd7cddfSDavid du Colombier 	w->pid = pid;
1068*7dd7cddfSDavid du Colombier 	sprint(w->label, "rc %d", pid);
1069*7dd7cddfSDavid du Colombier 	sprint(buf, "/proc/%d/notepg", pid);
1070*7dd7cddfSDavid du Colombier 	fd = open(buf, OWRITE|OCEXEC);
1071*7dd7cddfSDavid du Colombier 	w->notefd = fd;
1072*7dd7cddfSDavid du Colombier }
1073*7dd7cddfSDavid du Colombier 
1074*7dd7cddfSDavid du Colombier void
1075*7dd7cddfSDavid du Colombier winshell(void *args)
1076*7dd7cddfSDavid du Colombier {
1077*7dd7cddfSDavid du Colombier 	Window *w;
1078*7dd7cddfSDavid du Colombier 	Channel *pidc;
1079*7dd7cddfSDavid du Colombier 	void **arg;
1080*7dd7cddfSDavid du Colombier 	char *cmd, *dir;
1081*7dd7cddfSDavid du Colombier 	char **argv;
1082*7dd7cddfSDavid du Colombier 
1083*7dd7cddfSDavid du Colombier 	arg = args;
1084*7dd7cddfSDavid du Colombier 	w = arg[0];
1085*7dd7cddfSDavid du Colombier 	pidc = arg[1];
1086*7dd7cddfSDavid du Colombier 	cmd = arg[2];
1087*7dd7cddfSDavid du Colombier 	argv = arg[3];
1088*7dd7cddfSDavid du Colombier 	dir = arg[4];
1089*7dd7cddfSDavid du Colombier 	rfork(RFNAMEG|RFFDG|RFENVG);
1090*7dd7cddfSDavid du Colombier 	if(filsysmount(filsys, w->id) < 0){
1091*7dd7cddfSDavid du Colombier 		threadprint(2, "mount failed: %r\n");
1092*7dd7cddfSDavid du Colombier 		threadexits("mount failed");
1093*7dd7cddfSDavid du Colombier 	}
1094*7dd7cddfSDavid du Colombier 	close(0);
1095*7dd7cddfSDavid du Colombier 	if(open("/dev/cons", OREAD) < 0){
1096*7dd7cddfSDavid du Colombier 		threadprint(2, "can't open /dev/cons: %r\n");
1097*7dd7cddfSDavid du Colombier 		threadexits("/dev/cons");
1098*7dd7cddfSDavid du Colombier 	}
1099*7dd7cddfSDavid du Colombier 	close(1);
1100*7dd7cddfSDavid du Colombier 	if(open("/dev/cons", OWRITE) < 0){
1101*7dd7cddfSDavid du Colombier 		threadprint(2, "can't open /dev/cons: %r\n");
1102*7dd7cddfSDavid du Colombier 		threadexits("open");	/* BUG? was terminate() */
1103*7dd7cddfSDavid du Colombier 	}
1104*7dd7cddfSDavid du Colombier 	if(wclose(w) == 0){	/* remove extra ref hanging from creation */
1105*7dd7cddfSDavid du Colombier 		notify(nil);
1106*7dd7cddfSDavid du Colombier 		dup(1, 2);
1107*7dd7cddfSDavid du Colombier 		if(dir)
1108*7dd7cddfSDavid du Colombier 			chdir(dir);
1109*7dd7cddfSDavid du Colombier 		procexec(pidc, cmd, argv);
1110*7dd7cddfSDavid du Colombier 		_exits("exec failed");
1111*7dd7cddfSDavid du Colombier 	}
1112*7dd7cddfSDavid du Colombier }
1113*7dd7cddfSDavid du Colombier 
1114*7dd7cddfSDavid du Colombier static Rune left1[] =  { L'{', L'[', L'(', L'<', L'«', 0 };
1115*7dd7cddfSDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
1116*7dd7cddfSDavid du Colombier static Rune left2[] =  { L'\n', 0 };
1117*7dd7cddfSDavid du Colombier static Rune left3[] =  { L'\'', L'"', L'`', 0 };
1118*7dd7cddfSDavid du Colombier 
1119*7dd7cddfSDavid du Colombier Rune *left[] = {
1120*7dd7cddfSDavid du Colombier 	left1,
1121*7dd7cddfSDavid du Colombier 	left2,
1122*7dd7cddfSDavid du Colombier 	left3,
1123*7dd7cddfSDavid du Colombier 	nil
1124*7dd7cddfSDavid du Colombier };
1125*7dd7cddfSDavid du Colombier Rune *right[] = {
1126*7dd7cddfSDavid du Colombier 	right1,
1127*7dd7cddfSDavid du Colombier 	left2,
1128*7dd7cddfSDavid du Colombier 	left3,
1129*7dd7cddfSDavid du Colombier 	nil
1130*7dd7cddfSDavid du Colombier };
1131*7dd7cddfSDavid du Colombier 
1132*7dd7cddfSDavid du Colombier void
1133*7dd7cddfSDavid du Colombier wdoubleclick(Window *w, uint *q0, uint *q1)
1134*7dd7cddfSDavid du Colombier {
1135*7dd7cddfSDavid du Colombier 	int c, i;
1136*7dd7cddfSDavid du Colombier 	Rune *r, *l, *p;
1137*7dd7cddfSDavid du Colombier 	uint q;
1138*7dd7cddfSDavid du Colombier 
1139*7dd7cddfSDavid du Colombier 	for(i=0; left[i]!=nil; i++){
1140*7dd7cddfSDavid du Colombier 		q = *q0;
1141*7dd7cddfSDavid du Colombier 		l = left[i];
1142*7dd7cddfSDavid du Colombier 		r = right[i];
1143*7dd7cddfSDavid du Colombier 		/* try matching character to left, looking right */
1144*7dd7cddfSDavid du Colombier 		if(q == 0)
1145*7dd7cddfSDavid du Colombier 			c = '\n';
1146*7dd7cddfSDavid du Colombier 		else
1147*7dd7cddfSDavid du Colombier 			c = w->r[q-1];
1148*7dd7cddfSDavid du Colombier 		p = strrune(l, c);
1149*7dd7cddfSDavid du Colombier 		if(p != nil){
1150*7dd7cddfSDavid du Colombier 			if(wclickmatch(w, c, r[p-l], 1, &q))
1151*7dd7cddfSDavid du Colombier 				*q1 = q-(c!='\n');
1152*7dd7cddfSDavid du Colombier 			return;
1153*7dd7cddfSDavid du Colombier 		}
1154*7dd7cddfSDavid du Colombier 		/* try matching character to right, looking left */
1155*7dd7cddfSDavid du Colombier 		if(q == w->nr)
1156*7dd7cddfSDavid du Colombier 			c = '\n';
1157*7dd7cddfSDavid du Colombier 		else
1158*7dd7cddfSDavid du Colombier 			c = w->r[q];
1159*7dd7cddfSDavid du Colombier 		p = strrune(r, c);
1160*7dd7cddfSDavid du Colombier 		if(p != nil){
1161*7dd7cddfSDavid du Colombier 			if(wclickmatch(w, c, l[p-r], -1, &q)){
1162*7dd7cddfSDavid du Colombier 				*q1 = *q0+(*q0<w->nr && c=='\n');
1163*7dd7cddfSDavid du Colombier 				*q0 = q;
1164*7dd7cddfSDavid du Colombier 				if(c!='\n' || q!=0 || w->r[0]=='\n')
1165*7dd7cddfSDavid du Colombier 					(*q0)++;
1166*7dd7cddfSDavid du Colombier 			}
1167*7dd7cddfSDavid du Colombier 			return;
1168*7dd7cddfSDavid du Colombier 		}
1169*7dd7cddfSDavid du Colombier 	}
1170*7dd7cddfSDavid du Colombier 	/* try filling out word to right */
1171*7dd7cddfSDavid du Colombier 	while(*q1<w->nr && isalnum(w->r[*q1]))
1172*7dd7cddfSDavid du Colombier 		(*q1)++;
1173*7dd7cddfSDavid du Colombier 	/* try filling out word to left */
1174*7dd7cddfSDavid du Colombier 	while(*q0>0 && isalnum(w->r[*q0-1]))
1175*7dd7cddfSDavid du Colombier 		(*q0)--;
1176*7dd7cddfSDavid du Colombier }
1177*7dd7cddfSDavid du Colombier 
1178*7dd7cddfSDavid du Colombier int
1179*7dd7cddfSDavid du Colombier wclickmatch(Window *w, int cl, int cr, int dir, uint *q)
1180*7dd7cddfSDavid du Colombier {
1181*7dd7cddfSDavid du Colombier 	Rune c;
1182*7dd7cddfSDavid du Colombier 	int nest;
1183*7dd7cddfSDavid du Colombier 
1184*7dd7cddfSDavid du Colombier 	nest = 1;
1185*7dd7cddfSDavid du Colombier 	for(;;){
1186*7dd7cddfSDavid du Colombier 		if(dir > 0){
1187*7dd7cddfSDavid du Colombier 			if(*q == w->nr)
1188*7dd7cddfSDavid du Colombier 				break;
1189*7dd7cddfSDavid du Colombier 			c = w->r[*q];
1190*7dd7cddfSDavid du Colombier 			(*q)++;
1191*7dd7cddfSDavid du Colombier 		}else{
1192*7dd7cddfSDavid du Colombier 			if(*q == 0)
1193*7dd7cddfSDavid du Colombier 				break;
1194*7dd7cddfSDavid du Colombier 			(*q)--;
1195*7dd7cddfSDavid du Colombier 			c = w->r[*q];
1196*7dd7cddfSDavid du Colombier 		}
1197*7dd7cddfSDavid du Colombier 		if(c == cr){
1198*7dd7cddfSDavid du Colombier 			if(--nest==0)
1199*7dd7cddfSDavid du Colombier 				return 1;
1200*7dd7cddfSDavid du Colombier 		}else if(c == cl)
1201*7dd7cddfSDavid du Colombier 			nest++;
1202*7dd7cddfSDavid du Colombier 	}
1203*7dd7cddfSDavid du Colombier 	return cl=='\n' && nest==1;
1204*7dd7cddfSDavid du Colombier }
1205*7dd7cddfSDavid du Colombier 
1206*7dd7cddfSDavid du Colombier 
1207*7dd7cddfSDavid du Colombier uint
1208*7dd7cddfSDavid du Colombier wbacknl(Window *w, uint p, uint n)
1209*7dd7cddfSDavid du Colombier {
1210*7dd7cddfSDavid du Colombier 	int i, j;
1211*7dd7cddfSDavid du Colombier 
1212*7dd7cddfSDavid du Colombier 	/* look for start of this line if n==0 */
1213*7dd7cddfSDavid du Colombier 	if(n==0 && p>0 && w->r[p-1]!='\n')
1214*7dd7cddfSDavid du Colombier 		n = 1;
1215*7dd7cddfSDavid du Colombier 	i = n;
1216*7dd7cddfSDavid du Colombier 	while(i-->0 && p>0){
1217*7dd7cddfSDavid du Colombier 		--p;	/* it's at a newline now; back over it */
1218*7dd7cddfSDavid du Colombier 		if(p == 0)
1219*7dd7cddfSDavid du Colombier 			break;
1220*7dd7cddfSDavid du Colombier 		/* at 128 chars, call it a line anyway */
1221*7dd7cddfSDavid du Colombier 		for(j=128; --j>0 && p>0; p--)
1222*7dd7cddfSDavid du Colombier 			if(w->r[p-1]=='\n')
1223*7dd7cddfSDavid du Colombier 				break;
1224*7dd7cddfSDavid du Colombier 	}
1225*7dd7cddfSDavid du Colombier 	return p;
1226*7dd7cddfSDavid du Colombier }
1227*7dd7cddfSDavid du Colombier 
1228*7dd7cddfSDavid du Colombier void
1229*7dd7cddfSDavid du Colombier wshow(Window *w, uint q0)
1230*7dd7cddfSDavid du Colombier {
1231*7dd7cddfSDavid du Colombier 	int qe;
1232*7dd7cddfSDavid du Colombier 	int nl;
1233*7dd7cddfSDavid du Colombier 	uint q;
1234*7dd7cddfSDavid du Colombier 
1235*7dd7cddfSDavid du Colombier 	qe = w->org+w->nchars;
1236*7dd7cddfSDavid du Colombier 	if(w->org<=q0 && (q0<qe || (q0==qe && qe==w->nr)))
1237*7dd7cddfSDavid du Colombier 		wscrdraw(w);
1238*7dd7cddfSDavid du Colombier 	else{
1239*7dd7cddfSDavid du Colombier 		nl = 4*w->maxlines/5;
1240*7dd7cddfSDavid du Colombier 		q = wbacknl(w, q0, nl);
1241*7dd7cddfSDavid du Colombier 		/* avoid going backwards if trying to go forwards - long lines! */
1242*7dd7cddfSDavid du Colombier 		if(!(q0>w->org && q<w->org))
1243*7dd7cddfSDavid du Colombier 			wsetorigin(w, q, TRUE);
1244*7dd7cddfSDavid du Colombier 		while(q0 > w->org+w->nchars)
1245*7dd7cddfSDavid du Colombier 			wsetorigin(w, w->org+1, FALSE);
1246*7dd7cddfSDavid du Colombier 	}
1247*7dd7cddfSDavid du Colombier }
1248*7dd7cddfSDavid du Colombier 
1249*7dd7cddfSDavid du Colombier void
1250*7dd7cddfSDavid du Colombier wsetorigin(Window *w, uint org, int exact)
1251*7dd7cddfSDavid du Colombier {
1252*7dd7cddfSDavid du Colombier 	int i, a, fixup;
1253*7dd7cddfSDavid du Colombier 	Rune *r;
1254*7dd7cddfSDavid du Colombier 	uint n;
1255*7dd7cddfSDavid du Colombier 
1256*7dd7cddfSDavid du Colombier 	if(org>0 && !exact){
1257*7dd7cddfSDavid du Colombier 		/* org is an estimate of the char posn; find a newline */
1258*7dd7cddfSDavid du Colombier 		/* don't try harder than 256 chars */
1259*7dd7cddfSDavid du Colombier 		for(i=0; i<256 && org<w->nr; i++){
1260*7dd7cddfSDavid du Colombier 			if(w->r[org] == '\n'){
1261*7dd7cddfSDavid du Colombier 				org++;
1262*7dd7cddfSDavid du Colombier 				break;
1263*7dd7cddfSDavid du Colombier 			}
1264*7dd7cddfSDavid du Colombier 			org++;
1265*7dd7cddfSDavid du Colombier 		}
1266*7dd7cddfSDavid du Colombier 	}
1267*7dd7cddfSDavid du Colombier 	a = org-w->org;
1268*7dd7cddfSDavid du Colombier 	fixup = 0;
1269*7dd7cddfSDavid du Colombier 	if(a>=0 && a<w->nchars){
1270*7dd7cddfSDavid du Colombier 		frdelete(w, 0, a);
1271*7dd7cddfSDavid du Colombier 		fixup = 1;	/* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
1272*7dd7cddfSDavid du Colombier 	}else if(a<0 && -a<w->nchars){
1273*7dd7cddfSDavid du Colombier 		n = w->org - org;
1274*7dd7cddfSDavid du Colombier 		r = runemalloc(n);
1275*7dd7cddfSDavid du Colombier 		runemove(r, w->r+org, n);
1276*7dd7cddfSDavid du Colombier 		frinsert(w, r, r+n, 0);
1277*7dd7cddfSDavid du Colombier 		free(r);
1278*7dd7cddfSDavid du Colombier 	}else
1279*7dd7cddfSDavid du Colombier 		frdelete(w, 0, w->nchars);
1280*7dd7cddfSDavid du Colombier 	w->org = org;
1281*7dd7cddfSDavid du Colombier 	wfill(w);
1282*7dd7cddfSDavid du Colombier 	wscrdraw(w);
1283*7dd7cddfSDavid du Colombier 	wsetselect(w, w->q0, w->q1);
1284*7dd7cddfSDavid du Colombier 	if(fixup && w->p1 > w->p0)
1285*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1-1), w->p1-1, w->p1, 1);
1286*7dd7cddfSDavid du Colombier }
1287*7dd7cddfSDavid du Colombier 
1288*7dd7cddfSDavid du Colombier void
1289*7dd7cddfSDavid du Colombier wsetselect(Window *w, uint q0, uint q1)
1290*7dd7cddfSDavid du Colombier {
1291*7dd7cddfSDavid du Colombier 	int p0, p1;
1292*7dd7cddfSDavid du Colombier 
1293*7dd7cddfSDavid du Colombier 	/* w->p0 and w->p1 are always right; w->q0 and w->q1 may be off */
1294*7dd7cddfSDavid du Colombier 	w->q0 = q0;
1295*7dd7cddfSDavid du Colombier 	w->q1 = q1;
1296*7dd7cddfSDavid du Colombier 	/* compute desired p0,p1 from q0,q1 */
1297*7dd7cddfSDavid du Colombier 	p0 = q0-w->org;
1298*7dd7cddfSDavid du Colombier 	p1 = q1-w->org;
1299*7dd7cddfSDavid du Colombier 	if(p0 < 0)
1300*7dd7cddfSDavid du Colombier 		p0 = 0;
1301*7dd7cddfSDavid du Colombier 	if(p1 < 0)
1302*7dd7cddfSDavid du Colombier 		p1 = 0;
1303*7dd7cddfSDavid du Colombier 	if(p0 > w->nchars)
1304*7dd7cddfSDavid du Colombier 		p0 = w->nchars;
1305*7dd7cddfSDavid du Colombier 	if(p1 > w->nchars)
1306*7dd7cddfSDavid du Colombier 		p1 = w->nchars;
1307*7dd7cddfSDavid du Colombier 	if(p0==w->p0 && p1==w->p1)
1308*7dd7cddfSDavid du Colombier 		return;
1309*7dd7cddfSDavid du Colombier 	/* screen disagrees with desired selection */
1310*7dd7cddfSDavid du Colombier 	if(w->p1<=p0 || p1<=w->p0 || p0==p1 || w->p1==w->p0){
1311*7dd7cddfSDavid du Colombier 		/* no overlap or too easy to bother trying */
1312*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p0), w->p0, w->p1, 0);
1313*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p0), p0, p1, 1);
1314*7dd7cddfSDavid du Colombier 		goto Return;
1315*7dd7cddfSDavid du Colombier 	}
1316*7dd7cddfSDavid du Colombier 	/* overlap; avoid unnecessary painting */
1317*7dd7cddfSDavid du Colombier 	if(p0 < w->p0){
1318*7dd7cddfSDavid du Colombier 		/* extend selection backwards */
1319*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p0), p0, w->p0, 1);
1320*7dd7cddfSDavid du Colombier 	}else if(p0 > w->p0){
1321*7dd7cddfSDavid du Colombier 		/* trim first part of selection */
1322*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p0), w->p0, p0, 0);
1323*7dd7cddfSDavid du Colombier 	}
1324*7dd7cddfSDavid du Colombier 	if(p1 > w->p1){
1325*7dd7cddfSDavid du Colombier 		/* extend selection forwards */
1326*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, w->p1), w->p1, p1, 1);
1327*7dd7cddfSDavid du Colombier 	}else if(p1 < w->p1){
1328*7dd7cddfSDavid du Colombier 		/* trim last part of selection */
1329*7dd7cddfSDavid du Colombier 		frdrawsel(w, frptofchar(w, p1), p1, w->p1, 0);
1330*7dd7cddfSDavid du Colombier 	}
1331*7dd7cddfSDavid du Colombier 
1332*7dd7cddfSDavid du Colombier     Return:
1333*7dd7cddfSDavid du Colombier 	w->p0 = p0;
1334*7dd7cddfSDavid du Colombier 	w->p1 = p1;
1335*7dd7cddfSDavid du Colombier }
1336*7dd7cddfSDavid du Colombier 
1337*7dd7cddfSDavid du Colombier uint
1338*7dd7cddfSDavid du Colombier winsert(Window *w, Rune *r, int n, uint q0)
1339*7dd7cddfSDavid du Colombier {
1340*7dd7cddfSDavid du Colombier 	uint m;
1341*7dd7cddfSDavid du Colombier 
1342*7dd7cddfSDavid du Colombier 	if(n == 0)
1343*7dd7cddfSDavid du Colombier 		return q0;
1344*7dd7cddfSDavid du Colombier 	if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){
1345*7dd7cddfSDavid du Colombier 		m = min(HiWater-LoWater, min(w->org, w->qh));
1346*7dd7cddfSDavid du Colombier 		w->org -= m;
1347*7dd7cddfSDavid du Colombier 		w->qh -= m;
1348*7dd7cddfSDavid du Colombier 		if(w->q0 > m)
1349*7dd7cddfSDavid du Colombier 			w->q0 -= m;
1350*7dd7cddfSDavid du Colombier 		else
1351*7dd7cddfSDavid du Colombier 			w->q0 = 0;
1352*7dd7cddfSDavid du Colombier 		if(w->q1 > m)
1353*7dd7cddfSDavid du Colombier 			w->q1 -= m;
1354*7dd7cddfSDavid du Colombier 		else
1355*7dd7cddfSDavid du Colombier 			w->q1 = 0;
1356*7dd7cddfSDavid du Colombier 		w->nr -= m;
1357*7dd7cddfSDavid du Colombier 		runemove(w->r, w->r+m, w->nr);
1358*7dd7cddfSDavid du Colombier 		q0 -= m;
1359*7dd7cddfSDavid du Colombier 	}
1360*7dd7cddfSDavid du Colombier 	if(w->nr+n > w->maxr){
1361*7dd7cddfSDavid du Colombier 		/*
1362*7dd7cddfSDavid du Colombier 		 * Minimize realloc breakage:
1363*7dd7cddfSDavid du Colombier 		 *	Allocate at least MinWater
1364*7dd7cddfSDavid du Colombier 		 * 	Double allocation size each time
1365*7dd7cddfSDavid du Colombier 		 *	But don't go much above HiWater
1366*7dd7cddfSDavid du Colombier 		 */
1367*7dd7cddfSDavid du Colombier 		m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater;
1368*7dd7cddfSDavid du Colombier 		if(m > HiWater)
1369*7dd7cddfSDavid du Colombier 			m = max(HiWater+MinWater, w->nr+n);
1370*7dd7cddfSDavid du Colombier 		if(m > w->maxr){
1371*7dd7cddfSDavid du Colombier 			w->r = runerealloc(w->r, m);
1372*7dd7cddfSDavid du Colombier 			w->maxr = m;
1373*7dd7cddfSDavid du Colombier 		}
1374*7dd7cddfSDavid du Colombier 	}
1375*7dd7cddfSDavid du Colombier 	runemove(w->r+q0+n, w->r+q0, w->nr-q0);
1376*7dd7cddfSDavid du Colombier 	runemove(w->r+q0, r, n);
1377*7dd7cddfSDavid du Colombier 	w->nr += n;
1378*7dd7cddfSDavid du Colombier 	/* if output touches, advance selection, not qh; works best for keyboard and output */
1379*7dd7cddfSDavid du Colombier 	if(q0 <= w->q1)
1380*7dd7cddfSDavid du Colombier 		w->q1 += n;
1381*7dd7cddfSDavid du Colombier 	if(q0 <= w->q0)
1382*7dd7cddfSDavid du Colombier 		w->q0 += n;
1383*7dd7cddfSDavid du Colombier 	if(q0 < w->qh)
1384*7dd7cddfSDavid du Colombier 		w->qh += n;
1385*7dd7cddfSDavid du Colombier 	if(q0 < w->org)
1386*7dd7cddfSDavid du Colombier 		w->org += n;
1387*7dd7cddfSDavid du Colombier 	else if(q0 <= w->org+w->nchars)
1388*7dd7cddfSDavid du Colombier 		frinsert(w, r, r+n, q0-w->org);
1389*7dd7cddfSDavid du Colombier 	return q0;
1390*7dd7cddfSDavid du Colombier }
1391*7dd7cddfSDavid du Colombier 
1392*7dd7cddfSDavid du Colombier void
1393*7dd7cddfSDavid du Colombier wfill(Window *w)
1394*7dd7cddfSDavid du Colombier {
1395*7dd7cddfSDavid du Colombier 	Rune *rp;
1396*7dd7cddfSDavid du Colombier 	int i, n, m, nl;
1397*7dd7cddfSDavid du Colombier 
1398*7dd7cddfSDavid du Colombier 	if(w->lastlinefull)
1399*7dd7cddfSDavid du Colombier 		return;
1400*7dd7cddfSDavid du Colombier 	rp = malloc(MAXFDATA+MAXMSG);
1401*7dd7cddfSDavid du Colombier 	do{
1402*7dd7cddfSDavid du Colombier 		n = w->nr-(w->org+w->nchars);
1403*7dd7cddfSDavid du Colombier 		if(n == 0)
1404*7dd7cddfSDavid du Colombier 			break;
1405*7dd7cddfSDavid du Colombier 		if(n > 2000)	/* educated guess at reasonable amount */
1406*7dd7cddfSDavid du Colombier 			n = 2000;
1407*7dd7cddfSDavid du Colombier 		runemove(rp, w->r+(w->org+w->nchars), n);
1408*7dd7cddfSDavid du Colombier 		/*
1409*7dd7cddfSDavid du Colombier 		 * it's expensive to frinsert more than we need, so
1410*7dd7cddfSDavid du Colombier 		 * count newlines.
1411*7dd7cddfSDavid du Colombier 		 */
1412*7dd7cddfSDavid du Colombier 		nl = w->maxlines-w->nlines;
1413*7dd7cddfSDavid du Colombier 		m = 0;
1414*7dd7cddfSDavid du Colombier 		for(i=0; i<n; ){
1415*7dd7cddfSDavid du Colombier 			if(rp[i++] == '\n'){
1416*7dd7cddfSDavid du Colombier 				m++;
1417*7dd7cddfSDavid du Colombier 				if(m >= nl)
1418*7dd7cddfSDavid du Colombier 					break;
1419*7dd7cddfSDavid du Colombier 			}
1420*7dd7cddfSDavid du Colombier 		}
1421*7dd7cddfSDavid du Colombier 		frinsert(w, rp, rp+i, w->nchars);
1422*7dd7cddfSDavid du Colombier 	}while(w->lastlinefull == FALSE);
1423*7dd7cddfSDavid du Colombier 	free(rp);
1424*7dd7cddfSDavid du Colombier }
1425*7dd7cddfSDavid du Colombier 
1426*7dd7cddfSDavid du Colombier char*
1427*7dd7cddfSDavid du Colombier wcontents(Window *w, int *ip)
1428*7dd7cddfSDavid du Colombier {
1429*7dd7cddfSDavid du Colombier 	return runetobyte(w->r, w->nr, ip);
1430*7dd7cddfSDavid du Colombier }
1431