xref: /inferno-os/libtk/textu.c (revision 5849851a19380dbb62a47d9c4d868a81e42fa79b)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "tk.h"
437da2899SCharles.Forsyth #include "textw.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth #define istring u.string
737da2899SCharles.Forsyth #define iwin u.win
837da2899SCharles.Forsyth #define imark u.mark
937da2899SCharles.Forsyth #define iline u.line
1037da2899SCharles.Forsyth 
1137da2899SCharles.Forsyth /* debugging */
1237da2899SCharles.Forsyth int tktdbg;
1337da2899SCharles.Forsyth extern void tktprinttext(TkText*);
1437da2899SCharles.Forsyth extern void tktprintindex(TkTindex*);
1537da2899SCharles.Forsyth extern void tktprintitem(TkTitem*);
1637da2899SCharles.Forsyth extern void tktprintline(TkTline*);
1737da2899SCharles.Forsyth extern void tktcheck(TkText*, char*);
1837da2899SCharles.Forsyth int tktutfpos(char*, int);
1937da2899SCharles.Forsyth 
2037da2899SCharles.Forsyth char*
tktnewitem(int kind,int tagextra,TkTitem ** ret)2137da2899SCharles.Forsyth tktnewitem(int kind, int tagextra,TkTitem **ret)
2237da2899SCharles.Forsyth {
2337da2899SCharles.Forsyth 	int n;
2437da2899SCharles.Forsyth 	TkTitem *i;
2537da2899SCharles.Forsyth 
2637da2899SCharles.Forsyth 	n = sizeof(TkTitem) + tagextra * sizeof(ulong);
2737da2899SCharles.Forsyth 	i = malloc(n);
2837da2899SCharles.Forsyth 	if(i == nil)
2937da2899SCharles.Forsyth 		return TkNomem;
3037da2899SCharles.Forsyth 
3137da2899SCharles.Forsyth 	memset(i, 0, n);
3237da2899SCharles.Forsyth 	i->kind = kind;
3337da2899SCharles.Forsyth 	i->tagextra = tagextra;
3437da2899SCharles.Forsyth 	*ret = i;
3537da2899SCharles.Forsyth 	return nil;
3637da2899SCharles.Forsyth }
3737da2899SCharles.Forsyth 
3837da2899SCharles.Forsyth char*
tktnewline(int flags,TkTitem * items,TkTline * prev,TkTline * next,TkTline ** ret)3937da2899SCharles.Forsyth tktnewline(int flags, TkTitem *items, TkTline *prev, TkTline *next, TkTline **ret)
4037da2899SCharles.Forsyth {
4137da2899SCharles.Forsyth 	TkTline *l;
4237da2899SCharles.Forsyth 	TkTitem *i;
4337da2899SCharles.Forsyth 
4437da2899SCharles.Forsyth 	l = malloc(sizeof(TkTline));
4537da2899SCharles.Forsyth 	if(l == nil)
4637da2899SCharles.Forsyth 		return TkNomem;
4737da2899SCharles.Forsyth 
4837da2899SCharles.Forsyth 	memset(l, 0, sizeof(TkTline));
4937da2899SCharles.Forsyth 	l->flags = flags;
5037da2899SCharles.Forsyth 	l->items = items;
5137da2899SCharles.Forsyth 	l->prev = prev;
5237da2899SCharles.Forsyth 	l->next = next;
5337da2899SCharles.Forsyth 	next->prev = l;
5437da2899SCharles.Forsyth 	prev->next = l;
5537da2899SCharles.Forsyth 
5637da2899SCharles.Forsyth 	for(i = items; i->next != nil;)
5737da2899SCharles.Forsyth 		i = i->next;
5837da2899SCharles.Forsyth 	if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline))
5937da2899SCharles.Forsyth 		print("text:tktnewline botch\n");
6037da2899SCharles.Forsyth 	i->iline = l;
6137da2899SCharles.Forsyth 
6237da2899SCharles.Forsyth 	*ret = l;
6337da2899SCharles.Forsyth 	return nil;
6437da2899SCharles.Forsyth }
6537da2899SCharles.Forsyth 
6637da2899SCharles.Forsyth /*
6737da2899SCharles.Forsyth  * free items; freewins is 0 when the subwindows will be
6837da2899SCharles.Forsyth  * freed anyway as the main text widget is being destroyed.
6937da2899SCharles.Forsyth  */
7037da2899SCharles.Forsyth void
tktfreeitems(TkText * tkt,TkTitem * i,int freewins)7137da2899SCharles.Forsyth tktfreeitems(TkText *tkt, TkTitem *i, int freewins)
7237da2899SCharles.Forsyth {
7337da2899SCharles.Forsyth 	TkTitem *n;
7437da2899SCharles.Forsyth 	Tk *tk;
7537da2899SCharles.Forsyth 
7637da2899SCharles.Forsyth 	while(i != nil) {
7737da2899SCharles.Forsyth 		n = i->next;
7837da2899SCharles.Forsyth 		if(tkt->mouse == i)
7937da2899SCharles.Forsyth 			tkt->mouse = nil;
8037da2899SCharles.Forsyth 		switch(i->kind) {
8137da2899SCharles.Forsyth 		case TkTascii:
8237da2899SCharles.Forsyth 		case TkTrune:
8337da2899SCharles.Forsyth 			if(i->istring != nil)
8437da2899SCharles.Forsyth 				free(i->istring);
8537da2899SCharles.Forsyth 			break;
8637da2899SCharles.Forsyth 		case TkTwin:
8737da2899SCharles.Forsyth 			if (i->iwin != nil) {
8837da2899SCharles.Forsyth 				tk = i->iwin->sub;
8937da2899SCharles.Forsyth 				if (tk != nil) {
9037da2899SCharles.Forsyth 					tk->geom = nil;
9137da2899SCharles.Forsyth 					tk->destroyed = nil;
9237da2899SCharles.Forsyth 					if (i->iwin->owned && freewins) {
9337da2899SCharles.Forsyth 						if (tk->name != nil)
9437da2899SCharles.Forsyth 							tkdestroy(tk->env->top, tk->name->name, nil);
9537da2899SCharles.Forsyth 					} else {
9637da2899SCharles.Forsyth 						tk->parent = nil;
9737da2899SCharles.Forsyth 						tk->geom = nil;
9837da2899SCharles.Forsyth 						tk->destroyed = nil;
9937da2899SCharles.Forsyth 					}
10037da2899SCharles.Forsyth 				}
10137da2899SCharles.Forsyth 				if(i->iwin->create != nil)
10237da2899SCharles.Forsyth 					free(i->iwin->create);
10337da2899SCharles.Forsyth 				free(i->iwin);
10437da2899SCharles.Forsyth 			}
10537da2899SCharles.Forsyth 			break;
10637da2899SCharles.Forsyth 		case TkTmark:
10737da2899SCharles.Forsyth 			break;
10837da2899SCharles.Forsyth 		}
10937da2899SCharles.Forsyth 		free(i);
11037da2899SCharles.Forsyth 		i = n;
11137da2899SCharles.Forsyth 	}
11237da2899SCharles.Forsyth }
11337da2899SCharles.Forsyth 
11437da2899SCharles.Forsyth void
tktfreelines(TkText * tkt,TkTline * l,int freewins)11537da2899SCharles.Forsyth tktfreelines(TkText *tkt, TkTline *l, int freewins)
11637da2899SCharles.Forsyth {
11737da2899SCharles.Forsyth 	TkTline *n;
11837da2899SCharles.Forsyth 
11937da2899SCharles.Forsyth 	while(l != nil) {
12037da2899SCharles.Forsyth 		n = l->next;
12137da2899SCharles.Forsyth 		tktfreeitems(tkt, l->items, freewins);
12237da2899SCharles.Forsyth 		free(l);
12337da2899SCharles.Forsyth 		l = n;
12437da2899SCharles.Forsyth 	}
12537da2899SCharles.Forsyth }
12637da2899SCharles.Forsyth 
12737da2899SCharles.Forsyth void
tktfreetabs(TkTtabstop * t)12837da2899SCharles.Forsyth tktfreetabs(TkTtabstop *t)
12937da2899SCharles.Forsyth {
13037da2899SCharles.Forsyth 	TkTtabstop *n;
13137da2899SCharles.Forsyth 
13237da2899SCharles.Forsyth 	while(t != nil) {
13337da2899SCharles.Forsyth 		n = t->next;
13437da2899SCharles.Forsyth 		free(t);
13537da2899SCharles.Forsyth 		t = n;
13637da2899SCharles.Forsyth 	}
13737da2899SCharles.Forsyth }
13837da2899SCharles.Forsyth 
13937da2899SCharles.Forsyth void
tkfreetext(Tk * tk)14037da2899SCharles.Forsyth tkfreetext(Tk *tk)
14137da2899SCharles.Forsyth {
14237da2899SCharles.Forsyth 	TkText *tkt = TKobj(TkText, tk);
14337da2899SCharles.Forsyth 
14437da2899SCharles.Forsyth 	if(tkt->start.next != nil && tkt->start.next != &(tkt->end)) {
14537da2899SCharles.Forsyth 		tkt->end.prev->next = nil;
14637da2899SCharles.Forsyth 		tktfreelines(tkt, tkt->start.next, 0);
14737da2899SCharles.Forsyth 	}
14837da2899SCharles.Forsyth 	tktfreeitems(tkt, tkt->start.items, 0);
14937da2899SCharles.Forsyth 	tktfreeitems(tkt, tkt->end.items, 0);
15037da2899SCharles.Forsyth 	tktfreetabs(tkt->tabs);
15137da2899SCharles.Forsyth 	if(tkt->tagshare == nil)
15237da2899SCharles.Forsyth 		tktfreetags(tkt->tags);
15337da2899SCharles.Forsyth 	else
15437da2899SCharles.Forsyth 		tk->binds = nil;
15537da2899SCharles.Forsyth 	tktfreemarks(tkt->marks);
15637da2899SCharles.Forsyth 	if(tkt->xscroll != nil)
15737da2899SCharles.Forsyth 		free(tkt->xscroll);
15837da2899SCharles.Forsyth 	if(tkt->yscroll != nil)
15937da2899SCharles.Forsyth 		free(tkt->yscroll);
16037da2899SCharles.Forsyth 	/* don't free image because it belongs to window */
16137da2899SCharles.Forsyth }
16237da2899SCharles.Forsyth 
16337da2899SCharles.Forsyth /*
16437da2899SCharles.Forsyth  * Remove the item at ix, joining previous and next items.
16537da2899SCharles.Forsyth  * If item is at end of line, remove next line and join
16637da2899SCharles.Forsyth  * its items to this one (except at end).
16737da2899SCharles.Forsyth  * On return, ix is adjusted to point to the next item.
16837da2899SCharles.Forsyth  */
16937da2899SCharles.Forsyth void
tktremitem(TkText * tkt,TkTindex * ix)17037da2899SCharles.Forsyth tktremitem(TkText *tkt, TkTindex *ix)
17137da2899SCharles.Forsyth {
17237da2899SCharles.Forsyth 	TkTline *l, *lnext;
17337da2899SCharles.Forsyth 	TkTindex prev, nx;
17437da2899SCharles.Forsyth 	TkTitem *i, *ilast;
17537da2899SCharles.Forsyth 
17637da2899SCharles.Forsyth 	l = ix->line;
17737da2899SCharles.Forsyth 	i = ix->item;
17837da2899SCharles.Forsyth 
17937da2899SCharles.Forsyth 	if(i->next == nil) {
18037da2899SCharles.Forsyth 		if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline)) {
18137da2899SCharles.Forsyth 			print("tktremitem: botch 1\n");
18237da2899SCharles.Forsyth 			return;
18337da2899SCharles.Forsyth 		}
18437da2899SCharles.Forsyth 		lnext = l->next;
18537da2899SCharles.Forsyth 		if(lnext == &tkt->end)
18637da2899SCharles.Forsyth 			/* not supposed to remove final newline */
18737da2899SCharles.Forsyth 			return;
18837da2899SCharles.Forsyth 		if(i->kind == TkTnewline)
18937da2899SCharles.Forsyth 			tkt->nlines--;
19037da2899SCharles.Forsyth 		ilast = tktlastitem(lnext->items);
19137da2899SCharles.Forsyth 		ilast->iline = l;
19237da2899SCharles.Forsyth 		i->next = lnext->items;
19337da2899SCharles.Forsyth 		l->flags = (l->flags & ~TkTlast) | (lnext->flags & TkTlast);
19437da2899SCharles.Forsyth 		l->next = lnext->next;
19537da2899SCharles.Forsyth 		lnext->next->prev = l;
19637da2899SCharles.Forsyth 		free(lnext);
19737da2899SCharles.Forsyth 	}
19837da2899SCharles.Forsyth 	if(l->items == i)
19937da2899SCharles.Forsyth 		l->items = i->next;
20037da2899SCharles.Forsyth 	else {
20137da2899SCharles.Forsyth 		prev = *ix;
20237da2899SCharles.Forsyth 		if(!tktadjustind(tkt, TkTbyitemback, &prev) && tktdbg) {
20337da2899SCharles.Forsyth 			print("tktremitem: botch 2\n");
20437da2899SCharles.Forsyth 			return;
20537da2899SCharles.Forsyth 		}
20637da2899SCharles.Forsyth 		prev.item->next = i->next;
20737da2899SCharles.Forsyth 	}
20837da2899SCharles.Forsyth 	ix->item = i->next;
20937da2899SCharles.Forsyth 	ix->pos = 0;
21037da2899SCharles.Forsyth 	i->next = nil;
21137da2899SCharles.Forsyth 	nx = *ix;
21237da2899SCharles.Forsyth 	tktadjustind(tkt, TkTbycharstart, &nx);
21337da2899SCharles.Forsyth 
21437da2899SCharles.Forsyth 	/* check against cached items */
21537da2899SCharles.Forsyth 	if(tkt->selfirst == i)
21637da2899SCharles.Forsyth 		tkt->selfirst = nx.item;
21737da2899SCharles.Forsyth 	if(tkt->sellast == i)
21837da2899SCharles.Forsyth 		tkt->sellast = nx.item;
21937da2899SCharles.Forsyth 	if(tkt->selfirst == tkt->sellast) {
22037da2899SCharles.Forsyth 		tkt->selfirst = nil;
22137da2899SCharles.Forsyth 		tkt->sellast = nil;
22237da2899SCharles.Forsyth 	}
22337da2899SCharles.Forsyth 
22437da2899SCharles.Forsyth 	tktfreeitems(tkt, i, 1);
22537da2899SCharles.Forsyth }
22637da2899SCharles.Forsyth 
22737da2899SCharles.Forsyth int
tktdispwidth(Tk * tk,TkTtabstop * tb,TkTitem * i,Font * f,int x,int pos,int nchars)22837da2899SCharles.Forsyth tktdispwidth(Tk *tk, TkTtabstop *tb, TkTitem *i, Font *f, int x, int pos, int nchars)
22937da2899SCharles.Forsyth {
23037da2899SCharles.Forsyth 	int w, del, locked;
23137da2899SCharles.Forsyth 	TkTtabstop *tbprev;
23237da2899SCharles.Forsyth 	Display *d;
23337da2899SCharles.Forsyth 	TkText *tkt;
23437da2899SCharles.Forsyth 	TkEnv env;
23537da2899SCharles.Forsyth 
23637da2899SCharles.Forsyth 	tkt = TKobj(TkText, tk);
23737da2899SCharles.Forsyth 	d = tk->env->top->display;
23837da2899SCharles.Forsyth 	if (tb == nil)
23937da2899SCharles.Forsyth 		tb = tkt->tabs;
24037da2899SCharles.Forsyth 
24137da2899SCharles.Forsyth 	switch(i->kind) {
24237da2899SCharles.Forsyth 	case TkTrune:
24337da2899SCharles.Forsyth 		pos = tktutfpos(i->istring, pos);
24437da2899SCharles.Forsyth 		/* FALLTHRU */
24537da2899SCharles.Forsyth 	case TkTascii:
24637da2899SCharles.Forsyth 		if(f == nil) {
24737da2899SCharles.Forsyth 			if(!tktanytags(i))
24837da2899SCharles.Forsyth 				f = tk->env->font;
24937da2899SCharles.Forsyth 			else {
25037da2899SCharles.Forsyth 				tkttagopts(tk, i, nil, &env, nil, 1);
25137da2899SCharles.Forsyth 				f = env.font;
25237da2899SCharles.Forsyth 			}
25337da2899SCharles.Forsyth 		}
25437da2899SCharles.Forsyth 		locked = 0;
25537da2899SCharles.Forsyth 		if(!(tkt->tflag&TkTdlocked))
25637da2899SCharles.Forsyth 			locked = lockdisplay(d);
25737da2899SCharles.Forsyth 		if(nchars >= 0)
25837da2899SCharles.Forsyth 			w = stringnwidth(f, i->istring+pos, nchars);
25937da2899SCharles.Forsyth 		else
26037da2899SCharles.Forsyth 			w = stringwidth(f, i->istring+pos);
26137da2899SCharles.Forsyth 		if(locked)
26237da2899SCharles.Forsyth 			unlockdisplay(d);
26337da2899SCharles.Forsyth 		break;
26437da2899SCharles.Forsyth 	case TkTtab:
26537da2899SCharles.Forsyth 		if(tb == nil)
26637da2899SCharles.Forsyth 			w = 0;
26737da2899SCharles.Forsyth 		else {
26837da2899SCharles.Forsyth 			tbprev = nil;
26937da2899SCharles.Forsyth 			while(tb->pos <= x && tb->next != nil) {
27037da2899SCharles.Forsyth 					tbprev = tb;
27137da2899SCharles.Forsyth 					tb = tb->next;
27237da2899SCharles.Forsyth 				}
27337da2899SCharles.Forsyth 			w = tb->pos - x;
27437da2899SCharles.Forsyth 			if(w <= 0) {
27537da2899SCharles.Forsyth 				del = tb->pos;
27637da2899SCharles.Forsyth 				if(tbprev != nil)
27737da2899SCharles.Forsyth 					del -= tbprev->pos;
27837da2899SCharles.Forsyth 				while(w <= 0)
27937da2899SCharles.Forsyth 					w += del;
28037da2899SCharles.Forsyth 			}
28137da2899SCharles.Forsyth 			/* todo: other kinds of justification */
28237da2899SCharles.Forsyth 		}
28337da2899SCharles.Forsyth 		break;
28437da2899SCharles.Forsyth 	case TkTwin:
28537da2899SCharles.Forsyth 		if(i->iwin->sub == 0)
28637da2899SCharles.Forsyth 			w = 0;
28737da2899SCharles.Forsyth 		else
28837da2899SCharles.Forsyth 			w = i->iwin->sub->act.width + 2*i->iwin->padx + 2*i->iwin->sub->borderwidth;
28937da2899SCharles.Forsyth 		break;
29037da2899SCharles.Forsyth 	default:
29137da2899SCharles.Forsyth 		w = 0;
29237da2899SCharles.Forsyth 	}
29337da2899SCharles.Forsyth 	return w;
29437da2899SCharles.Forsyth }
29537da2899SCharles.Forsyth 
29637da2899SCharles.Forsyth int
tktindrune(TkTindex * ix)29737da2899SCharles.Forsyth tktindrune(TkTindex *ix)
29837da2899SCharles.Forsyth {
29937da2899SCharles.Forsyth 	int ans;
30037da2899SCharles.Forsyth 	Rune r;
30137da2899SCharles.Forsyth 
30237da2899SCharles.Forsyth 	switch(ix->item->kind) {
30337da2899SCharles.Forsyth 		case TkTascii:
30437da2899SCharles.Forsyth 			ans = ix->item->istring[ix->pos];
30537da2899SCharles.Forsyth 			break;
30637da2899SCharles.Forsyth 		case TkTrune:
30737da2899SCharles.Forsyth 			chartorune(&r, ix->item->istring + tktutfpos(ix->item->istring, ix->pos));
30837da2899SCharles.Forsyth 			ans = r;
30937da2899SCharles.Forsyth 			break;
31037da2899SCharles.Forsyth 		case TkTtab:
31137da2899SCharles.Forsyth 			ans = '\t';
31237da2899SCharles.Forsyth 			break;
31337da2899SCharles.Forsyth 		case TkTnewline:
31437da2899SCharles.Forsyth 			ans = '\n';
31537da2899SCharles.Forsyth 			break;
31637da2899SCharles.Forsyth 		default:
31737da2899SCharles.Forsyth 			/* only care that it isn't a word char */
31837da2899SCharles.Forsyth 			ans = 0x80;
31937da2899SCharles.Forsyth 	}
32037da2899SCharles.Forsyth 	return ans;
32137da2899SCharles.Forsyth }
32237da2899SCharles.Forsyth 
32337da2899SCharles.Forsyth TkTitem*
tktlastitem(TkTitem * i)32437da2899SCharles.Forsyth tktlastitem(TkTitem *i)
32537da2899SCharles.Forsyth {
32637da2899SCharles.Forsyth 	while(i->next != nil)
32737da2899SCharles.Forsyth 		i = i->next;
32837da2899SCharles.Forsyth 	if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline))
32937da2899SCharles.Forsyth 		print("text:tktlastitem botch\n");
33037da2899SCharles.Forsyth 
33137da2899SCharles.Forsyth 	return i;
33237da2899SCharles.Forsyth }
33337da2899SCharles.Forsyth 
33437da2899SCharles.Forsyth TkTline*
tktitemline(TkTitem * i)33537da2899SCharles.Forsyth tktitemline(TkTitem *i)
33637da2899SCharles.Forsyth {
33737da2899SCharles.Forsyth 	i = tktlastitem(i);
33837da2899SCharles.Forsyth 	return i->iline;
33937da2899SCharles.Forsyth }
34037da2899SCharles.Forsyth 
34137da2899SCharles.Forsyth int
tktlinenum(TkText * tkt,TkTindex * p)34237da2899SCharles.Forsyth tktlinenum(TkText *tkt, TkTindex *p)
34337da2899SCharles.Forsyth {
34437da2899SCharles.Forsyth 	int n;
34537da2899SCharles.Forsyth 	TkTline *l;
34637da2899SCharles.Forsyth 
34737da2899SCharles.Forsyth 	if(p->line->orig.y <= tkt->end.orig.y / 2) {
34837da2899SCharles.Forsyth 		/* line seems closer to beginning */
34937da2899SCharles.Forsyth 		n = 1;
35037da2899SCharles.Forsyth 		for(l = tkt->start.next; l != p->line; l = l->next) {
35137da2899SCharles.Forsyth 			if(tktdbg && l->next == nil) {
35237da2899SCharles.Forsyth 				print("text: tktlinenum botch\n");
35337da2899SCharles.Forsyth 				break;
35437da2899SCharles.Forsyth 			}
35537da2899SCharles.Forsyth 			if(l->flags & TkTlast)
35637da2899SCharles.Forsyth 				n++;
35737da2899SCharles.Forsyth 		}
35837da2899SCharles.Forsyth 	}
35937da2899SCharles.Forsyth 	else {
36037da2899SCharles.Forsyth 		n = tkt->nlines;
36137da2899SCharles.Forsyth 		for(l = tkt->end.prev; l != p->line; l = l->prev) {
36237da2899SCharles.Forsyth 			if(tktdbg && l->prev == nil) {
36337da2899SCharles.Forsyth 				print("text: tktlinenum botch\n");
36437da2899SCharles.Forsyth 				break;
36537da2899SCharles.Forsyth 			}
36637da2899SCharles.Forsyth 			if(l->flags & TkTfirst)
36737da2899SCharles.Forsyth 				n--;
36837da2899SCharles.Forsyth 		}
36937da2899SCharles.Forsyth 	}
37037da2899SCharles.Forsyth 	return n;
37137da2899SCharles.Forsyth }
37237da2899SCharles.Forsyth 
37337da2899SCharles.Forsyth int
tktlinepos(TkText * tkt,TkTindex * p)37437da2899SCharles.Forsyth tktlinepos(TkText *tkt, TkTindex *p)
37537da2899SCharles.Forsyth {
37637da2899SCharles.Forsyth 	int n;
37737da2899SCharles.Forsyth 	TkTindex ix;
37837da2899SCharles.Forsyth 	TkTitem *i;
37937da2899SCharles.Forsyth 
38037da2899SCharles.Forsyth 	n = 0;
38137da2899SCharles.Forsyth 	ix = *p;
38237da2899SCharles.Forsyth 	i = ix.item;
38337da2899SCharles.Forsyth 	tktadjustind(tkt, TkTbylinestart, &ix);
38437da2899SCharles.Forsyth 	while(ix.item != i) {
38537da2899SCharles.Forsyth 		if(tktdbg && ix.item->next == nil && (ix.line->flags&TkTlast)) {
38637da2899SCharles.Forsyth 			print("text: tktlinepos botch\n");
38737da2899SCharles.Forsyth 			break;
38837da2899SCharles.Forsyth 		}
38937da2899SCharles.Forsyth 		n += tktposcount(ix.item);
39037da2899SCharles.Forsyth 		if(!tktadjustind(tkt, TkTbyitem, &ix)) {
39137da2899SCharles.Forsyth 			if(tktdbg)
39237da2899SCharles.Forsyth 				print("tktlinepos botch\n");
39337da2899SCharles.Forsyth 			break;
39437da2899SCharles.Forsyth 		}
39537da2899SCharles.Forsyth 	}
39637da2899SCharles.Forsyth 	return (n+p->pos);
39737da2899SCharles.Forsyth }
39837da2899SCharles.Forsyth 
39937da2899SCharles.Forsyth int
tktposcount(TkTitem * i)40037da2899SCharles.Forsyth tktposcount(TkTitem *i)
40137da2899SCharles.Forsyth {
40237da2899SCharles.Forsyth 	int n;
40337da2899SCharles.Forsyth 
40437da2899SCharles.Forsyth 	if(i->kind == TkTascii)
40537da2899SCharles.Forsyth 		n = strlen(i->istring);
40637da2899SCharles.Forsyth 	else
40737da2899SCharles.Forsyth 	if(i->kind == TkTrune)
40837da2899SCharles.Forsyth 		n = utflen(i->istring);
40937da2899SCharles.Forsyth 	else
41037da2899SCharles.Forsyth 	if(i->kind == TkTmark || i->kind == TkTcontline)
41137da2899SCharles.Forsyth 		n = 0;
41237da2899SCharles.Forsyth 	else
41337da2899SCharles.Forsyth 		n = 1;
41437da2899SCharles.Forsyth 	return n;
41537da2899SCharles.Forsyth }
41637da2899SCharles.Forsyth 
41737da2899SCharles.Forsyth /*
41837da2899SCharles.Forsyth  * Insert item i before position ins.
41937da2899SCharles.Forsyth  * If i is a newline or a contline, make a new line to contain the items up to
42037da2899SCharles.Forsyth  * and including the new newline, and make the original line
42137da2899SCharles.Forsyth  * contain the items from ins on.
42237da2899SCharles.Forsyth  * Adjust ins so that it points just after inserted item.
42337da2899SCharles.Forsyth  */
42437da2899SCharles.Forsyth char*
tktiteminsert(TkText * tkt,TkTindex * ins,TkTitem * i)42537da2899SCharles.Forsyth tktiteminsert(TkText *tkt, TkTindex *ins, TkTitem *i)
42637da2899SCharles.Forsyth {
42737da2899SCharles.Forsyth 	int hasprev, flags;
42837da2899SCharles.Forsyth 	char *e;
42937da2899SCharles.Forsyth 	TkTindex prev;
43037da2899SCharles.Forsyth 	TkTline *l;
43137da2899SCharles.Forsyth 	TkTitem *items;
43237da2899SCharles.Forsyth 
43337da2899SCharles.Forsyth 	prev = *ins;
43437da2899SCharles.Forsyth 	hasprev = tktadjustind(tkt, TkTbyitemback, &prev);
43537da2899SCharles.Forsyth 
43637da2899SCharles.Forsyth 	if(i->kind == TkTnewline || i->kind == TkTcontline) {
43737da2899SCharles.Forsyth 		i->next = nil;
43837da2899SCharles.Forsyth 		if(hasprev && prev.line == ins->line) {
43937da2899SCharles.Forsyth 			items = ins->line->items;
44037da2899SCharles.Forsyth 			prev.item->next = i;
44137da2899SCharles.Forsyth 		}
44237da2899SCharles.Forsyth 		else
44337da2899SCharles.Forsyth 			items = i;
44437da2899SCharles.Forsyth 
44537da2899SCharles.Forsyth 		flags = ins->line->flags&TkTfirst;
44637da2899SCharles.Forsyth 		if(i->kind == TkTnewline)
44737da2899SCharles.Forsyth 			flags |= TkTlast;
44837da2899SCharles.Forsyth 		e = tktnewline(flags, items, ins->line->prev, ins->line, &l);
44937da2899SCharles.Forsyth 		if(e != nil) {
45037da2899SCharles.Forsyth 			if(hasprev && prev.line == ins->line)
45137da2899SCharles.Forsyth 				prev.item->next = ins->item;
45237da2899SCharles.Forsyth 			return e;
45337da2899SCharles.Forsyth 		}
45437da2899SCharles.Forsyth 
45537da2899SCharles.Forsyth 		if(i->kind == TkTnewline)
45637da2899SCharles.Forsyth 			ins->line->flags |= TkTfirst;
45737da2899SCharles.Forsyth 
45837da2899SCharles.Forsyth 		if(i->kind == TkTcontline)
45937da2899SCharles.Forsyth 			ins->line->flags &= ~TkTfirst;
46037da2899SCharles.Forsyth 		ins->line->items = ins->item;
46137da2899SCharles.Forsyth 		ins->pos = 0;
46237da2899SCharles.Forsyth 	}
46337da2899SCharles.Forsyth 	else {
46437da2899SCharles.Forsyth 		if(hasprev && prev.line == ins->line)
46537da2899SCharles.Forsyth 			prev.item->next = i;
46637da2899SCharles.Forsyth 		else
46737da2899SCharles.Forsyth 			ins->line->items = i;
46837da2899SCharles.Forsyth 		i->next = ins->item;
46937da2899SCharles.Forsyth 	}
47037da2899SCharles.Forsyth 
47137da2899SCharles.Forsyth 	return nil;
47237da2899SCharles.Forsyth }
47337da2899SCharles.Forsyth 
47437da2899SCharles.Forsyth /*
47537da2899SCharles.Forsyth  * If index p doesn't point at the beginning of an item,
47637da2899SCharles.Forsyth  * split the item at p.  Adjust p to point to the beginning of
47737da2899SCharles.Forsyth  * the item after the split (same character it used to point at).
47837da2899SCharles.Forsyth  * If there is a split, the old item gets the characters before
47937da2899SCharles.Forsyth  * the split, and a new item gets the characters after it.
48037da2899SCharles.Forsyth  */
48137da2899SCharles.Forsyth char*
tktsplititem(TkTindex * p)48237da2899SCharles.Forsyth tktsplititem(TkTindex *p)
48337da2899SCharles.Forsyth {
48437da2899SCharles.Forsyth 	int l1, l2;
48537da2899SCharles.Forsyth 	char *s1, *s2, *e;
48637da2899SCharles.Forsyth 	TkTitem *i, *i2;
48737da2899SCharles.Forsyth 
48837da2899SCharles.Forsyth 	i = p->item;
48937da2899SCharles.Forsyth 
49037da2899SCharles.Forsyth 	if(p->pos != 0) {
49137da2899SCharles.Forsyth 		/*
49237da2899SCharles.Forsyth 		 * Must be TkTascii or TkTrune
49337da2899SCharles.Forsyth 		 *
49437da2899SCharles.Forsyth 		 * Make new item i2, to be inserted after i,
49537da2899SCharles.Forsyth 		 * with portion of string from p->pos on
49637da2899SCharles.Forsyth 		 */
49737da2899SCharles.Forsyth 
49837da2899SCharles.Forsyth 		if (i->kind == TkTascii)
49937da2899SCharles.Forsyth 			l1 = p->pos;
50037da2899SCharles.Forsyth 		else
50137da2899SCharles.Forsyth 			l1 = tktutfpos(i->istring, p->pos);
50237da2899SCharles.Forsyth 		l2 = strlen(i->istring) - l1;
50337da2899SCharles.Forsyth 		if (l2 == 0)
50437da2899SCharles.Forsyth 			print("tktsplititem botch\n");
50537da2899SCharles.Forsyth 		s1 = malloc(l1+1);
50637da2899SCharles.Forsyth 		if(s1 == nil)
50737da2899SCharles.Forsyth 			return TkNomem;
50837da2899SCharles.Forsyth 		s2 = malloc(l2+1);
50937da2899SCharles.Forsyth 		if(s2 == nil) {
51037da2899SCharles.Forsyth 			free(s1);
51137da2899SCharles.Forsyth 			return TkNomem;
51237da2899SCharles.Forsyth 		}
51337da2899SCharles.Forsyth 
51437da2899SCharles.Forsyth 		memmove(s1, i->istring, l1);
51537da2899SCharles.Forsyth 		s1[l1] = '\0';
51637da2899SCharles.Forsyth 		memmove(s2, i->istring + l1, l2);
51737da2899SCharles.Forsyth 		s2[l2] = '\0';
51837da2899SCharles.Forsyth 
51937da2899SCharles.Forsyth 		e = tktnewitem(i->kind, i->tagextra, &i2);
52037da2899SCharles.Forsyth 		if(e != nil) {
52137da2899SCharles.Forsyth 			free(s1);
52237da2899SCharles.Forsyth 			free(s2);
52337da2899SCharles.Forsyth 			return e;
52437da2899SCharles.Forsyth 		}
52537da2899SCharles.Forsyth 
52637da2899SCharles.Forsyth 		free(i->istring);
52737da2899SCharles.Forsyth 
52837da2899SCharles.Forsyth 		tkttagcomb(i2, i, 1);
52937da2899SCharles.Forsyth 		i2->next = i->next;
53037da2899SCharles.Forsyth 		i->next = i2;
53137da2899SCharles.Forsyth 		i->istring = s1;
53237da2899SCharles.Forsyth 		i2->istring = s2;
53337da2899SCharles.Forsyth 
53437da2899SCharles.Forsyth 		p->item = i2;
53537da2899SCharles.Forsyth 		p->pos = 0;
53637da2899SCharles.Forsyth 	}
53737da2899SCharles.Forsyth 
53837da2899SCharles.Forsyth 	return nil;
53937da2899SCharles.Forsyth }
54037da2899SCharles.Forsyth 
54137da2899SCharles.Forsyth int
tktmaxwid(TkTline * l)54237da2899SCharles.Forsyth tktmaxwid(TkTline *l)
54337da2899SCharles.Forsyth {
54437da2899SCharles.Forsyth 	int w, maxw;
54537da2899SCharles.Forsyth 
54637da2899SCharles.Forsyth 	maxw = 0;
54737da2899SCharles.Forsyth 	while(l != nil) {
54837da2899SCharles.Forsyth 		w = l->width;
54937da2899SCharles.Forsyth 		if(w > maxw)
55037da2899SCharles.Forsyth 			maxw = w;
55137da2899SCharles.Forsyth 		l = l->next;
55237da2899SCharles.Forsyth 	}
55337da2899SCharles.Forsyth 	return maxw;
55437da2899SCharles.Forsyth }
55537da2899SCharles.Forsyth 
55637da2899SCharles.Forsyth Rectangle
tktbbox(Tk * tk,TkTindex * ix)55737da2899SCharles.Forsyth tktbbox(Tk *tk, TkTindex *ix)
55837da2899SCharles.Forsyth {
55937da2899SCharles.Forsyth 	Rectangle r;
56037da2899SCharles.Forsyth 	int d, w;
56137da2899SCharles.Forsyth 	TkTitem *i;
56237da2899SCharles.Forsyth 	TkTline *l;
56337da2899SCharles.Forsyth 	TkEnv env;
56437da2899SCharles.Forsyth 	TkTtabstop *tb = nil;
56537da2899SCharles.Forsyth 	Tk *sub;
56637da2899SCharles.Forsyth 	TkText *tkt = TKobj(TkText, tk);
56737da2899SCharles.Forsyth  	int opts[TkTnumopts];
56837da2899SCharles.Forsyth 
56937da2899SCharles.Forsyth 	l = ix->line;
57037da2899SCharles.Forsyth 
57137da2899SCharles.Forsyth 	/* r in V space */
57237da2899SCharles.Forsyth 	r.min = subpt(l->orig, tkt->deltatv);
57337da2899SCharles.Forsyth 	r.min.y += l->ascent;
574*5849851aSforsyth 	r.max = r.min;
57537da2899SCharles.Forsyth 
57637da2899SCharles.Forsyth 	/* tabs dependon tags of first non-mark on display line */
57737da2899SCharles.Forsyth 	for(i = l->items; i->kind == TkTmark; )
57837da2899SCharles.Forsyth 		i = i->next;
57937da2899SCharles.Forsyth 	tkttagopts(tk, i, opts, &env, &tb, 1);
58037da2899SCharles.Forsyth 
58137da2899SCharles.Forsyth 	for(i = l->items; i != nil; i = i->next) {
58237da2899SCharles.Forsyth 		if(i == ix->item) {
58337da2899SCharles.Forsyth 			tkttagopts(tk, i, opts, &env, nil, 1);
58437da2899SCharles.Forsyth 			r.min.y -= opts[TkToffset];
58537da2899SCharles.Forsyth 			switch(i->kind) {
58637da2899SCharles.Forsyth 			case TkTascii:
58737da2899SCharles.Forsyth 			case TkTrune:
58837da2899SCharles.Forsyth 				d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, ix->pos);
58937da2899SCharles.Forsyth 				w = tktdispwidth(tk, tb, i, nil, r.min.x, ix->pos, 1);
59037da2899SCharles.Forsyth 				r.min.x += d;
59137da2899SCharles.Forsyth 				r.min.y -= env.font->ascent;
59237da2899SCharles.Forsyth 				r.max.x = r.min.x + w;
59337da2899SCharles.Forsyth 				r.max.y = r.min.y + env.font->height;
59437da2899SCharles.Forsyth 				break;
59537da2899SCharles.Forsyth 			case TkTwin:
59637da2899SCharles.Forsyth 				sub = i->iwin->sub;
59737da2899SCharles.Forsyth 				if(sub == nil)
59837da2899SCharles.Forsyth 					break;
59937da2899SCharles.Forsyth 				r.min.x += sub->act.x;
60037da2899SCharles.Forsyth 				r.min.y += sub->act.y;
60137da2899SCharles.Forsyth 				r.max.x = r.min.x + sub->act.width + 2*sub->borderwidth;
60237da2899SCharles.Forsyth 				r.max.y = r.min.y + sub->act.height + 2*sub->borderwidth;
60337da2899SCharles.Forsyth 				break;
60437da2899SCharles.Forsyth 			case TkTnewline:
60537da2899SCharles.Forsyth 				r.max.x = r.min.x;
60637da2899SCharles.Forsyth 				r.min.y -= l->ascent;
60737da2899SCharles.Forsyth 				r.max.y = r.min.y + l->height;
60837da2899SCharles.Forsyth 				break;
60937da2899SCharles.Forsyth 			default:
61037da2899SCharles.Forsyth 				d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1);
61137da2899SCharles.Forsyth 				r.max.x = r.min.x + d;
61237da2899SCharles.Forsyth 				r.max.y = r.min.y;
61337da2899SCharles.Forsyth 				break;
61437da2899SCharles.Forsyth 			}
61537da2899SCharles.Forsyth 			return r;
61637da2899SCharles.Forsyth 		}
61737da2899SCharles.Forsyth 		r.min.x += tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1);
61837da2899SCharles.Forsyth 	}
61937da2899SCharles.Forsyth 	r.min.x = 0;
62037da2899SCharles.Forsyth 	r.min.y = 0;
62137da2899SCharles.Forsyth 	r.max.x = 0;
6226e425a9dSCharles.Forsyth 	r.max.y = 0;
62337da2899SCharles.Forsyth 	return r;
62437da2899SCharles.Forsyth }
62537da2899SCharles.Forsyth 
62637da2899SCharles.Forsyth /* Return left-at-baseline position of given item, in V coords */
62737da2899SCharles.Forsyth static Point
tktitempos(Tk * tk,TkTindex * ix)62837da2899SCharles.Forsyth tktitempos(Tk *tk, TkTindex *ix)
62937da2899SCharles.Forsyth {
63037da2899SCharles.Forsyth 	Point p;
63137da2899SCharles.Forsyth 	TkTitem *i;
63237da2899SCharles.Forsyth 	TkTline *l;
63337da2899SCharles.Forsyth 	TkText *tkt = TKobj(TkText, tk);
63437da2899SCharles.Forsyth 
63537da2899SCharles.Forsyth 	l = ix->line;
63637da2899SCharles.Forsyth 
63737da2899SCharles.Forsyth 	/* p in V space */
63837da2899SCharles.Forsyth 	p = subpt(l->orig, tkt->deltatv);
63937da2899SCharles.Forsyth 	p.y += l->ascent;
64037da2899SCharles.Forsyth 
64137da2899SCharles.Forsyth 	for(i = l->items; i != nil && i != ix->item; i = i->next)
64237da2899SCharles.Forsyth 		p.x += i->width;
64337da2899SCharles.Forsyth 	return p;
64437da2899SCharles.Forsyth }
64537da2899SCharles.Forsyth 
64637da2899SCharles.Forsyth static Tk*
tktdeliver(Tk * tk,TkTitem * i,TkTitem * tagit,int event,void * data,Point deltasv)64737da2899SCharles.Forsyth tktdeliver(Tk *tk, TkTitem *i, TkTitem *tagit, int event, void *data, Point deltasv)
64837da2899SCharles.Forsyth {
64937da2899SCharles.Forsyth 	Tk *ftk, *dest;
65037da2899SCharles.Forsyth 	TkTwind *w;
65137da2899SCharles.Forsyth 	TkText *tkt;
65237da2899SCharles.Forsyth 	TkTtaginfo *t;
65337da2899SCharles.Forsyth 	TkTline *l;
65437da2899SCharles.Forsyth 	TkMouse m;
65537da2899SCharles.Forsyth 	Point mp, p;
65637da2899SCharles.Forsyth 	TkTindex ix;
65737da2899SCharles.Forsyth 	int bd;
65837da2899SCharles.Forsyth 
65937da2899SCharles.Forsyth 	dest = nil;
66037da2899SCharles.Forsyth 	if(i != nil) {
66137da2899SCharles.Forsyth 		tkt = TKobj(TkText, tk);
66237da2899SCharles.Forsyth 
66337da2899SCharles.Forsyth 		if(i->kind == TkTwin) {
66437da2899SCharles.Forsyth 			w = i->iwin;
66537da2899SCharles.Forsyth 			if(w->sub != nil) {
66637da2899SCharles.Forsyth 				if(!(event & TkKey) && (event & TkEmouse)) {
66737da2899SCharles.Forsyth 					m = *(TkMouse*)data;
66837da2899SCharles.Forsyth 					mp.x = m.x;
66937da2899SCharles.Forsyth 					mp.y = m.y;
67037da2899SCharles.Forsyth 					ix.item = i;
67137da2899SCharles.Forsyth 					ix.pos = 0;
67237da2899SCharles.Forsyth 					ix.line = tktitemline(i);
67337da2899SCharles.Forsyth 					p = tktitempos(tk, &ix);
67437da2899SCharles.Forsyth 					bd = w->sub->borderwidth;
67537da2899SCharles.Forsyth 					mp.x = m.x - (deltasv.x + p.x + w->sub->act.x + bd);
67637da2899SCharles.Forsyth 					mp.y = m.y - (deltasv.y + p.y + w->sub->act.y + bd);
67737da2899SCharles.Forsyth 					ftk = tkinwindow(w->sub, mp, 0);
67837da2899SCharles.Forsyth 					if(ftk != w->focus) {
67937da2899SCharles.Forsyth 						tkdeliver(w->focus, TkLeave, data);
68037da2899SCharles.Forsyth 						tkdeliver(ftk, TkEnter, data);
68137da2899SCharles.Forsyth 
68237da2899SCharles.Forsyth 						w->focus = ftk;
68337da2899SCharles.Forsyth 					}
68437da2899SCharles.Forsyth 					if(ftk != nil)
68537da2899SCharles.Forsyth 						dest = tkdeliver(ftk, event, &m);
68637da2899SCharles.Forsyth 				}
68737da2899SCharles.Forsyth 				else {
68837da2899SCharles.Forsyth 					if ((event & TkLeave) && (w->focus != w->sub)) {
68937da2899SCharles.Forsyth 						tkdeliver(w->focus, TkLeave, data);
69037da2899SCharles.Forsyth 						w->focus = nil;
69137da2899SCharles.Forsyth 						event &= ~TkLeave;
69237da2899SCharles.Forsyth 					}
69337da2899SCharles.Forsyth 					if (event)
69437da2899SCharles.Forsyth 						tkdeliver(w->sub, event, data);
69537da2899SCharles.Forsyth 				}
69637da2899SCharles.Forsyth 				if(Dx(w->sub->dirty) > 0) {
69737da2899SCharles.Forsyth 					l = tktitemline(i);
69837da2899SCharles.Forsyth 					tktfixgeom(tk, tktprevwrapline(tk, l), l, 0);
69937da2899SCharles.Forsyth 				}
70037da2899SCharles.Forsyth 				if(event & TkKey)
70137da2899SCharles.Forsyth 					return dest;
70237da2899SCharles.Forsyth 			}
70337da2899SCharles.Forsyth 		}
70437da2899SCharles.Forsyth 
70537da2899SCharles.Forsyth 		if(tagit != 0) {
70637da2899SCharles.Forsyth 			for(t = tkt->tags; t != nil; t = t->next) {
70737da2899SCharles.Forsyth 				if(t->binds != nil && tkttagset(tagit, t->id)) {
70837da2899SCharles.Forsyth 					if(tksubdeliver(tk, t->binds, event, data, 0) == TkDbreak) {
70937da2899SCharles.Forsyth 						return dest;
71037da2899SCharles.Forsyth 					}
71137da2899SCharles.Forsyth 				}
71237da2899SCharles.Forsyth 			}
71337da2899SCharles.Forsyth 		}
71437da2899SCharles.Forsyth 	}
71537da2899SCharles.Forsyth 	return dest;
71637da2899SCharles.Forsyth }
71737da2899SCharles.Forsyth 
71837da2899SCharles.Forsyth Tk*
tktinwindow(Tk * tk,Point * p)71937da2899SCharles.Forsyth tktinwindow(Tk *tk, Point *p)
72037da2899SCharles.Forsyth {
72137da2899SCharles.Forsyth 	TkTindex ix;
72237da2899SCharles.Forsyth 	Point q;
72337da2899SCharles.Forsyth 	Tk *sub;
72437da2899SCharles.Forsyth 
72537da2899SCharles.Forsyth 	tktxyind(tk, p->x, p->y, &ix);
72637da2899SCharles.Forsyth 	if (ix.item == nil || ix.item->kind != TkTwin || ix.item->iwin->sub == nil)
72737da2899SCharles.Forsyth 		return tk;
72837da2899SCharles.Forsyth 	sub = ix.item->iwin->sub;
72937da2899SCharles.Forsyth 	q = tktitempos(tk, &ix);
73037da2899SCharles.Forsyth 	p->x -= q.x + sub->borderwidth + sub->act.x;
73137da2899SCharles.Forsyth 	p->y -= q.y + sub->borderwidth + sub->act.y;
73237da2899SCharles.Forsyth 	return sub;
73337da2899SCharles.Forsyth }
73437da2899SCharles.Forsyth 
73537da2899SCharles.Forsyth Tk*
tktextevent(Tk * tk,int event,void * data)73637da2899SCharles.Forsyth tktextevent(Tk *tk, int event, void *data)
73737da2899SCharles.Forsyth {
73837da2899SCharles.Forsyth 	char *e;
73937da2899SCharles.Forsyth 	TkMouse m, vm;
74037da2899SCharles.Forsyth 	TkTitem *f, *tagit;
74137da2899SCharles.Forsyth 	TkText *tkt;
74237da2899SCharles.Forsyth 	TkTindex ix;
74337da2899SCharles.Forsyth 	Tk *dest;
74437da2899SCharles.Forsyth 	Point deltasv;
74537da2899SCharles.Forsyth 
74637da2899SCharles.Forsyth 	tkt = TKobj(TkText, tk);
74737da2899SCharles.Forsyth 	deltasv = tkposn(tk);
74837da2899SCharles.Forsyth 	deltasv.x += tk->borderwidth + tk->ipad.x/2;
74937da2899SCharles.Forsyth 	deltasv.y += tk->borderwidth + tk->ipad.y/2;
75037da2899SCharles.Forsyth 
75137da2899SCharles.Forsyth 	dest = nil;
75237da2899SCharles.Forsyth 	if(event == TkLeave && tkt->mouse != nil) {
75337da2899SCharles.Forsyth 		vm.x = 0;
75437da2899SCharles.Forsyth 		vm.y = 0;
75537da2899SCharles.Forsyth 		tktdeliver(tk, tkt->mouse, tkt->mouse, TkLeave, data, deltasv);
75637da2899SCharles.Forsyth 		tkt->mouse = nil;
75737da2899SCharles.Forsyth 	}
75837da2899SCharles.Forsyth 	else if((event & TkKey) == 0 && (event & TkEmouse)) {
75937da2899SCharles.Forsyth 		/* m in S space, tm in V space */
76037da2899SCharles.Forsyth 		m = *(TkMouse*)data;
76137da2899SCharles.Forsyth 		vm = m;
76237da2899SCharles.Forsyth 		vm.x -= deltasv.x;
76337da2899SCharles.Forsyth 		vm.y -= deltasv.y;
76437da2899SCharles.Forsyth 		if((event & TkMotion) == 0 || m.b == 0) {
76537da2899SCharles.Forsyth 			tkt->current.x = vm.x;
76637da2899SCharles.Forsyth 			tkt->current.y = vm.y;
76737da2899SCharles.Forsyth 		}
76837da2899SCharles.Forsyth 		tktxyind(tk, vm.x, vm.y, &ix);
76937da2899SCharles.Forsyth 		f = ix.item;
77037da2899SCharles.Forsyth 		if(tkt->mouse != f) {
77137da2899SCharles.Forsyth 			tagit = nil;
77237da2899SCharles.Forsyth 			if(tkt->mouse != nil) {
77337da2899SCharles.Forsyth 				if(tktanytags(tkt->mouse)) {
77437da2899SCharles.Forsyth 					e = tktnewitem(TkTascii, tkt->mouse->tagextra, &tagit);
77537da2899SCharles.Forsyth 					if(e != nil)
77637da2899SCharles.Forsyth 						return dest;	/* XXX propagate error? */
77737da2899SCharles.Forsyth 					tkttagcomb(tagit, tkt->mouse, 1);
77837da2899SCharles.Forsyth 					tkttagcomb(tagit, f, -1);
77937da2899SCharles.Forsyth 				}
78037da2899SCharles.Forsyth 				tktdeliver(tk, tkt->mouse, tagit, TkLeave, data, deltasv);
78137da2899SCharles.Forsyth 				if(tagit)
78237da2899SCharles.Forsyth 					free(tagit);
78337da2899SCharles.Forsyth 				tagit = nil;
78437da2899SCharles.Forsyth 			}
78537da2899SCharles.Forsyth 			if(tktanytags(f)) {
78637da2899SCharles.Forsyth 				e = tktnewitem(TkTascii, f->tagextra, &tagit);
78737da2899SCharles.Forsyth 				if(e != nil)
78837da2899SCharles.Forsyth 					return dest;		/* XXX propagate error? */
78937da2899SCharles.Forsyth 				tkttagcomb(tagit, f, 1);
79037da2899SCharles.Forsyth 				if(tkt->mouse)
79137da2899SCharles.Forsyth 					tkttagcomb(tagit, tkt->mouse, -1);
79237da2899SCharles.Forsyth 			}
79337da2899SCharles.Forsyth 			tktdeliver(tk, f, tagit, TkEnter, data, deltasv);
79437da2899SCharles.Forsyth 			tkt->mouse = f;
79537da2899SCharles.Forsyth 			if(tagit)
79637da2899SCharles.Forsyth 				free(tagit);
79737da2899SCharles.Forsyth 		}
79837da2899SCharles.Forsyth 		if(tkt->mouse != nil)
79937da2899SCharles.Forsyth 			dest = tktdeliver(tk, tkt->mouse, tkt->mouse, event, &m, deltasv);
80037da2899SCharles.Forsyth 	}
80137da2899SCharles.Forsyth 	else if(event == TkFocusin)
80237da2899SCharles.Forsyth 		tktextcursor(tk, " insert", (char **) nil);
80337da2899SCharles.Forsyth 	/* pass all "real" events on to parent text widget - DBK */
80437da2899SCharles.Forsyth 	tksubdeliver(tk, tk->binds, event, data, 0);
80537da2899SCharles.Forsyth 	return dest;
80637da2899SCharles.Forsyth }
80737da2899SCharles.Forsyth 
80837da2899SCharles.Forsyth /* Debugging */
80937da2899SCharles.Forsyth void
tktprintitem(TkTitem * i)81037da2899SCharles.Forsyth tktprintitem(TkTitem *i)
81137da2899SCharles.Forsyth {
81237da2899SCharles.Forsyth 	int j;
81337da2899SCharles.Forsyth 
81437da2899SCharles.Forsyth 	print("%p:", i);
81537da2899SCharles.Forsyth 	switch(i->kind){
81637da2899SCharles.Forsyth 	case TkTascii:
81737da2899SCharles.Forsyth 		print("\"%s\"", i->istring);
81837da2899SCharles.Forsyth 		break;
81937da2899SCharles.Forsyth 	case TkTrune:
82037da2899SCharles.Forsyth 		print("<rune:%s>", i->istring);
82137da2899SCharles.Forsyth 		break;
82237da2899SCharles.Forsyth 	case TkTnewline:
82337da2899SCharles.Forsyth 		print("<nl:%p>", i->iline);
82437da2899SCharles.Forsyth 		break;
82537da2899SCharles.Forsyth 	case TkTcontline:
82637da2899SCharles.Forsyth 		print("<cont:%p>", i->iline);
82737da2899SCharles.Forsyth 		break;
82837da2899SCharles.Forsyth 	case TkTtab:
82937da2899SCharles.Forsyth 		print("<tab>");
83037da2899SCharles.Forsyth 		break;
83137da2899SCharles.Forsyth 	case TkTmark:
83237da2899SCharles.Forsyth 		print("<mk:%s>", i->imark->name);
83337da2899SCharles.Forsyth 		break;
83437da2899SCharles.Forsyth 	case TkTwin:
83537da2899SCharles.Forsyth 	        if (i->iwin->sub->name != nil)
83637da2899SCharles.Forsyth 		  print("<win:%s>", i->iwin->sub? i->iwin->sub->name->name : "<null>");
83737da2899SCharles.Forsyth 	}
83837da2899SCharles.Forsyth 	print("[%d]", i->width);
83937da2899SCharles.Forsyth 	if(i->tags !=0 || i->tagextra !=0) {
84037da2899SCharles.Forsyth 		print("{%lux", i->tags[0]);
84137da2899SCharles.Forsyth 		for(j=0; j < i->tagextra; j++)
84237da2899SCharles.Forsyth 			print(" %lux", i->tags[j+1]);
84337da2899SCharles.Forsyth 		print("}");
84437da2899SCharles.Forsyth 	}
84537da2899SCharles.Forsyth 	print(" ");
84637da2899SCharles.Forsyth }
84737da2899SCharles.Forsyth 
84837da2899SCharles.Forsyth void
tktprintline(TkTline * l)84937da2899SCharles.Forsyth tktprintline(TkTline *l)
85037da2899SCharles.Forsyth {
85137da2899SCharles.Forsyth 	TkTitem *i;
85237da2899SCharles.Forsyth 
85337da2899SCharles.Forsyth 	print("line %p: orig=(%d,%d), w=%d, h=%d, a=%d, f=%x\n\t",
85437da2899SCharles.Forsyth 		l, l->orig.x, l->orig.y, l->width, l->height, l->ascent, l->flags);
85537da2899SCharles.Forsyth 	for(i = l->items; i != nil; i = i->next)
85637da2899SCharles.Forsyth 		tktprintitem(i);
85737da2899SCharles.Forsyth 	print("\n");
85837da2899SCharles.Forsyth }
85937da2899SCharles.Forsyth 
86037da2899SCharles.Forsyth void
tktprintindex(TkTindex * ix)86137da2899SCharles.Forsyth tktprintindex(TkTindex *ix)
86237da2899SCharles.Forsyth {
86337da2899SCharles.Forsyth 	print("line=%p,item=%p,pos=%d\n", ix->line, ix->item, ix->pos);
86437da2899SCharles.Forsyth }
86537da2899SCharles.Forsyth 
86637da2899SCharles.Forsyth void
tktprinttext(TkText * tkt)86737da2899SCharles.Forsyth tktprinttext(TkText *tkt)
86837da2899SCharles.Forsyth {
86937da2899SCharles.Forsyth 	TkTline *l;
87037da2899SCharles.Forsyth 	TkTtaginfo *ti;
87137da2899SCharles.Forsyth 	TkTmarkinfo *mi;
87237da2899SCharles.Forsyth 
87337da2899SCharles.Forsyth 	for(ti=tkt->tags; ti != nil; ti=ti->next)
87437da2899SCharles.Forsyth 		print("%s{%d} ", ti->name, ti->id);
87537da2899SCharles.Forsyth 	print("\n");
87637da2899SCharles.Forsyth 	for(mi = tkt->marks; mi != nil; mi=mi->next)
87737da2899SCharles.Forsyth 		print("%s{%p} ", mi->name? mi->name : "nil", mi->cur);
87837da2899SCharles.Forsyth 	print("\n");
87937da2899SCharles.Forsyth 	print("selfirst=%p sellast=%p\n", tkt->selfirst, tkt->sellast);
88037da2899SCharles.Forsyth 
88137da2899SCharles.Forsyth 	for(l = &tkt->start; l != nil; l = l->next)
88237da2899SCharles.Forsyth 		tktprintline(l);
88337da2899SCharles.Forsyth }
88437da2899SCharles.Forsyth 
88537da2899SCharles.Forsyth /*
88637da2899SCharles.Forsyth  * Check that assumed invariants are true.
88737da2899SCharles.Forsyth  *
88837da2899SCharles.Forsyth  * - start line and end line have no items
88937da2899SCharles.Forsyth  * - all other lines have at least one item
89037da2899SCharles.Forsyth  * - start line leads to end line via next pointers
89137da2899SCharles.Forsyth  * - prev pointers point to previous lines
89237da2899SCharles.Forsyth  * - each line ends in either a TkTnewline or a TkTcontline
89337da2899SCharles.Forsyth  *    whose iline pointer points to the line itself
89437da2899SCharles.Forsyth  * - TkTcontline and TkTmark items have no tags
89537da2899SCharles.Forsyth  *    (this is so they don't get realloc'd because of tag combination)
89637da2899SCharles.Forsyth  * - all cur fields of marks point to nil or a TkTmark
89737da2899SCharles.Forsyth  * - selfirst and sellast correctly define select region
89837da2899SCharles.Forsyth  * - nlines counts the number of lines
89937da2899SCharles.Forsyth  */
90037da2899SCharles.Forsyth void
tktcheck(TkText * tkt,char * fun)90137da2899SCharles.Forsyth tktcheck(TkText *tkt, char *fun)
90237da2899SCharles.Forsyth {
90337da2899SCharles.Forsyth 	int nl, insel, selfound;
90437da2899SCharles.Forsyth 	TkTline *l;
90537da2899SCharles.Forsyth 	TkTitem *i;
90637da2899SCharles.Forsyth 	TkTmarkinfo *mi;
90737da2899SCharles.Forsyth 	TkTindex ix;
90837da2899SCharles.Forsyth 	char *prob;
90937da2899SCharles.Forsyth 
91037da2899SCharles.Forsyth 	prob = nil;
91137da2899SCharles.Forsyth 	nl = 0;
91237da2899SCharles.Forsyth 
91337da2899SCharles.Forsyth 	if(tkt->start.items != nil || tkt->end.items != nil)
91437da2899SCharles.Forsyth 		prob = "start/end has items";
91537da2899SCharles.Forsyth 	for(l = tkt->start.next; l != &tkt->end; l = l->next) {
91637da2899SCharles.Forsyth 		if(l->prev->next != l) {
91737da2899SCharles.Forsyth 			prob = "prev mismatch";
91837da2899SCharles.Forsyth 			break;
91937da2899SCharles.Forsyth 		}
92037da2899SCharles.Forsyth 		if(l->next->prev != l) {
92137da2899SCharles.Forsyth 			prob = "next mismatch";
92237da2899SCharles.Forsyth 			break;
92337da2899SCharles.Forsyth 		}
92437da2899SCharles.Forsyth 		i = l->items;
92537da2899SCharles.Forsyth 		if(i == nil) {
92637da2899SCharles.Forsyth 			prob = "empty line";
92737da2899SCharles.Forsyth 			break;
92837da2899SCharles.Forsyth 		}
92937da2899SCharles.Forsyth 		while(i->next != nil) {
93037da2899SCharles.Forsyth 			if(i->kind == TkTnewline || i->kind == TkTcontline) {
93137da2899SCharles.Forsyth 				prob = "premature end of line";
93237da2899SCharles.Forsyth 				break;
93337da2899SCharles.Forsyth 			}
93437da2899SCharles.Forsyth 			if(i->kind == TkTmark && (i->tags[0] != 0 || i->tagextra != 0)) {
93537da2899SCharles.Forsyth 				prob = "mark has tags";
93637da2899SCharles.Forsyth 				break;
93737da2899SCharles.Forsyth 			}
93837da2899SCharles.Forsyth 			i = i->next;
93937da2899SCharles.Forsyth 		}
94037da2899SCharles.Forsyth 		if(i->kind == TkTnewline)
94137da2899SCharles.Forsyth 			nl++;
94237da2899SCharles.Forsyth 		if(!(i->kind == TkTnewline || i->kind == TkTcontline)) {
94337da2899SCharles.Forsyth 			prob = "bad end of line";
94437da2899SCharles.Forsyth 			break;
94537da2899SCharles.Forsyth 		}
94637da2899SCharles.Forsyth 		if(i->kind == TkTcontline && (i->tags[0] != 0 || i->tagextra != 0)) {
94737da2899SCharles.Forsyth 			prob = "contline has tags";
94837da2899SCharles.Forsyth 			break;
94937da2899SCharles.Forsyth 		}
95037da2899SCharles.Forsyth 		if(i->iline != l) {
95137da2899SCharles.Forsyth 			prob = "bad end-of-line pointer";
95237da2899SCharles.Forsyth 			break;
95337da2899SCharles.Forsyth 		}
95437da2899SCharles.Forsyth 	}
95537da2899SCharles.Forsyth 	for(mi = tkt->marks; mi != nil; mi=mi->next) {
95637da2899SCharles.Forsyth 		if(mi->cur != nil) {
95737da2899SCharles.Forsyth 			tktstartind(tkt, &ix);
95837da2899SCharles.Forsyth 			do {
95937da2899SCharles.Forsyth 				if(ix.item->kind == TkTmark && ix.item == mi->cur)
96037da2899SCharles.Forsyth 					goto foundmark;
96137da2899SCharles.Forsyth 			} while(tktadjustind(tkt, TkTbyitem, &ix));
96237da2899SCharles.Forsyth 			prob = "bad mark cur";
96337da2899SCharles.Forsyth 			break;
96437da2899SCharles.Forsyth 		    foundmark: ;
96537da2899SCharles.Forsyth 		}
96637da2899SCharles.Forsyth 	}
96737da2899SCharles.Forsyth 	insel = 0;
96837da2899SCharles.Forsyth 	selfound = 0;
96937da2899SCharles.Forsyth 	tktstartind(tkt, &ix);
97037da2899SCharles.Forsyth 	do {
97137da2899SCharles.Forsyth 		i = ix.item;
97237da2899SCharles.Forsyth 		if(i == tkt->selfirst) {
97337da2899SCharles.Forsyth 			if(i->kind == TkTmark || i->kind == TkTcontline) {
97437da2899SCharles.Forsyth 				prob = "selfirst not on character";
97537da2899SCharles.Forsyth 				break;
97637da2899SCharles.Forsyth 			}
97737da2899SCharles.Forsyth 			if(i == tkt->sellast) {
97837da2899SCharles.Forsyth 				prob = "selfirst==sellast, not nil";
97937da2899SCharles.Forsyth 				break;
98037da2899SCharles.Forsyth 			}
98137da2899SCharles.Forsyth 			insel = 1;
98237da2899SCharles.Forsyth 			selfound = 1;
98337da2899SCharles.Forsyth 		}
98437da2899SCharles.Forsyth 		if(i == tkt->sellast) {
98537da2899SCharles.Forsyth 			if(i->kind == TkTmark || i->kind == TkTcontline) {
98637da2899SCharles.Forsyth 				prob = "sellast not on character";
98737da2899SCharles.Forsyth 				break;
98837da2899SCharles.Forsyth 			}
98937da2899SCharles.Forsyth 			insel = 0;
99037da2899SCharles.Forsyth 		}
99137da2899SCharles.Forsyth 		if(i->kind != TkTmark && i->kind != TkTcontline) {
99237da2899SCharles.Forsyth 			if(i->tags[0] & (1<<TkTselid)) {
99337da2899SCharles.Forsyth 				if(!insel) {
99437da2899SCharles.Forsyth 					prob = "sel set outside selfirst..sellast";
99537da2899SCharles.Forsyth 					break;
99637da2899SCharles.Forsyth 				}
99737da2899SCharles.Forsyth 			}
99837da2899SCharles.Forsyth 			else {
99937da2899SCharles.Forsyth 				if(insel) {
100037da2899SCharles.Forsyth 					prob = "sel not set inside selfirst..sellast";
100137da2899SCharles.Forsyth 					break;
100237da2899SCharles.Forsyth 				}
100337da2899SCharles.Forsyth 			}
100437da2899SCharles.Forsyth 		}
100537da2899SCharles.Forsyth 	} while(tktadjustind(tkt, TkTbyitem, &ix));
100637da2899SCharles.Forsyth 	if(tkt->selfirst != nil && !selfound)
100737da2899SCharles.Forsyth 		prob = "selfirst not found";
100837da2899SCharles.Forsyth 
100937da2899SCharles.Forsyth 	if(prob != nil) {
101037da2899SCharles.Forsyth 		print("tktcheck problem: %s: %s\n", fun, prob);
101137da2899SCharles.Forsyth 		tktprinttext(tkt);
101237da2899SCharles.Forsyth abort();
101337da2899SCharles.Forsyth 	}
101437da2899SCharles.Forsyth }
101537da2899SCharles.Forsyth 
101637da2899SCharles.Forsyth int
tktutfpos(char * s,int pos)101737da2899SCharles.Forsyth tktutfpos(char *s, int pos)
101837da2899SCharles.Forsyth {
101937da2899SCharles.Forsyth 	char *s1;
102037da2899SCharles.Forsyth 	int c;
102137da2899SCharles.Forsyth 	Rune r;
102237da2899SCharles.Forsyth 
102337da2899SCharles.Forsyth 	for (s1 = s; pos > 0; pos--) {
102437da2899SCharles.Forsyth 		c = *(uchar *)s1;
102537da2899SCharles.Forsyth 		if (c < Runeself) {
102637da2899SCharles.Forsyth 			if (c == '\0')
102737da2899SCharles.Forsyth 				break;
102837da2899SCharles.Forsyth 			s1++;
102937da2899SCharles.Forsyth 		}
103037da2899SCharles.Forsyth 		else
103137da2899SCharles.Forsyth 			s1 += chartorune(&r, s1);
103237da2899SCharles.Forsyth 	}
103337da2899SCharles.Forsyth 	return s1 - s;
103437da2899SCharles.Forsyth }
103537da2899SCharles.Forsyth 
103637da2899SCharles.Forsyth /*
103737da2899SCharles.Forsyth struct timerec {
103837da2899SCharles.Forsyth 	char *name;
103937da2899SCharles.Forsyth 	ulong ms;
104037da2899SCharles.Forsyth };
104137da2899SCharles.Forsyth 
104237da2899SCharles.Forsyth static struct timerec tt[100];
104337da2899SCharles.Forsyth static int ntt = 1;
104437da2899SCharles.Forsyth 
104537da2899SCharles.Forsyth int
104637da2899SCharles.Forsyth tktalloctime(char *name)
104737da2899SCharles.Forsyth {
104837da2899SCharles.Forsyth 	if(ntt >= 100)
104937da2899SCharles.Forsyth 		abort();
105037da2899SCharles.Forsyth 	tt[ntt].name = strdup(name);
105137da2899SCharles.Forsyth 	tt[ntt].ms = 0;
105237da2899SCharles.Forsyth 	return ntt++;
105337da2899SCharles.Forsyth }
105437da2899SCharles.Forsyth 
105537da2899SCharles.Forsyth void
105637da2899SCharles.Forsyth tktstarttime(int ind)
105737da2899SCharles.Forsyth {
105837da2899SCharles.Forsyth return;
105937da2899SCharles.Forsyth 	tt[ind].ms -= osmillisec();
106037da2899SCharles.Forsyth }
106137da2899SCharles.Forsyth 
106237da2899SCharles.Forsyth void
106337da2899SCharles.Forsyth tktendtime(int ind)
106437da2899SCharles.Forsyth {
106537da2899SCharles.Forsyth return;
106637da2899SCharles.Forsyth 	tt[ind].ms += osmillisec();
106737da2899SCharles.Forsyth }
106837da2899SCharles.Forsyth 
106937da2899SCharles.Forsyth void
107037da2899SCharles.Forsyth tktdumptime(void)
107137da2899SCharles.Forsyth {
107237da2899SCharles.Forsyth 	int i;
107337da2899SCharles.Forsyth 
107437da2899SCharles.Forsyth 	for(i = 1; i < ntt; i++)
107537da2899SCharles.Forsyth 		print("%s: %d\n", tt[i].name, tt[i].ms);
107637da2899SCharles.Forsyth }
107737da2899SCharles.Forsyth */
1078