xref: /plan9/sys/src/cmd/acme/wind.c (revision 588d0145e19f8596f2f4442d05dd8a9eda147983)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid 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 int	winid;
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier void
wininit(Window * w,Window * clone,Rectangle r)177dd7cddfSDavid du Colombier wininit(Window *w, Window *clone, Rectangle r)
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	Rectangle r1, br;
207dd7cddfSDavid du Colombier 	File *f;
217dd7cddfSDavid du Colombier 	Reffont *rf;
227dd7cddfSDavid du Colombier 	Rune *rp;
237dd7cddfSDavid du Colombier 	int nc;
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier 	w->tag.w = w;
267dd7cddfSDavid du Colombier 	w->body.w = w;
277dd7cddfSDavid du Colombier 	w->id = ++winid;
287dd7cddfSDavid du Colombier 	incref(w);
2906300895SDavid du Colombier 	if(globalincref)
3006300895SDavid du Colombier 		incref(w);
317dd7cddfSDavid du Colombier 	w->ctlfid = ~0;
327dd7cddfSDavid du Colombier 	w->utflastqid = -1;
337dd7cddfSDavid du Colombier 	r1 = r;
347dd7cddfSDavid du Colombier 	r1.max.y = r1.min.y + font->height;
357dd7cddfSDavid du Colombier 	incref(&reffont);
367dd7cddfSDavid du Colombier 	f = fileaddtext(nil, &w->tag);
377dd7cddfSDavid du Colombier 	textinit(&w->tag, f, r1, &reffont, tagcols);
387dd7cddfSDavid du Colombier 	w->tag.what = Tag;
397dd7cddfSDavid du Colombier 	/* tag is a copy of the contents, not a tracked image */
407dd7cddfSDavid du Colombier 	if(clone){
417dd7cddfSDavid du Colombier 		textdelete(&w->tag, 0, w->tag.file->nc, TRUE);
427dd7cddfSDavid du Colombier 		nc = clone->tag.file->nc;
437dd7cddfSDavid du Colombier 		rp = runemalloc(nc);
447dd7cddfSDavid du Colombier 		bufread(clone->tag.file, 0, rp, nc);
457dd7cddfSDavid du Colombier 		textinsert(&w->tag, 0, rp, nc, TRUE);
467dd7cddfSDavid du Colombier 		free(rp);
477dd7cddfSDavid du Colombier 		filereset(w->tag.file);
487dd7cddfSDavid du Colombier 		textsetselect(&w->tag, nc, nc);
497dd7cddfSDavid du Colombier 	}
507dd7cddfSDavid du Colombier 	r1 = r;
517dd7cddfSDavid du Colombier 	r1.min.y += font->height + 1;
527dd7cddfSDavid du Colombier 	if(r1.max.y < r1.min.y)
537dd7cddfSDavid du Colombier 		r1.max.y = r1.min.y;
547dd7cddfSDavid du Colombier 	f = nil;
557dd7cddfSDavid du Colombier 	if(clone){
567dd7cddfSDavid du Colombier 		f = clone->body.file;
577dd7cddfSDavid du Colombier 		w->body.org = clone->body.org;
587dd7cddfSDavid du Colombier 		w->isscratch = clone->isscratch;
597dd7cddfSDavid du Colombier 		rf = rfget(FALSE, FALSE, FALSE, clone->body.reffont->f->name);
607dd7cddfSDavid du Colombier 	}else
617dd7cddfSDavid du Colombier 		rf = rfget(FALSE, FALSE, FALSE, nil);
627dd7cddfSDavid du Colombier 	f = fileaddtext(f, &w->body);
637dd7cddfSDavid du Colombier 	w->body.what = Body;
647dd7cddfSDavid du Colombier 	textinit(&w->body, f, r1, rf, textcols);
657dd7cddfSDavid du Colombier 	r1.min.y -= 1;
667dd7cddfSDavid du Colombier 	r1.max.y = r1.min.y+1;
677dd7cddfSDavid du Colombier 	draw(screen, r1, tagcols[BORD], nil, ZP);
687dd7cddfSDavid du Colombier 	textscrdraw(&w->body);
697dd7cddfSDavid du Colombier 	w->r = r;
707dd7cddfSDavid du Colombier 	w->r.max.y = w->body.r.max.y;
717dd7cddfSDavid du Colombier 	br.min = w->tag.scrollr.min;
727dd7cddfSDavid du Colombier 	br.max.x = br.min.x + Dx(button->r);
737dd7cddfSDavid du Colombier 	br.max.y = br.min.y + Dy(button->r);
747dd7cddfSDavid du Colombier 	draw(screen, br, button, nil, button->r.min);
757dd7cddfSDavid du Colombier 	w->filemenu = TRUE;
767dd7cddfSDavid du Colombier 	w->maxlines = w->body.maxlines;
77a30303efSDavid du Colombier 	w->autoindent = globalautoindent;
787dd7cddfSDavid du Colombier 	if(clone){
797dd7cddfSDavid du Colombier 		w->dirty = clone->dirty;
807dd7cddfSDavid du Colombier 		textsetselect(&w->body, clone->body.q0, clone->body.q1);
817dd7cddfSDavid du Colombier 		winsettag(w);
82a30303efSDavid du Colombier 		w->autoindent = clone->autoindent;
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier int
delrunepos(Window * w)87*588d0145SDavid du Colombier delrunepos(Window *w)
88*588d0145SDavid du Colombier {
89*588d0145SDavid du Colombier 	int n;
90*588d0145SDavid du Colombier 	Rune rune;
91*588d0145SDavid du Colombier 
92*588d0145SDavid du Colombier 	for(n=0; n<w->tag.file->nc; n++) {
93*588d0145SDavid du Colombier 		bufread(w->tag.file, n, &rune, 1);
94*588d0145SDavid du Colombier 		if(rune == ' ')
95*588d0145SDavid du Colombier 			break;
96*588d0145SDavid du Colombier 	}
97*588d0145SDavid du Colombier 	n += 2;
98*588d0145SDavid du Colombier 	if(n >= w->tag.file->nc)
99*588d0145SDavid du Colombier 		return -1;
100*588d0145SDavid du Colombier 	return n;
101*588d0145SDavid du Colombier }
102*588d0145SDavid du Colombier 
103*588d0145SDavid du Colombier void
movetodel(Window * w)104*588d0145SDavid du Colombier movetodel(Window *w)
105*588d0145SDavid du Colombier {
106*588d0145SDavid du Colombier 	int n;
107*588d0145SDavid du Colombier 
108*588d0145SDavid du Colombier 	n = delrunepos(w);
109*588d0145SDavid du Colombier 	if(n < 0)
110*588d0145SDavid du Colombier 		return;
111*588d0145SDavid du Colombier 	moveto(mousectl, addpt(frptofchar(&w->tag, n), Pt(4, w->tag.font->height-4)));
112*588d0145SDavid du Colombier }
113*588d0145SDavid du Colombier 
114*588d0145SDavid du Colombier int
winresize(Window * w,Rectangle r,int safe)1157dd7cddfSDavid du Colombier winresize(Window *w, Rectangle r, int safe)
1167dd7cddfSDavid du Colombier {
1177dd7cddfSDavid du Colombier 	Rectangle r1;
1187dd7cddfSDavid du Colombier 	int y;
1197dd7cddfSDavid du Colombier 	Image *b;
1207dd7cddfSDavid du Colombier 	Rectangle br;
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	r1 = r;
1237dd7cddfSDavid du Colombier 	r1.max.y = r1.min.y + font->height;
1247dd7cddfSDavid du Colombier 	y = r1.max.y;
1257dd7cddfSDavid du Colombier 	if(!safe || !eqrect(w->tag.r, r1)){
1267dd7cddfSDavid du Colombier 		y = textresize(&w->tag, r1);
1277dd7cddfSDavid du Colombier 		b = button;
1287dd7cddfSDavid du Colombier 		if(w->body.file->mod && !w->isdir && !w->isscratch)
1297dd7cddfSDavid du Colombier 			b = modbutton;
1307dd7cddfSDavid du Colombier 		br.min = w->tag.scrollr.min;
1317dd7cddfSDavid du Colombier 		br.max.x = br.min.x + Dx(b->r);
1327dd7cddfSDavid du Colombier 		br.max.y = br.min.y + Dy(b->r);
1337dd7cddfSDavid du Colombier 		draw(screen, br, b, nil, b->r.min);
1347dd7cddfSDavid du Colombier 	}
1357dd7cddfSDavid du Colombier 	if(!safe || !eqrect(w->body.r, r1)){
1367dd7cddfSDavid du Colombier 		if(y+1+font->height > r.max.y){		/* no body */
1377dd7cddfSDavid du Colombier 			r1.min.y = y;
1387dd7cddfSDavid du Colombier 			r1.max.y = y;
1397dd7cddfSDavid du Colombier 			textresize(&w->body, r1);
1407dd7cddfSDavid du Colombier 			w->r = r;
1417dd7cddfSDavid du Colombier 			w->r.max.y = y;
1427dd7cddfSDavid du Colombier 			return y;
1437dd7cddfSDavid du Colombier 		}
1447dd7cddfSDavid du Colombier 		r1 = r;
1457dd7cddfSDavid du Colombier 		r1.min.y = y;
1467dd7cddfSDavid du Colombier 		r1.max.y = y + 1;
1477dd7cddfSDavid du Colombier 		draw(screen, r1, tagcols[BORD], nil, ZP);
1487dd7cddfSDavid du Colombier 		r1.min.y = y + 1;
1497dd7cddfSDavid du Colombier 		r1.max.y = r.max.y;
1507dd7cddfSDavid du Colombier 		y = textresize(&w->body, r1);
1517dd7cddfSDavid du Colombier 		w->r = r;
1527dd7cddfSDavid du Colombier 		w->r.max.y = y;
1537dd7cddfSDavid du Colombier 		textscrdraw(&w->body);
1547dd7cddfSDavid du Colombier 	}
1557dd7cddfSDavid du Colombier 	w->maxlines = min(w->body.nlines, max(w->maxlines, w->body.maxlines));
1567dd7cddfSDavid du Colombier 	return w->r.max.y;
1577dd7cddfSDavid du Colombier }
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier void
winlock1(Window * w,int owner)1607dd7cddfSDavid du Colombier winlock1(Window *w, int owner)
1617dd7cddfSDavid du Colombier {
1627dd7cddfSDavid du Colombier 	incref(w);
1637dd7cddfSDavid du Colombier 	qlock(w);
1647dd7cddfSDavid du Colombier 	w->owner = owner;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier void
winlock(Window * w,int owner)1687dd7cddfSDavid du Colombier winlock(Window *w, int owner)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	int i;
1717dd7cddfSDavid du Colombier 	File *f;
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	f = w->body.file;
1747dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++)
1757dd7cddfSDavid du Colombier 		winlock1(f->text[i]->w, owner);
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier void
winunlock(Window * w)1797dd7cddfSDavid du Colombier winunlock(Window *w)
1807dd7cddfSDavid du Colombier {
1817dd7cddfSDavid du Colombier 	int i;
1827dd7cddfSDavid du Colombier 	File *f;
1837dd7cddfSDavid du Colombier 
184e6f18918SDavid du Colombier 	/*
185e6f18918SDavid du Colombier 	 * subtle: loop runs backwards to avoid tripping over
186e6f18918SDavid du Colombier 	 * winclose indirectly editing f->text and freeing f
187e6f18918SDavid du Colombier 	 * on the last iteration of the loop.
188e6f18918SDavid du Colombier 	 */
1897dd7cddfSDavid du Colombier 	f = w->body.file;
190e6f18918SDavid du Colombier 	for(i=f->ntext-1; i>=0; i--){
1917dd7cddfSDavid du Colombier 		w = f->text[i]->w;
1927dd7cddfSDavid du Colombier 		w->owner = 0;
1937dd7cddfSDavid du Colombier 		qunlock(w);
1947dd7cddfSDavid du Colombier 		winclose(w);
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier void
winmousebut(Window * w)1997dd7cddfSDavid du Colombier winmousebut(Window *w)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier 	moveto(mousectl, divpt(addpt(w->tag.scrollr.min, w->tag.scrollr.max), 2));
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier void
windirfree(Window * w)2057dd7cddfSDavid du Colombier windirfree(Window *w)
2067dd7cddfSDavid du Colombier {
2077dd7cddfSDavid du Colombier 	int i;
2087dd7cddfSDavid du Colombier 	Dirlist *dl;
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier 	if(w->isdir){
2117dd7cddfSDavid du Colombier 		for(i=0; i<w->ndl; i++){
2127dd7cddfSDavid du Colombier 			dl = w->dlp[i];
2137dd7cddfSDavid du Colombier 			free(dl->r);
2147dd7cddfSDavid du Colombier 			free(dl);
2157dd7cddfSDavid du Colombier 		}
2167dd7cddfSDavid du Colombier 		free(w->dlp);
2177dd7cddfSDavid du Colombier 	}
2187dd7cddfSDavid du Colombier 	w->dlp = nil;
2197dd7cddfSDavid du Colombier 	w->ndl = 0;
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier void
winclose(Window * w)2237dd7cddfSDavid du Colombier winclose(Window *w)
2247dd7cddfSDavid du Colombier {
2257dd7cddfSDavid du Colombier 	int i;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 	if(decref(w) == 0){
2287dd7cddfSDavid du Colombier 		windirfree(w);
2297dd7cddfSDavid du Colombier 		textclose(&w->tag);
2307dd7cddfSDavid du Colombier 		textclose(&w->body);
2317dd7cddfSDavid du Colombier 		if(activewin == w)
2327dd7cddfSDavid du Colombier 			activewin = nil;
2337dd7cddfSDavid du Colombier 		for(i=0; i<w->nincl; i++)
2347dd7cddfSDavid du Colombier 			free(w->incl[i]);
2357dd7cddfSDavid du Colombier 		free(w->incl);
2367dd7cddfSDavid du Colombier 		free(w->events);
2377dd7cddfSDavid du Colombier 		free(w);
2387dd7cddfSDavid du Colombier 	}
2397dd7cddfSDavid du Colombier }
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier void
windelete(Window * w)2427dd7cddfSDavid du Colombier windelete(Window *w)
2437dd7cddfSDavid du Colombier {
2447dd7cddfSDavid du Colombier 	Xfid *x;
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	x = w->eventx;
2477dd7cddfSDavid du Colombier 	if(x){
2487dd7cddfSDavid du Colombier 		w->nevents = 0;
2497dd7cddfSDavid du Colombier 		free(w->events);
2507dd7cddfSDavid du Colombier 		w->events = nil;
2517dd7cddfSDavid du Colombier 		w->eventx = nil;
2527dd7cddfSDavid du Colombier 		sendp(x->c, nil);	/* wake him up */
2537dd7cddfSDavid du Colombier 	}
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier void
winundo(Window * w,int isundo)2577dd7cddfSDavid du Colombier winundo(Window *w, int isundo)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier 	Text *body;
2607dd7cddfSDavid du Colombier 	int i;
2617dd7cddfSDavid du Colombier 	File *f;
2627dd7cddfSDavid du Colombier 	Window *v;
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier 	w->utflastqid = -1;
2657dd7cddfSDavid du Colombier 	body = &w->body;
2667dd7cddfSDavid du Colombier 	fileundo(body->file, isundo, &body->q0, &body->q1);
2679a747e4fSDavid du Colombier 	textshow(body, body->q0, body->q1, 1);
2687dd7cddfSDavid du Colombier 	f = body->file;
2697dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++){
2707dd7cddfSDavid du Colombier 		v = f->text[i]->w;
2717dd7cddfSDavid du Colombier 		v->dirty = (f->seq != v->putseq);
2727dd7cddfSDavid du Colombier 		if(v != w){
2737dd7cddfSDavid du Colombier 			v->body.q0 = v->body.p0+v->body.org;
2747dd7cddfSDavid du Colombier 			v->body.q1 = v->body.p1+v->body.org;
2757dd7cddfSDavid du Colombier 		}
2767dd7cddfSDavid du Colombier 	}
2777dd7cddfSDavid du Colombier 	winsettag(w);
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier void
winsetname(Window * w,Rune * name,int n)2817dd7cddfSDavid du Colombier winsetname(Window *w, Rune *name, int n)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	Text *t;
2847dd7cddfSDavid du Colombier 	Window *v;
2857dd7cddfSDavid du Colombier 	int i;
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier 	t = &w->body;
2887dd7cddfSDavid du Colombier 	if(runeeq(t->file->name, t->file->nname, name, n) == TRUE)
2897dd7cddfSDavid du Colombier 		return;
2907dd7cddfSDavid du Colombier 	w->isscratch = FALSE;
2917dd7cddfSDavid du Colombier 	if(n>=6 && runeeq(L"/guide", 6, name+(n-6), 6))
2927dd7cddfSDavid du Colombier 		w->isscratch = TRUE;
2937dd7cddfSDavid du Colombier 	else if(n>=7 && runeeq(L"+Errors", 7, name+(n-7), 7))
2947dd7cddfSDavid du Colombier 		w->isscratch = TRUE;
2957dd7cddfSDavid du Colombier 	filesetname(t->file, name, n);
2967dd7cddfSDavid du Colombier 	for(i=0; i<t->file->ntext; i++){
2977dd7cddfSDavid du Colombier 		v = t->file->text[i]->w;
2987dd7cddfSDavid du Colombier 		winsettag(v);
2997dd7cddfSDavid du Colombier 		v->isscratch = w->isscratch;
3007dd7cddfSDavid du Colombier 	}
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier 
3037dd7cddfSDavid du Colombier void
wintype(Window * w,Text * t,Rune r)3047dd7cddfSDavid du Colombier wintype(Window *w, Text *t, Rune r)
3057dd7cddfSDavid du Colombier {
3067dd7cddfSDavid du Colombier 	int i;
3077dd7cddfSDavid du Colombier 
3087dd7cddfSDavid du Colombier 	texttype(t, r);
3097dd7cddfSDavid du Colombier 	if(t->what == Body)
3107dd7cddfSDavid du Colombier 		for(i=0; i<t->file->ntext; i++)
3117dd7cddfSDavid du Colombier 			textscrdraw(t->file->text[i]);
3127dd7cddfSDavid du Colombier 	winsettag(w);
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier 
3157dd7cddfSDavid du Colombier void
wincleartag(Window * w)3167dd7cddfSDavid du Colombier wincleartag(Window *w)
3177dd7cddfSDavid du Colombier {
3187dd7cddfSDavid du Colombier 	int i, n;
3197dd7cddfSDavid du Colombier 	Rune *r;
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier 	/* w must be committed */
3227dd7cddfSDavid du Colombier 	n = w->tag.file->nc;
3237dd7cddfSDavid du Colombier 	r = runemalloc(n);
3247dd7cddfSDavid du Colombier 	bufread(w->tag.file, 0, r, n);
3257dd7cddfSDavid du Colombier 	for(i=0; i<n; i++)
3267dd7cddfSDavid du Colombier 		if(r[i]==' ' || r[i]=='\t')
3277dd7cddfSDavid du Colombier 			break;
3287dd7cddfSDavid du Colombier 	for(; i<n; i++)
3297dd7cddfSDavid du Colombier 		if(r[i] == '|')
3307dd7cddfSDavid du Colombier 			break;
3317dd7cddfSDavid du Colombier 	if(i == n)
3327dd7cddfSDavid du Colombier 		return;
3337dd7cddfSDavid du Colombier 	i++;
3347dd7cddfSDavid du Colombier 	textdelete(&w->tag, i, n, TRUE);
3357dd7cddfSDavid du Colombier 	free(r);
3367dd7cddfSDavid du Colombier 	w->tag.file->mod = FALSE;
3377dd7cddfSDavid du Colombier 	if(w->tag.q0 > i)
3387dd7cddfSDavid du Colombier 		w->tag.q0 = i;
3397dd7cddfSDavid du Colombier 	if(w->tag.q1 > i)
3407dd7cddfSDavid du Colombier 		w->tag.q1 = i;
3417dd7cddfSDavid du Colombier 	textsetselect(&w->tag, w->tag.q0, w->tag.q1);
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier void
winsettag1(Window * w)3457dd7cddfSDavid du Colombier winsettag1(Window *w)
3467dd7cddfSDavid du Colombier {
3477dd7cddfSDavid du Colombier 	int i, j, k, n, bar, dirty;
3487dd7cddfSDavid du Colombier 	Rune *new, *old, *r;
3497dd7cddfSDavid du Colombier 	Image *b;
3507dd7cddfSDavid du Colombier 	uint q0, q1;
3517dd7cddfSDavid du Colombier 	Rectangle br;
3527dd7cddfSDavid du Colombier 
3537dd7cddfSDavid du Colombier 	/* there are races that get us here with stuff in the tag cache, so we take extra care to sync it */
3547dd7cddfSDavid du Colombier 	if(w->tag.ncache!=0 || w->tag.file->mod)
3557dd7cddfSDavid du Colombier 		wincommit(w, &w->tag);	/* check file name; also guarantees we can modify tag contents */
3567dd7cddfSDavid du Colombier 	old = runemalloc(w->tag.file->nc+1);
3577dd7cddfSDavid du Colombier 	bufread(w->tag.file, 0, old, w->tag.file->nc);
3587dd7cddfSDavid du Colombier 	old[w->tag.file->nc] = '\0';
3597dd7cddfSDavid du Colombier 	for(i=0; i<w->tag.file->nc; i++)
3607dd7cddfSDavid du Colombier 		if(old[i]==' ' || old[i]=='\t')
3617dd7cddfSDavid du Colombier 			break;
3627dd7cddfSDavid du Colombier 	if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE){
3637dd7cddfSDavid du Colombier 		textdelete(&w->tag, 0, i, TRUE);
3647dd7cddfSDavid du Colombier 		textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE);
3657dd7cddfSDavid du Colombier 		free(old);
3667dd7cddfSDavid du Colombier 		old = runemalloc(w->tag.file->nc+1);
3677dd7cddfSDavid du Colombier 		bufread(w->tag.file, 0, old, w->tag.file->nc);
3687dd7cddfSDavid du Colombier 		old[w->tag.file->nc] = '\0';
3697dd7cddfSDavid du Colombier 	}
3707dd7cddfSDavid du Colombier 	new = runemalloc(w->body.file->nname+100);
3717dd7cddfSDavid du Colombier 	i = 0;
3727dd7cddfSDavid du Colombier 	runemove(new+i, w->body.file->name, w->body.file->nname);
3737dd7cddfSDavid du Colombier 	i += w->body.file->nname;
3747dd7cddfSDavid du Colombier 	runemove(new+i, L" Del Snarf", 10);
3757dd7cddfSDavid du Colombier 	i += 10;
3767dd7cddfSDavid du Colombier 	if(w->filemenu){
3777dd7cddfSDavid du Colombier 		if(w->body.file->delta.nc>0 || w->body.ncache){
3787dd7cddfSDavid du Colombier 			runemove(new+i, L" Undo", 5);
3797dd7cddfSDavid du Colombier 			i += 5;
3807dd7cddfSDavid du Colombier 		}
3817dd7cddfSDavid du Colombier 		if(w->body.file->epsilon.nc > 0){
3827dd7cddfSDavid du Colombier 			runemove(new+i, L" Redo", 5);
3837dd7cddfSDavid du Colombier 			i += 5;
3847dd7cddfSDavid du Colombier 		}
3857dd7cddfSDavid du Colombier 		dirty = w->body.file->nname && (w->body.ncache || w->body.file->seq!=w->putseq);
3867dd7cddfSDavid du Colombier 		if(!w->isdir && dirty){
3877dd7cddfSDavid du Colombier 			runemove(new+i, L" Put", 4);
3887dd7cddfSDavid du Colombier 			i += 4;
3897dd7cddfSDavid du Colombier 		}
3907dd7cddfSDavid du Colombier 	}
3917dd7cddfSDavid du Colombier 	if(w->isdir){
3927dd7cddfSDavid du Colombier 		runemove(new+i, L" Get", 4);
3937dd7cddfSDavid du Colombier 		i += 4;
3947dd7cddfSDavid du Colombier 	}
3957dd7cddfSDavid du Colombier 	runemove(new+i, L" |", 2);
3967dd7cddfSDavid du Colombier 	i += 2;
39759cc4ca5SDavid du Colombier 	r = runestrchr(old, '|');
3987dd7cddfSDavid du Colombier 	if(r)
3997dd7cddfSDavid du Colombier 		k = r-old+1;
4007dd7cddfSDavid du Colombier 	else{
4017dd7cddfSDavid du Colombier 		k = w->tag.file->nc;
4027dd7cddfSDavid du Colombier 		if(w->body.file->seq == 0){
4037dd7cddfSDavid du Colombier 			runemove(new+i, L" Look ", 6);
4047dd7cddfSDavid du Colombier 			i += 6;
4057dd7cddfSDavid du Colombier 		}
4067dd7cddfSDavid du Colombier 	}
4077dd7cddfSDavid du Colombier 	if(runeeq(new, i, old, k) == FALSE){
4087dd7cddfSDavid du Colombier 		n = k;
4097dd7cddfSDavid du Colombier 		if(n > i)
4107dd7cddfSDavid du Colombier 			n = i;
4117dd7cddfSDavid du Colombier 		for(j=0; j<n; j++)
4127dd7cddfSDavid du Colombier 			if(old[j] != new[j])
4137dd7cddfSDavid du Colombier 				break;
4147dd7cddfSDavid du Colombier 		q0 = w->tag.q0;
4157dd7cddfSDavid du Colombier 		q1 = w->tag.q1;
4167dd7cddfSDavid du Colombier 		textdelete(&w->tag, j, k, TRUE);
4177dd7cddfSDavid du Colombier 		textinsert(&w->tag, j, new+j, i-j, TRUE);
4187dd7cddfSDavid du Colombier 		/* try to preserve user selection */
41959cc4ca5SDavid du Colombier 		r = runestrchr(old, '|');
4207dd7cddfSDavid du Colombier 		if(r){
4217dd7cddfSDavid du Colombier 			bar = r-old;
4227dd7cddfSDavid du Colombier 			if(q0 > bar){
42359cc4ca5SDavid du Colombier 				bar = (runestrchr(new, '|')-new)-bar;
4247dd7cddfSDavid du Colombier 				w->tag.q0 = q0+bar;
4257dd7cddfSDavid du Colombier 				w->tag.q1 = q1+bar;
4267dd7cddfSDavid du Colombier 			}
4277dd7cddfSDavid du Colombier 		}
4287dd7cddfSDavid du Colombier 	}
4297dd7cddfSDavid du Colombier 	free(old);
4307dd7cddfSDavid du Colombier 	free(new);
4317dd7cddfSDavid du Colombier 	w->tag.file->mod = FALSE;
4327dd7cddfSDavid du Colombier 	n = w->tag.file->nc+w->tag.ncache;
4337dd7cddfSDavid du Colombier 	if(w->tag.q0 > n)
4347dd7cddfSDavid du Colombier 		w->tag.q0 = n;
4357dd7cddfSDavid du Colombier 	if(w->tag.q1 > n)
4367dd7cddfSDavid du Colombier 		w->tag.q1 = n;
4377dd7cddfSDavid du Colombier 	textsetselect(&w->tag, w->tag.q0, w->tag.q1);
4387dd7cddfSDavid du Colombier 	b = button;
4397dd7cddfSDavid du Colombier 	if(!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache))
4407dd7cddfSDavid du Colombier 		b = modbutton;
4417dd7cddfSDavid du Colombier 	br.min = w->tag.scrollr.min;
4427dd7cddfSDavid du Colombier 	br.max.x = br.min.x + Dx(b->r);
4437dd7cddfSDavid du Colombier 	br.max.y = br.min.y + Dy(b->r);
4447dd7cddfSDavid du Colombier 	draw(screen, br, b, nil, b->r.min);
4457dd7cddfSDavid du Colombier }
4467dd7cddfSDavid du Colombier 
4477dd7cddfSDavid du Colombier void
winsettag(Window * w)4487dd7cddfSDavid du Colombier winsettag(Window *w)
4497dd7cddfSDavid du Colombier {
4507dd7cddfSDavid du Colombier 	int i;
4517dd7cddfSDavid du Colombier 	File *f;
4527dd7cddfSDavid du Colombier 	Window *v;
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier 	f = w->body.file;
4557dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++){
4567dd7cddfSDavid du Colombier 		v = f->text[i]->w;
4577dd7cddfSDavid du Colombier 		if(v->col->safe || v->body.maxlines>0)
4587dd7cddfSDavid du Colombier 			winsettag1(v);
4597dd7cddfSDavid du Colombier 	}
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier void
wincommit(Window * w,Text * t)4637dd7cddfSDavid du Colombier wincommit(Window *w, Text *t)
4647dd7cddfSDavid du Colombier {
4657dd7cddfSDavid du Colombier 	Rune *r;
4667dd7cddfSDavid du Colombier 	int i;
4677dd7cddfSDavid du Colombier 	File *f;
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier 	textcommit(t, TRUE);
4707dd7cddfSDavid du Colombier 	f = t->file;
4717dd7cddfSDavid du Colombier 	if(f->ntext > 1)
4727dd7cddfSDavid du Colombier 		for(i=0; i<f->ntext; i++)
4737dd7cddfSDavid du Colombier 			textcommit(f->text[i], FALSE);	/* no-op for t */
4747dd7cddfSDavid du Colombier 	if(t->what == Body)
4757dd7cddfSDavid du Colombier 		return;
4767dd7cddfSDavid du Colombier 	r = runemalloc(w->tag.file->nc);
4777dd7cddfSDavid du Colombier 	bufread(w->tag.file, 0, r, w->tag.file->nc);
4787dd7cddfSDavid du Colombier 	for(i=0; i<w->tag.file->nc; i++)
4797dd7cddfSDavid du Colombier 		if(r[i]==' ' || r[i]=='\t')
4807dd7cddfSDavid du Colombier 			break;
4817dd7cddfSDavid du Colombier 	if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE){
4827dd7cddfSDavid du Colombier 		seq++;
4837dd7cddfSDavid du Colombier 		filemark(w->body.file);
4847dd7cddfSDavid du Colombier 		w->body.file->mod = TRUE;
4857dd7cddfSDavid du Colombier 		w->dirty = TRUE;
4867dd7cddfSDavid du Colombier 		winsetname(w, r, i);
4877dd7cddfSDavid du Colombier 		winsettag(w);
4887dd7cddfSDavid du Colombier 	}
4897dd7cddfSDavid du Colombier 	free(r);
4907dd7cddfSDavid du Colombier }
4917dd7cddfSDavid du Colombier 
4927dd7cddfSDavid du Colombier void
winaddincl(Window * w,Rune * r,int n)4937dd7cddfSDavid du Colombier winaddincl(Window *w, Rune *r, int n)
4947dd7cddfSDavid du Colombier {
4957dd7cddfSDavid du Colombier 	char *a;
4969a747e4fSDavid du Colombier 	Dir *d;
4977dd7cddfSDavid du Colombier 	Runestr rs;
4987dd7cddfSDavid du Colombier 
4997dd7cddfSDavid du Colombier 	a = runetobyte(r, n);
5009a747e4fSDavid du Colombier 	d = dirstat(a);
5019a747e4fSDavid du Colombier 	if(d == nil){
5027dd7cddfSDavid du Colombier 		if(a[0] == '/')
5037dd7cddfSDavid du Colombier 			goto Rescue;
5047dd7cddfSDavid du Colombier 		rs = dirname(&w->body, r, n);
5057dd7cddfSDavid du Colombier 		r = rs.r;
5067dd7cddfSDavid du Colombier 		n = rs.nr;
5077dd7cddfSDavid du Colombier 		free(a);
5087dd7cddfSDavid du Colombier 		a = runetobyte(r, n);
5099a747e4fSDavid du Colombier 		d = dirstat(a);
5109a747e4fSDavid du Colombier 		if(d == nil)
5117dd7cddfSDavid du Colombier 			goto Rescue;
5127dd7cddfSDavid du Colombier 		r = runerealloc(r, n+1);
5137dd7cddfSDavid du Colombier 		r[n] = 0;
5147dd7cddfSDavid du Colombier 	}
5157dd7cddfSDavid du Colombier 	free(a);
5169a747e4fSDavid du Colombier 	if((d->qid.type&QTDIR) == 0){
5179a747e4fSDavid du Colombier 		free(d);
5187dd7cddfSDavid du Colombier 		warning(nil, "%s: not a directory\n", a);
5197dd7cddfSDavid du Colombier 		free(r);
5207dd7cddfSDavid du Colombier 		return;
5217dd7cddfSDavid du Colombier 	}
5229a747e4fSDavid du Colombier 	free(d);
5237dd7cddfSDavid du Colombier 	w->nincl++;
5247dd7cddfSDavid du Colombier 	w->incl = realloc(w->incl, w->nincl*sizeof(Rune*));
5257dd7cddfSDavid du Colombier 	memmove(w->incl+1, w->incl, (w->nincl-1)*sizeof(Rune*));
5267dd7cddfSDavid du Colombier 	w->incl[0] = runemalloc(n+1);
5277dd7cddfSDavid du Colombier 	runemove(w->incl[0], r, n);
5287dd7cddfSDavid du Colombier 	free(r);
5297dd7cddfSDavid du Colombier 	return;
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier Rescue:
5327dd7cddfSDavid du Colombier 	warning(nil, "%s: %r\n", a);
5337dd7cddfSDavid du Colombier 	free(r);
5347dd7cddfSDavid du Colombier 	free(a);
5357dd7cddfSDavid du Colombier 	return;
5367dd7cddfSDavid du Colombier }
5377dd7cddfSDavid du Colombier 
5387dd7cddfSDavid du Colombier int
winclean(Window * w,int conservative)5397dd7cddfSDavid du Colombier winclean(Window *w, int conservative)	/* as it stands, conservative is always TRUE */
5407dd7cddfSDavid du Colombier {
5417dd7cddfSDavid du Colombier 	if(w->isscratch || w->isdir)	/* don't whine if it's a guide file, error window, etc. */
5427dd7cddfSDavid du Colombier 		return TRUE;
5437dd7cddfSDavid du Colombier 	if(!conservative && w->nopen[QWevent]>0)
5447dd7cddfSDavid du Colombier 		return TRUE;
5457dd7cddfSDavid du Colombier 	if(w->dirty){
5467dd7cddfSDavid du Colombier 		if(w->body.file->nname)
5477dd7cddfSDavid du Colombier 			warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name);
5487dd7cddfSDavid du Colombier 		else{
5497dd7cddfSDavid du Colombier 			if(w->body.file->nc < 100)	/* don't whine if it's too small */
5507dd7cddfSDavid du Colombier 				return TRUE;
5517dd7cddfSDavid du Colombier 			warning(nil, "unnamed file modified\n");
5527dd7cddfSDavid du Colombier 		}
5537dd7cddfSDavid du Colombier 		w->dirty = FALSE;
5547dd7cddfSDavid du Colombier 		return FALSE;
5557dd7cddfSDavid du Colombier 	}
5567dd7cddfSDavid du Colombier 	return TRUE;
5577dd7cddfSDavid du Colombier }
5587dd7cddfSDavid du Colombier 
5598a2c5ad0SDavid du Colombier char*
winctlprint(Window * w,char * buf,int fonts)5609a747e4fSDavid du Colombier winctlprint(Window *w, char *buf, int fonts)
5617dd7cddfSDavid du Colombier {
5628a2c5ad0SDavid du Colombier 	sprint(buf, "%11d %11d %11d %11d %11d ", w->id, w->tag.file->nc,
5637dd7cddfSDavid du Colombier 		w->body.file->nc, w->isdir, w->dirty);
5649a747e4fSDavid du Colombier 	if(fonts)
5658a2c5ad0SDavid du Colombier 		return smprint("%s%11d %q %11d " , buf, Dx(w->body.r),
5668a2c5ad0SDavid du Colombier 			w->body.reffont->f->name, w->body.maxtab);
5678a2c5ad0SDavid du Colombier 	return buf;
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier void
winevent(Window * w,char * fmt,...)5717dd7cddfSDavid du Colombier winevent(Window *w, char *fmt, ...)
5727dd7cddfSDavid du Colombier {
5737dd7cddfSDavid du Colombier 	int n;
5747dd7cddfSDavid du Colombier 	char *b;
5757dd7cddfSDavid du Colombier 	Xfid *x;
5767dd7cddfSDavid du Colombier 	va_list arg;
5777dd7cddfSDavid du Colombier 
5787dd7cddfSDavid du Colombier 	if(w->nopen[QWevent] == 0)
5797dd7cddfSDavid du Colombier 		return;
5807dd7cddfSDavid du Colombier 	if(w->owner == 0)
5817dd7cddfSDavid du Colombier 		error("no window owner");
5827dd7cddfSDavid du Colombier 	va_start(arg, fmt);
5839a747e4fSDavid du Colombier 	b = vsmprint(fmt, arg);
5847dd7cddfSDavid du Colombier 	va_end(arg);
5859a747e4fSDavid du Colombier 	if(b == nil)
5869a747e4fSDavid du Colombier 		error("vsmprint failed");
5879a747e4fSDavid du Colombier 	n = strlen(b);
5887dd7cddfSDavid du Colombier 	w->events = realloc(w->events, w->nevents+1+n);
5897dd7cddfSDavid du Colombier 	w->events[w->nevents++] = w->owner;
5907dd7cddfSDavid du Colombier 	memmove(w->events+w->nevents, b, n);
5919a747e4fSDavid du Colombier 	free(b);
5927dd7cddfSDavid du Colombier 	w->nevents += n;
5937dd7cddfSDavid du Colombier 	x = w->eventx;
5947dd7cddfSDavid du Colombier 	if(x){
5957dd7cddfSDavid du Colombier 		w->eventx = nil;
5967dd7cddfSDavid du Colombier 		sendp(x->c, nil);
5977dd7cddfSDavid du Colombier 	}
5987dd7cddfSDavid du Colombier }
599