xref: /plan9/sys/src/cmd/acme/wind.c (revision a30303ef3ee662b532d68ad7e5cb756bf7e0736d)
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
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;
77*a30303efSDavid 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);
82*a30303efSDavid du Colombier 		w->autoindent = clone->autoindent;
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier int
877dd7cddfSDavid du Colombier winresize(Window *w, Rectangle r, int safe)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier 	Rectangle r1;
907dd7cddfSDavid du Colombier 	int y;
917dd7cddfSDavid du Colombier 	Image *b;
927dd7cddfSDavid du Colombier 	Rectangle br;
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	r1 = r;
957dd7cddfSDavid du Colombier 	r1.max.y = r1.min.y + font->height;
967dd7cddfSDavid du Colombier 	y = r1.max.y;
977dd7cddfSDavid du Colombier 	if(!safe || !eqrect(w->tag.r, r1)){
987dd7cddfSDavid du Colombier 		y = textresize(&w->tag, r1);
997dd7cddfSDavid du Colombier 		b = button;
1007dd7cddfSDavid du Colombier 		if(w->body.file->mod && !w->isdir && !w->isscratch)
1017dd7cddfSDavid du Colombier 			b = modbutton;
1027dd7cddfSDavid du Colombier 		br.min = w->tag.scrollr.min;
1037dd7cddfSDavid du Colombier 		br.max.x = br.min.x + Dx(b->r);
1047dd7cddfSDavid du Colombier 		br.max.y = br.min.y + Dy(b->r);
1057dd7cddfSDavid du Colombier 		draw(screen, br, b, nil, b->r.min);
1067dd7cddfSDavid du Colombier 	}
1077dd7cddfSDavid du Colombier 	if(!safe || !eqrect(w->body.r, r1)){
1087dd7cddfSDavid du Colombier 		if(y+1+font->height > r.max.y){		/* no body */
1097dd7cddfSDavid du Colombier 			r1.min.y = y;
1107dd7cddfSDavid du Colombier 			r1.max.y = y;
1117dd7cddfSDavid du Colombier 			textresize(&w->body, r1);
1127dd7cddfSDavid du Colombier 			w->r = r;
1137dd7cddfSDavid du Colombier 			w->r.max.y = y;
1147dd7cddfSDavid du Colombier 			return y;
1157dd7cddfSDavid du Colombier 		}
1167dd7cddfSDavid du Colombier 		r1 = r;
1177dd7cddfSDavid du Colombier 		r1.min.y = y;
1187dd7cddfSDavid du Colombier 		r1.max.y = y + 1;
1197dd7cddfSDavid du Colombier 		draw(screen, r1, tagcols[BORD], nil, ZP);
1207dd7cddfSDavid du Colombier 		r1.min.y = y + 1;
1217dd7cddfSDavid du Colombier 		r1.max.y = r.max.y;
1227dd7cddfSDavid du Colombier 		y = textresize(&w->body, r1);
1237dd7cddfSDavid du Colombier 		w->r = r;
1247dd7cddfSDavid du Colombier 		w->r.max.y = y;
1257dd7cddfSDavid du Colombier 		textscrdraw(&w->body);
1267dd7cddfSDavid du Colombier 	}
1277dd7cddfSDavid du Colombier 	w->maxlines = min(w->body.nlines, max(w->maxlines, w->body.maxlines));
1287dd7cddfSDavid du Colombier 	return w->r.max.y;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier void
1327dd7cddfSDavid du Colombier winlock1(Window *w, int owner)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier 	incref(w);
1357dd7cddfSDavid du Colombier 	qlock(w);
1367dd7cddfSDavid du Colombier 	w->owner = owner;
1377dd7cddfSDavid du Colombier }
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier void
1407dd7cddfSDavid du Colombier winlock(Window *w, int owner)
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier 	int i;
1437dd7cddfSDavid du Colombier 	File *f;
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier 	f = w->body.file;
1467dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++)
1477dd7cddfSDavid du Colombier 		winlock1(f->text[i]->w, owner);
1487dd7cddfSDavid du Colombier }
1497dd7cddfSDavid du Colombier 
1507dd7cddfSDavid du Colombier void
1517dd7cddfSDavid du Colombier winunlock(Window *w)
1527dd7cddfSDavid du Colombier {
1537dd7cddfSDavid du Colombier 	int i;
1547dd7cddfSDavid du Colombier 	File *f;
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 	f = w->body.file;
1577dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++){
1587dd7cddfSDavid du Colombier 		w = f->text[i]->w;
1597dd7cddfSDavid du Colombier 		w->owner = 0;
1607dd7cddfSDavid du Colombier 		qunlock(w);
1617dd7cddfSDavid du Colombier 		winclose(w);
1627dd7cddfSDavid du Colombier 		/* winclose() can change up f->text; beware */
1637dd7cddfSDavid du Colombier 		if(f->ntext>0 && w != f->text[i]->w)
1647dd7cddfSDavid du Colombier 			--i;	/* winclose() deleted window */
1657dd7cddfSDavid du Colombier 	}
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier void
1697dd7cddfSDavid du Colombier winmousebut(Window *w)
1707dd7cddfSDavid du Colombier {
1717dd7cddfSDavid du Colombier 	moveto(mousectl, divpt(addpt(w->tag.scrollr.min, w->tag.scrollr.max), 2));
1727dd7cddfSDavid du Colombier }
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier void
1757dd7cddfSDavid du Colombier windirfree(Window *w)
1767dd7cddfSDavid du Colombier {
1777dd7cddfSDavid du Colombier 	int i;
1787dd7cddfSDavid du Colombier 	Dirlist *dl;
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 	if(w->isdir){
1817dd7cddfSDavid du Colombier 		for(i=0; i<w->ndl; i++){
1827dd7cddfSDavid du Colombier 			dl = w->dlp[i];
1837dd7cddfSDavid du Colombier 			free(dl->r);
1847dd7cddfSDavid du Colombier 			free(dl);
1857dd7cddfSDavid du Colombier 		}
1867dd7cddfSDavid du Colombier 		free(w->dlp);
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier 	w->dlp = nil;
1897dd7cddfSDavid du Colombier 	w->ndl = 0;
1907dd7cddfSDavid du Colombier }
1917dd7cddfSDavid du Colombier 
1927dd7cddfSDavid du Colombier void
1937dd7cddfSDavid du Colombier winclose(Window *w)
1947dd7cddfSDavid du Colombier {
1957dd7cddfSDavid du Colombier 	int i;
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	if(decref(w) == 0){
1987dd7cddfSDavid du Colombier 		windirfree(w);
1997dd7cddfSDavid du Colombier 		textclose(&w->tag);
2007dd7cddfSDavid du Colombier 		textclose(&w->body);
2017dd7cddfSDavid du Colombier 		if(activewin == w)
2027dd7cddfSDavid du Colombier 			activewin = nil;
2037dd7cddfSDavid du Colombier 		for(i=0; i<w->nincl; i++)
2047dd7cddfSDavid du Colombier 			free(w->incl[i]);
2057dd7cddfSDavid du Colombier 		free(w->incl);
2067dd7cddfSDavid du Colombier 		free(w->events);
2077dd7cddfSDavid du Colombier 		free(w);
2087dd7cddfSDavid du Colombier 	}
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier void
2127dd7cddfSDavid du Colombier windelete(Window *w)
2137dd7cddfSDavid du Colombier {
2147dd7cddfSDavid du Colombier 	Xfid *x;
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier 	x = w->eventx;
2177dd7cddfSDavid du Colombier 	if(x){
2187dd7cddfSDavid du Colombier 		w->nevents = 0;
2197dd7cddfSDavid du Colombier 		free(w->events);
2207dd7cddfSDavid du Colombier 		w->events = nil;
2217dd7cddfSDavid du Colombier 		w->eventx = nil;
2227dd7cddfSDavid du Colombier 		sendp(x->c, nil);	/* wake him up */
2237dd7cddfSDavid du Colombier 	}
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier void
2277dd7cddfSDavid du Colombier winundo(Window *w, int isundo)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier 	Text *body;
2307dd7cddfSDavid du Colombier 	int i;
2317dd7cddfSDavid du Colombier 	File *f;
2327dd7cddfSDavid du Colombier 	Window *v;
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	w->utflastqid = -1;
2357dd7cddfSDavid du Colombier 	body = &w->body;
2367dd7cddfSDavid du Colombier 	fileundo(body->file, isundo, &body->q0, &body->q1);
2379a747e4fSDavid du Colombier 	textshow(body, body->q0, body->q1, 1);
2387dd7cddfSDavid du Colombier 	f = body->file;
2397dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++){
2407dd7cddfSDavid du Colombier 		v = f->text[i]->w;
2417dd7cddfSDavid du Colombier 		v->dirty = (f->seq != v->putseq);
2427dd7cddfSDavid du Colombier 		if(v != w){
2437dd7cddfSDavid du Colombier 			v->body.q0 = v->body.p0+v->body.org;
2447dd7cddfSDavid du Colombier 			v->body.q1 = v->body.p1+v->body.org;
2457dd7cddfSDavid du Colombier 		}
2467dd7cddfSDavid du Colombier 	}
2477dd7cddfSDavid du Colombier 	winsettag(w);
2487dd7cddfSDavid du Colombier }
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier void
2517dd7cddfSDavid du Colombier winsetname(Window *w, Rune *name, int n)
2527dd7cddfSDavid du Colombier {
2537dd7cddfSDavid du Colombier 	Text *t;
2547dd7cddfSDavid du Colombier 	Window *v;
2557dd7cddfSDavid du Colombier 	int i;
2567dd7cddfSDavid du Colombier 
2577dd7cddfSDavid du Colombier 	t = &w->body;
2587dd7cddfSDavid du Colombier 	if(runeeq(t->file->name, t->file->nname, name, n) == TRUE)
2597dd7cddfSDavid du Colombier 		return;
2607dd7cddfSDavid du Colombier 	w->isscratch = FALSE;
2617dd7cddfSDavid du Colombier 	if(n>=6 && runeeq(L"/guide", 6, name+(n-6), 6))
2627dd7cddfSDavid du Colombier 		w->isscratch = TRUE;
2637dd7cddfSDavid du Colombier 	else if(n>=7 && runeeq(L"+Errors", 7, name+(n-7), 7))
2647dd7cddfSDavid du Colombier 		w->isscratch = TRUE;
2657dd7cddfSDavid du Colombier 	filesetname(t->file, name, n);
2667dd7cddfSDavid du Colombier 	for(i=0; i<t->file->ntext; i++){
2677dd7cddfSDavid du Colombier 		v = t->file->text[i]->w;
2687dd7cddfSDavid du Colombier 		winsettag(v);
2697dd7cddfSDavid du Colombier 		v->isscratch = w->isscratch;
2707dd7cddfSDavid du Colombier 	}
2717dd7cddfSDavid du Colombier }
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier void
2747dd7cddfSDavid du Colombier wintype(Window *w, Text *t, Rune r)
2757dd7cddfSDavid du Colombier {
2767dd7cddfSDavid du Colombier 	int i;
2777dd7cddfSDavid du Colombier 
2787dd7cddfSDavid du Colombier 	texttype(t, r);
2797dd7cddfSDavid du Colombier 	if(t->what == Body)
2807dd7cddfSDavid du Colombier 		for(i=0; i<t->file->ntext; i++)
2817dd7cddfSDavid du Colombier 			textscrdraw(t->file->text[i]);
2827dd7cddfSDavid du Colombier 	winsettag(w);
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier void
2867dd7cddfSDavid du Colombier wincleartag(Window *w)
2877dd7cddfSDavid du Colombier {
2887dd7cddfSDavid du Colombier 	int i, n;
2897dd7cddfSDavid du Colombier 	Rune *r;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier 	/* w must be committed */
2927dd7cddfSDavid du Colombier 	n = w->tag.file->nc;
2937dd7cddfSDavid du Colombier 	r = runemalloc(n);
2947dd7cddfSDavid du Colombier 	bufread(w->tag.file, 0, r, n);
2957dd7cddfSDavid du Colombier 	for(i=0; i<n; i++)
2967dd7cddfSDavid du Colombier 		if(r[i]==' ' || r[i]=='\t')
2977dd7cddfSDavid du Colombier 			break;
2987dd7cddfSDavid du Colombier 	for(; i<n; i++)
2997dd7cddfSDavid du Colombier 		if(r[i] == '|')
3007dd7cddfSDavid du Colombier 			break;
3017dd7cddfSDavid du Colombier 	if(i == n)
3027dd7cddfSDavid du Colombier 		return;
3037dd7cddfSDavid du Colombier 	i++;
3047dd7cddfSDavid du Colombier 	textdelete(&w->tag, i, n, TRUE);
3057dd7cddfSDavid du Colombier 	free(r);
3067dd7cddfSDavid du Colombier 	w->tag.file->mod = FALSE;
3077dd7cddfSDavid du Colombier 	if(w->tag.q0 > i)
3087dd7cddfSDavid du Colombier 		w->tag.q0 = i;
3097dd7cddfSDavid du Colombier 	if(w->tag.q1 > i)
3107dd7cddfSDavid du Colombier 		w->tag.q1 = i;
3117dd7cddfSDavid du Colombier 	textsetselect(&w->tag, w->tag.q0, w->tag.q1);
3127dd7cddfSDavid du Colombier }
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier void
3157dd7cddfSDavid du Colombier winsettag1(Window *w)
3167dd7cddfSDavid du Colombier {
3177dd7cddfSDavid du Colombier 	int i, j, k, n, bar, dirty;
3187dd7cddfSDavid du Colombier 	Rune *new, *old, *r;
3197dd7cddfSDavid du Colombier 	Image *b;
3207dd7cddfSDavid du Colombier 	uint q0, q1;
3217dd7cddfSDavid du Colombier 	Rectangle br;
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 	/* there are races that get us here with stuff in the tag cache, so we take extra care to sync it */
3247dd7cddfSDavid du Colombier 	if(w->tag.ncache!=0 || w->tag.file->mod)
3257dd7cddfSDavid du Colombier 		wincommit(w, &w->tag);	/* check file name; also guarantees we can modify tag contents */
3267dd7cddfSDavid du Colombier 	old = runemalloc(w->tag.file->nc+1);
3277dd7cddfSDavid du Colombier 	bufread(w->tag.file, 0, old, w->tag.file->nc);
3287dd7cddfSDavid du Colombier 	old[w->tag.file->nc] = '\0';
3297dd7cddfSDavid du Colombier 	for(i=0; i<w->tag.file->nc; i++)
3307dd7cddfSDavid du Colombier 		if(old[i]==' ' || old[i]=='\t')
3317dd7cddfSDavid du Colombier 			break;
3327dd7cddfSDavid du Colombier 	if(runeeq(old, i, w->body.file->name, w->body.file->nname) == FALSE){
3337dd7cddfSDavid du Colombier 		textdelete(&w->tag, 0, i, TRUE);
3347dd7cddfSDavid du Colombier 		textinsert(&w->tag, 0, w->body.file->name, w->body.file->nname, TRUE);
3357dd7cddfSDavid du Colombier 		free(old);
3367dd7cddfSDavid du Colombier 		old = runemalloc(w->tag.file->nc+1);
3377dd7cddfSDavid du Colombier 		bufread(w->tag.file, 0, old, w->tag.file->nc);
3387dd7cddfSDavid du Colombier 		old[w->tag.file->nc] = '\0';
3397dd7cddfSDavid du Colombier 	}
3407dd7cddfSDavid du Colombier 	new = runemalloc(w->body.file->nname+100);
3417dd7cddfSDavid du Colombier 	i = 0;
3427dd7cddfSDavid du Colombier 	runemove(new+i, w->body.file->name, w->body.file->nname);
3437dd7cddfSDavid du Colombier 	i += w->body.file->nname;
3447dd7cddfSDavid du Colombier 	runemove(new+i, L" Del Snarf", 10);
3457dd7cddfSDavid du Colombier 	i += 10;
3467dd7cddfSDavid du Colombier 	if(w->filemenu){
3477dd7cddfSDavid du Colombier 		if(w->body.file->delta.nc>0 || w->body.ncache){
3487dd7cddfSDavid du Colombier 			runemove(new+i, L" Undo", 5);
3497dd7cddfSDavid du Colombier 			i += 5;
3507dd7cddfSDavid du Colombier 		}
3517dd7cddfSDavid du Colombier 		if(w->body.file->epsilon.nc > 0){
3527dd7cddfSDavid du Colombier 			runemove(new+i, L" Redo", 5);
3537dd7cddfSDavid du Colombier 			i += 5;
3547dd7cddfSDavid du Colombier 		}
3557dd7cddfSDavid du Colombier 		dirty = w->body.file->nname && (w->body.ncache || w->body.file->seq!=w->putseq);
3567dd7cddfSDavid du Colombier 		if(!w->isdir && dirty){
3577dd7cddfSDavid du Colombier 			runemove(new+i, L" Put", 4);
3587dd7cddfSDavid du Colombier 			i += 4;
3597dd7cddfSDavid du Colombier 		}
3607dd7cddfSDavid du Colombier 	}
3617dd7cddfSDavid du Colombier 	if(w->isdir){
3627dd7cddfSDavid du Colombier 		runemove(new+i, L" Get", 4);
3637dd7cddfSDavid du Colombier 		i += 4;
3647dd7cddfSDavid du Colombier 	}
3657dd7cddfSDavid du Colombier 	runemove(new+i, L" |", 2);
3667dd7cddfSDavid du Colombier 	i += 2;
36759cc4ca5SDavid du Colombier 	r = runestrchr(old, '|');
3687dd7cddfSDavid du Colombier 	if(r)
3697dd7cddfSDavid du Colombier 		k = r-old+1;
3707dd7cddfSDavid du Colombier 	else{
3717dd7cddfSDavid du Colombier 		k = w->tag.file->nc;
3727dd7cddfSDavid du Colombier 		if(w->body.file->seq == 0){
3737dd7cddfSDavid du Colombier 			runemove(new+i, L" Look ", 6);
3747dd7cddfSDavid du Colombier 			i += 6;
3757dd7cddfSDavid du Colombier 		}
3767dd7cddfSDavid du Colombier 	}
3777dd7cddfSDavid du Colombier 	if(runeeq(new, i, old, k) == FALSE){
3787dd7cddfSDavid du Colombier 		n = k;
3797dd7cddfSDavid du Colombier 		if(n > i)
3807dd7cddfSDavid du Colombier 			n = i;
3817dd7cddfSDavid du Colombier 		for(j=0; j<n; j++)
3827dd7cddfSDavid du Colombier 			if(old[j] != new[j])
3837dd7cddfSDavid du Colombier 				break;
3847dd7cddfSDavid du Colombier 		q0 = w->tag.q0;
3857dd7cddfSDavid du Colombier 		q1 = w->tag.q1;
3867dd7cddfSDavid du Colombier 		textdelete(&w->tag, j, k, TRUE);
3877dd7cddfSDavid du Colombier 		textinsert(&w->tag, j, new+j, i-j, TRUE);
3887dd7cddfSDavid du Colombier 		/* try to preserve user selection */
38959cc4ca5SDavid du Colombier 		r = runestrchr(old, '|');
3907dd7cddfSDavid du Colombier 		if(r){
3917dd7cddfSDavid du Colombier 			bar = r-old;
3927dd7cddfSDavid du Colombier 			if(q0 > bar){
39359cc4ca5SDavid du Colombier 				bar = (runestrchr(new, '|')-new)-bar;
3947dd7cddfSDavid du Colombier 				w->tag.q0 = q0+bar;
3957dd7cddfSDavid du Colombier 				w->tag.q1 = q1+bar;
3967dd7cddfSDavid du Colombier 			}
3977dd7cddfSDavid du Colombier 		}
3987dd7cddfSDavid du Colombier 	}
3997dd7cddfSDavid du Colombier 	free(old);
4007dd7cddfSDavid du Colombier 	free(new);
4017dd7cddfSDavid du Colombier 	w->tag.file->mod = FALSE;
4027dd7cddfSDavid du Colombier 	n = w->tag.file->nc+w->tag.ncache;
4037dd7cddfSDavid du Colombier 	if(w->tag.q0 > n)
4047dd7cddfSDavid du Colombier 		w->tag.q0 = n;
4057dd7cddfSDavid du Colombier 	if(w->tag.q1 > n)
4067dd7cddfSDavid du Colombier 		w->tag.q1 = n;
4077dd7cddfSDavid du Colombier 	textsetselect(&w->tag, w->tag.q0, w->tag.q1);
4087dd7cddfSDavid du Colombier 	b = button;
4097dd7cddfSDavid du Colombier 	if(!w->isdir && !w->isscratch && (w->body.file->mod || w->body.ncache))
4107dd7cddfSDavid du Colombier 		b = modbutton;
4117dd7cddfSDavid du Colombier 	br.min = w->tag.scrollr.min;
4127dd7cddfSDavid du Colombier 	br.max.x = br.min.x + Dx(b->r);
4137dd7cddfSDavid du Colombier 	br.max.y = br.min.y + Dy(b->r);
4147dd7cddfSDavid du Colombier 	draw(screen, br, b, nil, b->r.min);
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier void
4187dd7cddfSDavid du Colombier winsettag(Window *w)
4197dd7cddfSDavid du Colombier {
4207dd7cddfSDavid du Colombier 	int i;
4217dd7cddfSDavid du Colombier 	File *f;
4227dd7cddfSDavid du Colombier 	Window *v;
4237dd7cddfSDavid du Colombier 
4247dd7cddfSDavid du Colombier 	f = w->body.file;
4257dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++){
4267dd7cddfSDavid du Colombier 		v = f->text[i]->w;
4277dd7cddfSDavid du Colombier 		if(v->col->safe || v->body.maxlines>0)
4287dd7cddfSDavid du Colombier 			winsettag1(v);
4297dd7cddfSDavid du Colombier 	}
4307dd7cddfSDavid du Colombier }
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier void
4337dd7cddfSDavid du Colombier wincommit(Window *w, Text *t)
4347dd7cddfSDavid du Colombier {
4357dd7cddfSDavid du Colombier 	Rune *r;
4367dd7cddfSDavid du Colombier 	int i;
4377dd7cddfSDavid du Colombier 	File *f;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier 	textcommit(t, TRUE);
4407dd7cddfSDavid du Colombier 	f = t->file;
4417dd7cddfSDavid du Colombier 	if(f->ntext > 1)
4427dd7cddfSDavid du Colombier 		for(i=0; i<f->ntext; i++)
4437dd7cddfSDavid du Colombier 			textcommit(f->text[i], FALSE);	/* no-op for t */
4447dd7cddfSDavid du Colombier 	if(t->what == Body)
4457dd7cddfSDavid du Colombier 		return;
4467dd7cddfSDavid du Colombier 	r = runemalloc(w->tag.file->nc);
4477dd7cddfSDavid du Colombier 	bufread(w->tag.file, 0, r, w->tag.file->nc);
4487dd7cddfSDavid du Colombier 	for(i=0; i<w->tag.file->nc; i++)
4497dd7cddfSDavid du Colombier 		if(r[i]==' ' || r[i]=='\t')
4507dd7cddfSDavid du Colombier 			break;
4517dd7cddfSDavid du Colombier 	if(runeeq(r, i, w->body.file->name, w->body.file->nname) == FALSE){
4527dd7cddfSDavid du Colombier 		seq++;
4537dd7cddfSDavid du Colombier 		filemark(w->body.file);
4547dd7cddfSDavid du Colombier 		w->body.file->mod = TRUE;
4557dd7cddfSDavid du Colombier 		w->dirty = TRUE;
4567dd7cddfSDavid du Colombier 		winsetname(w, r, i);
4577dd7cddfSDavid du Colombier 		winsettag(w);
4587dd7cddfSDavid du Colombier 	}
4597dd7cddfSDavid du Colombier 	free(r);
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier void
4637dd7cddfSDavid du Colombier winaddincl(Window *w, Rune *r, int n)
4647dd7cddfSDavid du Colombier {
4657dd7cddfSDavid du Colombier 	char *a;
4669a747e4fSDavid du Colombier 	Dir *d;
4677dd7cddfSDavid du Colombier 	Runestr rs;
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier 	a = runetobyte(r, n);
4709a747e4fSDavid du Colombier 	d = dirstat(a);
4719a747e4fSDavid du Colombier 	if(d == nil){
4727dd7cddfSDavid du Colombier 		if(a[0] == '/')
4737dd7cddfSDavid du Colombier 			goto Rescue;
4747dd7cddfSDavid du Colombier 		rs = dirname(&w->body, r, n);
4757dd7cddfSDavid du Colombier 		r = rs.r;
4767dd7cddfSDavid du Colombier 		n = rs.nr;
4777dd7cddfSDavid du Colombier 		free(a);
4787dd7cddfSDavid du Colombier 		a = runetobyte(r, n);
4799a747e4fSDavid du Colombier 		d = dirstat(a);
4809a747e4fSDavid du Colombier 		if(d == nil)
4817dd7cddfSDavid du Colombier 			goto Rescue;
4827dd7cddfSDavid du Colombier 		r = runerealloc(r, n+1);
4837dd7cddfSDavid du Colombier 		r[n] = 0;
4847dd7cddfSDavid du Colombier 	}
4857dd7cddfSDavid du Colombier 	free(a);
4869a747e4fSDavid du Colombier 	if((d->qid.type&QTDIR) == 0){
4879a747e4fSDavid du Colombier 		free(d);
4887dd7cddfSDavid du Colombier 		warning(nil, "%s: not a directory\n", a);
4897dd7cddfSDavid du Colombier 		free(r);
4907dd7cddfSDavid du Colombier 		return;
4917dd7cddfSDavid du Colombier 	}
4929a747e4fSDavid du Colombier 	free(d);
4937dd7cddfSDavid du Colombier 	w->nincl++;
4947dd7cddfSDavid du Colombier 	w->incl = realloc(w->incl, w->nincl*sizeof(Rune*));
4957dd7cddfSDavid du Colombier 	memmove(w->incl+1, w->incl, (w->nincl-1)*sizeof(Rune*));
4967dd7cddfSDavid du Colombier 	w->incl[0] = runemalloc(n+1);
4977dd7cddfSDavid du Colombier 	runemove(w->incl[0], r, n);
4987dd7cddfSDavid du Colombier 	free(r);
4997dd7cddfSDavid du Colombier 	return;
5007dd7cddfSDavid du Colombier 
5017dd7cddfSDavid du Colombier Rescue:
5027dd7cddfSDavid du Colombier 	warning(nil, "%s: %r\n", a);
5037dd7cddfSDavid du Colombier 	free(r);
5047dd7cddfSDavid du Colombier 	free(a);
5057dd7cddfSDavid du Colombier 	return;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier int
5097dd7cddfSDavid du Colombier winclean(Window *w, int conservative)	/* as it stands, conservative is always TRUE */
5107dd7cddfSDavid du Colombier {
5117dd7cddfSDavid du Colombier 	if(w->isscratch || w->isdir)	/* don't whine if it's a guide file, error window, etc. */
5127dd7cddfSDavid du Colombier 		return TRUE;
5137dd7cddfSDavid du Colombier 	if(!conservative && w->nopen[QWevent]>0)
5147dd7cddfSDavid du Colombier 		return TRUE;
5157dd7cddfSDavid du Colombier 	if(w->dirty){
5167dd7cddfSDavid du Colombier 		if(w->body.file->nname)
5177dd7cddfSDavid du Colombier 			warning(nil, "%.*S modified\n", w->body.file->nname, w->body.file->name);
5187dd7cddfSDavid du Colombier 		else{
5197dd7cddfSDavid du Colombier 			if(w->body.file->nc < 100)	/* don't whine if it's too small */
5207dd7cddfSDavid du Colombier 				return TRUE;
5217dd7cddfSDavid du Colombier 			warning(nil, "unnamed file modified\n");
5227dd7cddfSDavid du Colombier 		}
5237dd7cddfSDavid du Colombier 		w->dirty = FALSE;
5247dd7cddfSDavid du Colombier 		return FALSE;
5257dd7cddfSDavid du Colombier 	}
5267dd7cddfSDavid du Colombier 	return TRUE;
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier void
5309a747e4fSDavid du Colombier winctlprint(Window *w, char *buf, int fonts)
5317dd7cddfSDavid du Colombier {
5329a747e4fSDavid du Colombier 	int n;
5339a747e4fSDavid du Colombier 
5349a747e4fSDavid du Colombier 	n = sprint(buf, "%11d %11d %11d %11d %11d ", w->id, w->tag.file->nc,
5357dd7cddfSDavid du Colombier 		w->body.file->nc, w->isdir, w->dirty);
5369a747e4fSDavid du Colombier 	if(fonts)
537b8661318SDavid du Colombier 		sprint(buf+n, "%11d %q %11d" , Dx(w->body.r), w->body.reffont->f->name, w->body.maxtab);
5387dd7cddfSDavid du Colombier }
5397dd7cddfSDavid du Colombier 
5407dd7cddfSDavid du Colombier void
5417dd7cddfSDavid du Colombier winevent(Window *w, char *fmt, ...)
5427dd7cddfSDavid du Colombier {
5437dd7cddfSDavid du Colombier 	int n;
5447dd7cddfSDavid du Colombier 	char *b;
5457dd7cddfSDavid du Colombier 	Xfid *x;
5467dd7cddfSDavid du Colombier 	va_list arg;
5477dd7cddfSDavid du Colombier 
5487dd7cddfSDavid du Colombier 	if(w->nopen[QWevent] == 0)
5497dd7cddfSDavid du Colombier 		return;
5507dd7cddfSDavid du Colombier 	if(w->owner == 0)
5517dd7cddfSDavid du Colombier 		error("no window owner");
5527dd7cddfSDavid du Colombier 	va_start(arg, fmt);
5539a747e4fSDavid du Colombier 	b = vsmprint(fmt, arg);
5547dd7cddfSDavid du Colombier 	va_end(arg);
5559a747e4fSDavid du Colombier 	if(b == nil)
5569a747e4fSDavid du Colombier 		error("vsmprint failed");
5579a747e4fSDavid du Colombier 	n = strlen(b);
5587dd7cddfSDavid du Colombier 	w->events = realloc(w->events, w->nevents+1+n);
5597dd7cddfSDavid du Colombier 	w->events[w->nevents++] = w->owner;
5607dd7cddfSDavid du Colombier 	memmove(w->events+w->nevents, b, n);
5619a747e4fSDavid du Colombier 	free(b);
5627dd7cddfSDavid du Colombier 	w->nevents += n;
5637dd7cddfSDavid du Colombier 	x = w->eventx;
5647dd7cddfSDavid du Colombier 	if(x){
5657dd7cddfSDavid du Colombier 		w->eventx = nil;
5667dd7cddfSDavid du Colombier 		sendp(x->c, nil);
5677dd7cddfSDavid du Colombier 	}
5687dd7cddfSDavid du Colombier }
569