xref: /inferno-os/libtk/canvu.c (revision c9c0d12ef55c878b0e361f9f6936bbb4c67b40fb)
137da2899SCharles.Forsyth #include <lib9.h>
237da2899SCharles.Forsyth #include <kernel.h>
337da2899SCharles.Forsyth #include "draw.h"
437da2899SCharles.Forsyth #include "tk.h"
537da2899SCharles.Forsyth #include "canvs.h"
637da2899SCharles.Forsyth 
737da2899SCharles.Forsyth char*
tkparsepts(TkTop * t,TkCpoints * i,char ** arg,int close)837da2899SCharles.Forsyth tkparsepts(TkTop *t, TkCpoints *i, char **arg, int close)
937da2899SCharles.Forsyth {
1037da2899SCharles.Forsyth 	char *s, *e;
1137da2899SCharles.Forsyth 	Point *p, *d;
1237da2899SCharles.Forsyth 	int n, npoint;
1337da2899SCharles.Forsyth 
1437da2899SCharles.Forsyth 	i->parampt = nil;
1537da2899SCharles.Forsyth 	i->drawpt = nil;
1637da2899SCharles.Forsyth 	i->bb = bbnil;
1737da2899SCharles.Forsyth 	s = *arg;
1837da2899SCharles.Forsyth 	npoint = 0;
1937da2899SCharles.Forsyth 	while(*s) {
2037da2899SCharles.Forsyth 		s = tkskip(s, " \t");
2137da2899SCharles.Forsyth 		if(*s == '-' && (s[1] < '0' || s[1] > '9'))
2237da2899SCharles.Forsyth 			break;
2337da2899SCharles.Forsyth 		while(*s && *s != ' ' && *s != '\t')
2437da2899SCharles.Forsyth 			s++;
2537da2899SCharles.Forsyth 		npoint++;
2637da2899SCharles.Forsyth 	}
2737da2899SCharles.Forsyth 
2837da2899SCharles.Forsyth 	i->parampt = mallocz(npoint*sizeof(Point), 0);
2937da2899SCharles.Forsyth 	if(i->parampt == nil)
3037da2899SCharles.Forsyth 		return TkNomem;
3137da2899SCharles.Forsyth 
3237da2899SCharles.Forsyth 	s = *arg;
3337da2899SCharles.Forsyth 	p = i->parampt;
3437da2899SCharles.Forsyth 	npoint = 0;
3537da2899SCharles.Forsyth 	while(*s) {
3637da2899SCharles.Forsyth 		e = tkfracword(t, &s, &p->x, nil);
3737da2899SCharles.Forsyth 		if(e != nil)
3837da2899SCharles.Forsyth 			goto Error;
3937da2899SCharles.Forsyth 		e = tkfracword(t, &s, &p->y, nil);
4037da2899SCharles.Forsyth 		if(e != nil)
4137da2899SCharles.Forsyth 			goto Error;
4237da2899SCharles.Forsyth 		npoint++;
4337da2899SCharles.Forsyth 		s = tkskip(s, " \t");
4437da2899SCharles.Forsyth 		if(*s == '-' && (s[1] < '0' || s[1] > '9'))
4537da2899SCharles.Forsyth 			break;
4637da2899SCharles.Forsyth 		p++;
4737da2899SCharles.Forsyth 	}
4837da2899SCharles.Forsyth 	*arg = s;
4937da2899SCharles.Forsyth 	close = (close != 0);
5037da2899SCharles.Forsyth 	i->drawpt = mallocz((npoint+close)*sizeof(Point), 0);
5137da2899SCharles.Forsyth 	if(i->drawpt == nil){
5237da2899SCharles.Forsyth 		e = TkNomem;
5337da2899SCharles.Forsyth 		goto Error;
5437da2899SCharles.Forsyth 	}
5537da2899SCharles.Forsyth 
5637da2899SCharles.Forsyth 	d = i->drawpt;
5737da2899SCharles.Forsyth 	p = i->parampt;
5837da2899SCharles.Forsyth 	for(n = 0; n < npoint; n++) {
5937da2899SCharles.Forsyth 		d->x = TKF2I(p->x);
6037da2899SCharles.Forsyth 		d->y = TKF2I(p->y);
6137da2899SCharles.Forsyth 		if(d->x < i->bb.min.x)
6237da2899SCharles.Forsyth 			i->bb.min.x = d->x;
6337da2899SCharles.Forsyth 		if(d->x > i->bb.max.x)
6437da2899SCharles.Forsyth 			i->bb.max.x = d->x;
6537da2899SCharles.Forsyth 		if(d->y < i->bb.min.y)
6637da2899SCharles.Forsyth 			i->bb.min.y = d->y;
6737da2899SCharles.Forsyth 		if(d->y > i->bb.max.y)
6837da2899SCharles.Forsyth 			i->bb.max.y = d->y;
6937da2899SCharles.Forsyth 		d++;
7037da2899SCharles.Forsyth 		p++;
7137da2899SCharles.Forsyth 	}
7237da2899SCharles.Forsyth 	if (close)
7337da2899SCharles.Forsyth 		*d = i->drawpt[0];
7437da2899SCharles.Forsyth 
7537da2899SCharles.Forsyth 	i->npoint = npoint;
7637da2899SCharles.Forsyth 	return nil;
7737da2899SCharles.Forsyth 
7837da2899SCharles.Forsyth Error:
7937da2899SCharles.Forsyth 	tkfreepoint(i);
8037da2899SCharles.Forsyth 	i->parampt = nil;
8137da2899SCharles.Forsyth 	i->drawpt = nil;
8237da2899SCharles.Forsyth 	return e;
8337da2899SCharles.Forsyth }
8437da2899SCharles.Forsyth 
8537da2899SCharles.Forsyth TkCitem*
tkcnewitem(Tk * tk,int t,int n)8637da2899SCharles.Forsyth tkcnewitem(Tk *tk, int t, int n)
8737da2899SCharles.Forsyth {
8837da2899SCharles.Forsyth 	TkCitem *i;
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth 	i = malloc(n);
9137da2899SCharles.Forsyth 	if(i == nil)
9237da2899SCharles.Forsyth 		return nil;
9337da2899SCharles.Forsyth 	memset(i, 0, n);
9437da2899SCharles.Forsyth 
9537da2899SCharles.Forsyth 	i->type = t;
9637da2899SCharles.Forsyth 	i->env = tk->env;
9737da2899SCharles.Forsyth 	i->env->ref++;
9837da2899SCharles.Forsyth 
9937da2899SCharles.Forsyth 	return i;
10037da2899SCharles.Forsyth }
10137da2899SCharles.Forsyth 
10237da2899SCharles.Forsyth /*
10337da2899SCharles.Forsyth  * expand the canvas's dirty rectangle, clipping
10437da2899SCharles.Forsyth  * appropriately to its boundaries.
10537da2899SCharles.Forsyth  */
10637da2899SCharles.Forsyth void
tkcvssetdirty(Tk * tk)10737da2899SCharles.Forsyth tkcvssetdirty(Tk *tk)
10837da2899SCharles.Forsyth {
10937da2899SCharles.Forsyth 	TkCanvas *c;
11037da2899SCharles.Forsyth 	Rectangle r;
11137da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
11237da2899SCharles.Forsyth 
11337da2899SCharles.Forsyth 	r = tkrect(tk, 0);
11437da2899SCharles.Forsyth 	if (rectclip(&r, rectsubpt(c->update, c->view)))
11537da2899SCharles.Forsyth 		combinerect(&tk->dirty, r);
11637da2899SCharles.Forsyth }
11737da2899SCharles.Forsyth 
11837da2899SCharles.Forsyth void
tkxlatepts(Point * p,int npoints,int x,int y)11937da2899SCharles.Forsyth tkxlatepts(Point *p, int npoints, int x, int y)
12037da2899SCharles.Forsyth {
12137da2899SCharles.Forsyth 	while(npoints--) {
12237da2899SCharles.Forsyth 		p->x += x;
12337da2899SCharles.Forsyth 		p->y += y;
12437da2899SCharles.Forsyth 		p++;
12537da2899SCharles.Forsyth 	}
12637da2899SCharles.Forsyth }
12737da2899SCharles.Forsyth 
12837da2899SCharles.Forsyth void
tkbbmax(Rectangle * bb,Rectangle * r)12937da2899SCharles.Forsyth tkbbmax(Rectangle *bb, Rectangle *r)
13037da2899SCharles.Forsyth {
13137da2899SCharles.Forsyth 	if(r->min.x < bb->min.x)
13237da2899SCharles.Forsyth 		bb->min.x = r->min.x;
13337da2899SCharles.Forsyth 	if(r->min.y < bb->min.y)
13437da2899SCharles.Forsyth 		bb->min.y = r->min.y;
13537da2899SCharles.Forsyth 	if(r->max.x > bb->max.x)
13637da2899SCharles.Forsyth 		bb->max.x = r->max.x;
13737da2899SCharles.Forsyth 	if(r->max.y > bb->max.y)
13837da2899SCharles.Forsyth 		bb->max.y = r->max.y;
13937da2899SCharles.Forsyth }
14037da2899SCharles.Forsyth 
14137da2899SCharles.Forsyth void
tkpolybound(Point * p,int n,Rectangle * r)14237da2899SCharles.Forsyth tkpolybound(Point *p, int n, Rectangle *r)
14337da2899SCharles.Forsyth {
14437da2899SCharles.Forsyth 	while(n--) {
14537da2899SCharles.Forsyth 		if(p->x < r->min.x)
14637da2899SCharles.Forsyth 			r->min.x = p->x;
14737da2899SCharles.Forsyth 		if(p->y < r->min.y)
14837da2899SCharles.Forsyth 			r->min.y = p->y;
14937da2899SCharles.Forsyth 		if(p->x > r->max.x)
15037da2899SCharles.Forsyth 			r->max.x = p->x;
15137da2899SCharles.Forsyth 		if(p->y > r->max.y)
15237da2899SCharles.Forsyth 			r->max.y = p->y;
15337da2899SCharles.Forsyth 		p++;
15437da2899SCharles.Forsyth 	}
15537da2899SCharles.Forsyth }
15637da2899SCharles.Forsyth 
15737da2899SCharles.Forsyth /*
15837da2899SCharles.Forsyth  * look up a tag for a canvas item.
15937da2899SCharles.Forsyth  * if n is non-nil, and the tag isn't found,
16037da2899SCharles.Forsyth  * then add it to the canvas's taglist.
16137da2899SCharles.Forsyth  * NB if there are no binds done on the
16237da2899SCharles.Forsyth  * canvas, these tags never get cleared out,
16337da2899SCharles.Forsyth  * even if nothing refers to them.
16437da2899SCharles.Forsyth  */
16537da2899SCharles.Forsyth TkName*
tkctaglook(Tk * tk,TkName * n,char * name)16637da2899SCharles.Forsyth tkctaglook(Tk* tk, TkName *n, char *name)
16737da2899SCharles.Forsyth {
16837da2899SCharles.Forsyth 	ulong h;
16937da2899SCharles.Forsyth 	TkCanvas *c;
17037da2899SCharles.Forsyth 	char *p, *s;
17137da2899SCharles.Forsyth 	TkName *f, **l;
17237da2899SCharles.Forsyth 
17337da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
17437da2899SCharles.Forsyth 
17537da2899SCharles.Forsyth 	s = name;
17637da2899SCharles.Forsyth 	if(s == nil)
17737da2899SCharles.Forsyth 		s = n->name;
17837da2899SCharles.Forsyth 
17937da2899SCharles.Forsyth 	if(strcmp(s, "current") == 0)
18037da2899SCharles.Forsyth 		return c->current;
18137da2899SCharles.Forsyth 
18237da2899SCharles.Forsyth 	h = 0;
18337da2899SCharles.Forsyth 	for(p = s; *p; p++)
18437da2899SCharles.Forsyth 		h += 3*h + *p;
18537da2899SCharles.Forsyth 
18637da2899SCharles.Forsyth 	l = &c->thash[h%TkChash];
18737da2899SCharles.Forsyth 	for(f = *l; f; f = f->link)
18837da2899SCharles.Forsyth 		if(strcmp(f->name, s) == 0)
18937da2899SCharles.Forsyth 			return f;
19037da2899SCharles.Forsyth 
19137da2899SCharles.Forsyth 	if(n == nil)
19237da2899SCharles.Forsyth 		return nil;
19337da2899SCharles.Forsyth 	n->link = *l;
19437da2899SCharles.Forsyth 	*l = n;
19537da2899SCharles.Forsyth 	return n;
19637da2899SCharles.Forsyth }
19737da2899SCharles.Forsyth 
19837da2899SCharles.Forsyth char*
tkcaddtag(Tk * tk,TkCitem * i,int new)19937da2899SCharles.Forsyth tkcaddtag(Tk *tk, TkCitem *i, int new)
20037da2899SCharles.Forsyth {
20137da2899SCharles.Forsyth 	TkCtag *t;
20237da2899SCharles.Forsyth 	TkCanvas *c;
20337da2899SCharles.Forsyth 	char buf[16];
20437da2899SCharles.Forsyth 	TkName *n, *f, *link;
20537da2899SCharles.Forsyth 
20637da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
20737da2899SCharles.Forsyth 	if(new != 0) {
20837da2899SCharles.Forsyth 		i->id = ++c->id;
20937da2899SCharles.Forsyth 		snprint(buf, sizeof(buf), "%d", i->id);
21037da2899SCharles.Forsyth 		n = tkmkname(buf);
21137da2899SCharles.Forsyth 		if(n == nil)
21237da2899SCharles.Forsyth 			return TkNomem;
21337da2899SCharles.Forsyth 		n->link = i->tags;
21437da2899SCharles.Forsyth 		i->tags = n;
21537da2899SCharles.Forsyth 	}
21637da2899SCharles.Forsyth 
21737da2899SCharles.Forsyth 	for(n = i->tags; n; n = link) {
21837da2899SCharles.Forsyth 		link = n->link;
21937da2899SCharles.Forsyth 		f = tkctaglook(tk, n, nil);
22037da2899SCharles.Forsyth 		if(n != f)
22137da2899SCharles.Forsyth 			free(n);
22237da2899SCharles.Forsyth 
22337da2899SCharles.Forsyth 		for(t = i->stag; t; t = t->itemlist)
22437da2899SCharles.Forsyth 			if(t->name == f)
22537da2899SCharles.Forsyth 				break;
22637da2899SCharles.Forsyth 		if(t == nil) {
22737da2899SCharles.Forsyth 			t = malloc(sizeof(TkCtag));
22837da2899SCharles.Forsyth 			if(t == nil) {
22937da2899SCharles.Forsyth 				tkfreename(link);
23037da2899SCharles.Forsyth 				return TkNomem;
23137da2899SCharles.Forsyth 			}
23237da2899SCharles.Forsyth 			t->name = f;
23337da2899SCharles.Forsyth 			t->taglist = f->obj;		/* add to head of items with this tag */
23437da2899SCharles.Forsyth 			f->obj = t;
23537da2899SCharles.Forsyth 			t->item = i;
23637da2899SCharles.Forsyth 			t->itemlist = i->stag;	/* add to head of tags for this item */
23737da2899SCharles.Forsyth 			i->stag = t;
23837da2899SCharles.Forsyth 		}
23937da2899SCharles.Forsyth 	}
24037da2899SCharles.Forsyth 	i->tags = nil;
24137da2899SCharles.Forsyth 
24237da2899SCharles.Forsyth 	if(new != 0) {
24337da2899SCharles.Forsyth 		i->tags = tkmkname("all");
24437da2899SCharles.Forsyth 		if(i->tags == nil)
24537da2899SCharles.Forsyth 			return TkNomem;		/* XXX - Tad: memory leak? */
24637da2899SCharles.Forsyth 		return tkcaddtag(tk, i, 0);
24737da2899SCharles.Forsyth 	}
24837da2899SCharles.Forsyth 
24937da2899SCharles.Forsyth 	return nil;
25037da2899SCharles.Forsyth }
25137da2899SCharles.Forsyth 
25237da2899SCharles.Forsyth void
tkfreepoint(TkCpoints * p)25337da2899SCharles.Forsyth tkfreepoint(TkCpoints *p)
25437da2899SCharles.Forsyth {
25537da2899SCharles.Forsyth 	free(p->drawpt);
25637da2899SCharles.Forsyth 	free(p->parampt);
25737da2899SCharles.Forsyth }
25837da2899SCharles.Forsyth 
25937da2899SCharles.Forsyth /*
26037da2899SCharles.Forsyth  * of all the items in ilist tagged with tag,
26137da2899SCharles.Forsyth  * return that tag for the first (topmost) item.
26237da2899SCharles.Forsyth  */
26337da2899SCharles.Forsyth TkCtag*
tkclasttag(TkCitem * ilist,TkCtag * tag)26437da2899SCharles.Forsyth tkclasttag(TkCitem *ilist, TkCtag* tag)
26537da2899SCharles.Forsyth {
26637da2899SCharles.Forsyth 	TkCtag *last, *t;
26737da2899SCharles.Forsyth 
26837da2899SCharles.Forsyth 	if (tag == nil || tag->taglist == nil)
26937da2899SCharles.Forsyth 		return tag;
27037da2899SCharles.Forsyth 	last = nil;
27137da2899SCharles.Forsyth 	while(ilist) {
27237da2899SCharles.Forsyth 		for(t = tag; t; t = t->taglist) {
27337da2899SCharles.Forsyth 			if(t->item == ilist) {
27437da2899SCharles.Forsyth 				last = t;
27537da2899SCharles.Forsyth 				break;
27637da2899SCharles.Forsyth 			}
27737da2899SCharles.Forsyth 		}
27837da2899SCharles.Forsyth 		ilist = ilist->next;
27937da2899SCharles.Forsyth 	}
28037da2899SCharles.Forsyth 	return last;
28137da2899SCharles.Forsyth }
28237da2899SCharles.Forsyth 
28337da2899SCharles.Forsyth /*
28437da2899SCharles.Forsyth  * of all the items in ilist tagged with tag,
28537da2899SCharles.Forsyth  * return that tag for the first (bottommost) item.
28637da2899SCharles.Forsyth  */
28737da2899SCharles.Forsyth TkCtag*
tkcfirsttag(TkCitem * ilist,TkCtag * tag)28837da2899SCharles.Forsyth tkcfirsttag(TkCitem *ilist, TkCtag* tag)
28937da2899SCharles.Forsyth {
29037da2899SCharles.Forsyth 	TkCtag *t;
29137da2899SCharles.Forsyth 
29237da2899SCharles.Forsyth 	if (tag == nil || tag->taglist == nil)
29337da2899SCharles.Forsyth 		return tag;
29437da2899SCharles.Forsyth 	for (; ilist != nil; ilist = ilist->next)
29537da2899SCharles.Forsyth 		for(t = tag; t; t = t->taglist)
29637da2899SCharles.Forsyth 			if(t->item == ilist)
29737da2899SCharles.Forsyth 				return t;
29837da2899SCharles.Forsyth 	return nil;
29937da2899SCharles.Forsyth }
30037da2899SCharles.Forsyth 
30137da2899SCharles.Forsyth void
tkmkpen(Image ** pen,TkEnv * e,Image * stipple)30237da2899SCharles.Forsyth tkmkpen(Image **pen, TkEnv *e, Image *stipple)
30337da2899SCharles.Forsyth {
30437da2899SCharles.Forsyth 	int locked;
30537da2899SCharles.Forsyth 	Display *d;
30637da2899SCharles.Forsyth 	Image *new, *fill;
30737da2899SCharles.Forsyth 
30837da2899SCharles.Forsyth 	fill = tkgc(e, TkCfill);
30937da2899SCharles.Forsyth 
31037da2899SCharles.Forsyth 	d = e->top->display;
31137da2899SCharles.Forsyth 	locked = lockdisplay(d);
31237da2899SCharles.Forsyth 	if(*pen != nil) {
31337da2899SCharles.Forsyth 		freeimage(*pen);
31437da2899SCharles.Forsyth 		*pen = nil;
31537da2899SCharles.Forsyth 	}
31637da2899SCharles.Forsyth 	if(stipple == nil) {
31737da2899SCharles.Forsyth 		if(locked)
31837da2899SCharles.Forsyth 			unlockdisplay(d);
31937da2899SCharles.Forsyth 		return;
32037da2899SCharles.Forsyth 	}
32137da2899SCharles.Forsyth 
32237da2899SCharles.Forsyth 	if(fill == nil)
32337da2899SCharles.Forsyth 		fill = d->black;
32437da2899SCharles.Forsyth 	new = allocimage(d, stipple->r, RGBA32, 1, DTransparent);	/* XXX RGBA32 is excessive sometimes... */
32537da2899SCharles.Forsyth 	if (new != nil)
32637da2899SCharles.Forsyth 		draw(new, stipple->r, fill, stipple, ZP);
32737da2899SCharles.Forsyth 	else
32837da2899SCharles.Forsyth 		new = fill;
32937da2899SCharles.Forsyth 	if(locked)
33037da2899SCharles.Forsyth 		unlockdisplay(d);
33137da2899SCharles.Forsyth 	*pen = new;
33237da2899SCharles.Forsyth }
33337da2899SCharles.Forsyth 
33437da2899SCharles.Forsyth Point
tkcvsanchor(Point dp,int w,int h,int anchor)33537da2899SCharles.Forsyth tkcvsanchor(Point dp, int w, int h, int anchor)
33637da2899SCharles.Forsyth {
33737da2899SCharles.Forsyth 	Point o;
33837da2899SCharles.Forsyth 
33937da2899SCharles.Forsyth 	if(anchor & Tknorth)
34037da2899SCharles.Forsyth 		o.y = dp.y;
341*c9c0d12eSforsyth 	else if(anchor & Tksouth)
34237da2899SCharles.Forsyth 		o.y = dp.y - h;
34337da2899SCharles.Forsyth 	else
34437da2899SCharles.Forsyth 		o.y = dp.y - h/2;
34537da2899SCharles.Forsyth 
34637da2899SCharles.Forsyth 	if(anchor & Tkwest)
34737da2899SCharles.Forsyth 		o.x = dp.x;
348*c9c0d12eSforsyth 	else if(anchor & Tkeast)
34937da2899SCharles.Forsyth 		o.x = dp.x - w;
35037da2899SCharles.Forsyth 	else
35137da2899SCharles.Forsyth 		o.x = dp.x - w/2;
35237da2899SCharles.Forsyth 
35337da2899SCharles.Forsyth 	return o;
35437da2899SCharles.Forsyth }
35537da2899SCharles.Forsyth 
35637da2899SCharles.Forsyth static TkCitem*
tkcvsmousefocus(TkCanvas * c,Point p)35737da2899SCharles.Forsyth tkcvsmousefocus(TkCanvas *c, Point p)
35837da2899SCharles.Forsyth {
35937da2899SCharles.Forsyth 	TkCitem *i, *s;
36037da2899SCharles.Forsyth 	int (*hit)(TkCitem*, Point);
36137da2899SCharles.Forsyth 
36237da2899SCharles.Forsyth 	if (c->grab != nil)
36337da2899SCharles.Forsyth 		return c->grab;
36437da2899SCharles.Forsyth 	s = nil;
36537da2899SCharles.Forsyth 	for(i = c->head; i; i = i->next)
36637da2899SCharles.Forsyth 		if(ptinrect(p, i->p.bb)) {
36737da2899SCharles.Forsyth 			if ((hit = tkcimethod[i->type].hit) != nil && !(*hit)(i, p))
36837da2899SCharles.Forsyth 				continue;
36937da2899SCharles.Forsyth 			s = i;
37037da2899SCharles.Forsyth 		}
37137da2899SCharles.Forsyth 
37237da2899SCharles.Forsyth 	return s;
37337da2899SCharles.Forsyth }
37437da2899SCharles.Forsyth 
37537da2899SCharles.Forsyth Tk*
tkcvsinwindow(Tk * tk,Point * p)37637da2899SCharles.Forsyth tkcvsinwindow(Tk *tk, Point *p)
37737da2899SCharles.Forsyth {
37837da2899SCharles.Forsyth 	TkCanvas *c;
37937da2899SCharles.Forsyth 	TkCitem *i;
38037da2899SCharles.Forsyth 	Point q;
38137da2899SCharles.Forsyth 	TkCwind *w;
38237da2899SCharles.Forsyth 
38337da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
38437da2899SCharles.Forsyth 
38537da2899SCharles.Forsyth 	q = addpt(*p, c->view);
38637da2899SCharles.Forsyth 	i = tkcvsmousefocus(c, addpt(*p, c->view));
38737da2899SCharles.Forsyth 	if (i == nil || i->type != TkCVwindow)
38837da2899SCharles.Forsyth 		return tk;
38937da2899SCharles.Forsyth 	w = TKobj(TkCwind, i);
39037da2899SCharles.Forsyth 	if (w->sub == nil)
39137da2899SCharles.Forsyth 		return tk;
39237da2899SCharles.Forsyth 	p->x = q.x - (i->p.bb.min.x + w->sub->borderwidth);
39337da2899SCharles.Forsyth 	p->y = q.y - (i->p.bb.min.y + w->sub->borderwidth);
39437da2899SCharles.Forsyth 	return w->sub;
39537da2899SCharles.Forsyth }
39637da2899SCharles.Forsyth 
39737da2899SCharles.Forsyth static Tk*
tkcvsmouseinsub(TkCwind * w,TkMouse m)39837da2899SCharles.Forsyth tkcvsmouseinsub(TkCwind *w, TkMouse m)
39937da2899SCharles.Forsyth {
40037da2899SCharles.Forsyth 	Point g, mp;
40137da2899SCharles.Forsyth 	int bd;
40237da2899SCharles.Forsyth 
40337da2899SCharles.Forsyth 	g = tkposn(w->sub);
40437da2899SCharles.Forsyth 	bd = w->sub->borderwidth;
40537da2899SCharles.Forsyth 	mp.x = m.x - (g.x + bd);
40637da2899SCharles.Forsyth 	mp.y = m.y - (g.y + bd);
40737da2899SCharles.Forsyth 	return tkinwindow(w->sub, mp, 0);
40837da2899SCharles.Forsyth }
40937da2899SCharles.Forsyth 
41037da2899SCharles.Forsyth static Tk*
tkcvsdeliver(Tk * tk,TkCitem * i,int event,void * data)41137da2899SCharles.Forsyth tkcvsdeliver(Tk *tk, TkCitem *i, int event, void *data)
41237da2899SCharles.Forsyth {
41337da2899SCharles.Forsyth 	Tk *ftk, *dest;
41437da2899SCharles.Forsyth 	TkCtag *t;
41537da2899SCharles.Forsyth 	TkCwind *w;
41637da2899SCharles.Forsyth 	TkAction *a;
41737da2899SCharles.Forsyth 
41837da2899SCharles.Forsyth 	if(i->type == TkCVwindow) {
41937da2899SCharles.Forsyth 		dest = nil;
42037da2899SCharles.Forsyth 		w = TKobj(TkCwind, i);
42137da2899SCharles.Forsyth 		if(w->sub == nil)
42237da2899SCharles.Forsyth 			return nil;
42337da2899SCharles.Forsyth 
42437da2899SCharles.Forsyth 		if(!(event & TkKey) && (event & TkEmouse)) {
42537da2899SCharles.Forsyth 			ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
42637da2899SCharles.Forsyth 			if(ftk != w->focus) {
42737da2899SCharles.Forsyth 				tkdeliver(w->focus, TkLeave, data);
4285849851aSforsyth if(0)print("focus %p %q %p %q\n", w->sub, tkname(w->sub), ftk, tkname(ftk));
42937da2899SCharles.Forsyth 				tkdeliver(ftk, TkEnter, data);
43037da2899SCharles.Forsyth 				w->focus = ftk;
43137da2899SCharles.Forsyth 			}
43237da2899SCharles.Forsyth 			if(ftk != nil)
43337da2899SCharles.Forsyth 				dest = tkdeliver(ftk, event, data);
4345849851aSforsyth 		} else {
43537da2899SCharles.Forsyth 			if(event & TkLeave) {
43637da2899SCharles.Forsyth 				tkdeliver(w->focus, TkLeave, data);
43737da2899SCharles.Forsyth 				w->focus = nil;
43837da2899SCharles.Forsyth 			} else if(event & TkEnter) {
43937da2899SCharles.Forsyth 				ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
44037da2899SCharles.Forsyth 				tkdeliver(ftk, TkEnter, data);
44137da2899SCharles.Forsyth 				w->focus = ftk;
44237da2899SCharles.Forsyth 			} else
44337da2899SCharles.Forsyth 				dest = tkdeliver(w->sub, event, data);
44437da2899SCharles.Forsyth 		}
44537da2899SCharles.Forsyth 		return dest;
44637da2899SCharles.Forsyth 	}
44737da2899SCharles.Forsyth 
44837da2899SCharles.Forsyth 	for(t = i->stag; t != nil; t = t->itemlist) {
44937da2899SCharles.Forsyth 		a = t->name->prop.binds;
45037da2899SCharles.Forsyth 		if(a != nil)
45137da2899SCharles.Forsyth 			tksubdeliver(tk, a, event, data, 0);
45237da2899SCharles.Forsyth 	}
45337da2899SCharles.Forsyth 	return nil;
45437da2899SCharles.Forsyth }
45537da2899SCharles.Forsyth 
45637da2899SCharles.Forsyth Tk*
tkcvsevent(Tk * tk,int event,void * data)45737da2899SCharles.Forsyth tkcvsevent(Tk *tk, int event, void *data)
45837da2899SCharles.Forsyth {
45937da2899SCharles.Forsyth 	TkMouse m;
46037da2899SCharles.Forsyth 	TkCitem *f;
46137da2899SCharles.Forsyth 	Point mp, g;
46237da2899SCharles.Forsyth 	TkCanvas *c;
46337da2899SCharles.Forsyth 	Tk *dest;
46437da2899SCharles.Forsyth 
46537da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
46637da2899SCharles.Forsyth 
46737da2899SCharles.Forsyth 	if(event == TkLeave && c->mouse != nil) {
46837da2899SCharles.Forsyth 		tkcvsdeliver(tk, c->mouse, TkLeave, data);
46937da2899SCharles.Forsyth 		c->mouse = nil;
47037da2899SCharles.Forsyth 	}
47137da2899SCharles.Forsyth 
47237da2899SCharles.Forsyth 	dest = nil;
47337da2899SCharles.Forsyth 	if(!(event & TkKey) && (event & TkEmouse) || (event & TkEnter)) {
47437da2899SCharles.Forsyth 		m = *(TkMouse*)data;
47537da2899SCharles.Forsyth 		g = tkposn(tk);
47637da2899SCharles.Forsyth 		mp.x = (m.x - g.x - tk->borderwidth) + c->view.x;
47737da2899SCharles.Forsyth 		mp.y = (m.y - g.y - tk->borderwidth) + c->view.y;
47837da2899SCharles.Forsyth 		f = tkcvsmousefocus(c, mp);
47937da2899SCharles.Forsyth 		if(c->mouse != f) {
48037da2899SCharles.Forsyth 			if(c->mouse != nil) {
48137da2899SCharles.Forsyth 				tkcvsdeliver(tk, c->mouse, TkLeave, data);
48237da2899SCharles.Forsyth 				c->current->obj = nil;
48337da2899SCharles.Forsyth 			}
48437da2899SCharles.Forsyth 			if(f != nil) {
48537da2899SCharles.Forsyth 				c->current->obj = &c->curtag;
48637da2899SCharles.Forsyth 				c->curtag.item = f;
48737da2899SCharles.Forsyth 				tkcvsdeliver(tk, f, TkEnter, data);
48837da2899SCharles.Forsyth 			}
48937da2899SCharles.Forsyth 			c->mouse = f;
49037da2899SCharles.Forsyth 		}
49137da2899SCharles.Forsyth 		f = c->mouse;
49237da2899SCharles.Forsyth 		if(f != nil && (event & TkEnter) == 0)
49337da2899SCharles.Forsyth 			dest = tkcvsdeliver(tk, f, event, &m);
49437da2899SCharles.Forsyth 	}
49537da2899SCharles.Forsyth 
49637da2899SCharles.Forsyth 	if(event & TkKey) {
49737da2899SCharles.Forsyth 		f = c->focus;
49837da2899SCharles.Forsyth 		if(f != nil)
49937da2899SCharles.Forsyth 			tkcvsdeliver(tk, f, event, data);
50037da2899SCharles.Forsyth 	}
50137da2899SCharles.Forsyth 	if(dest == nil)
50237da2899SCharles.Forsyth 		tksubdeliver(tk, tk->binds, event, data, 0);
50337da2899SCharles.Forsyth 	return dest;
50437da2899SCharles.Forsyth }
5055849851aSforsyth 
5065849851aSforsyth /*
5075849851aSforsyth  * debugging
5085849851aSforsyth  */
5095849851aSforsyth void
tkcvsdump(Tk * tk)5105849851aSforsyth tkcvsdump(Tk *tk)
5115849851aSforsyth {
5125849851aSforsyth 	TkCanvas *c;
5135849851aSforsyth 	TkCitem *it;
5145849851aSforsyth 	TkCwind *w;
5155849851aSforsyth 	char v1[Tkminitem], v2[Tkminitem];
5165849851aSforsyth 	int i;
5175849851aSforsyth 
5185849851aSforsyth 	if(tk == nil)
5195849851aSforsyth 		return;
5205849851aSforsyth 	c = TKobj(TkCanvas, tk);
5215849851aSforsyth 	tkfprint(v1, c->width);
5225849851aSforsyth 	tkfprint(v2, c->height);
5235849851aSforsyth 	print("%q configure -width %s -height %s", tkname(tk), v1, v2);
5245849851aSforsyth 	print(" # focus %#p mouse %#p grab %#p\n", c->focus, c->mouse, c->grab);
5255849851aSforsyth 	for(it = c->head; it != nil; it = it->next){
5265849851aSforsyth 		print("%q create %q", tkname(tk), tkcimethod[it->type].name);
5275849851aSforsyth 		for(i = 0; i < it->p.npoint; i++){
5285849851aSforsyth 			tkfprint(v1, it->p.parampt[i].x);
5295849851aSforsyth 			tkfprint(v2, it->p.parampt[i].y);
5305849851aSforsyth 			print(" %s %s", v1, v2);
5315849851aSforsyth 		}
5325849851aSforsyth 		if(it->type == TkCVwindow){
5335849851aSforsyth 			w = TKobj(TkCwind, it);
5345849851aSforsyth 			if(w->sub != nil)
5355849851aSforsyth 				print(" -window %q", tkname(w->sub));
5365849851aSforsyth 			print(" # item %#p id %d sub %#p focus [%#p %q]\n", it, it->id, w->sub, w->focus, tkname(w->focus));
5375849851aSforsyth 		}else
5385849851aSforsyth 			print("# item %#p id %d\n", it, it->id);
5395849851aSforsyth 	}
5405849851aSforsyth }
541