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