xref: /inferno-os/libtk/windw.c (revision c9c0d12ef55c878b0e361f9f6936bbb4c67b40fb)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "tk.h"
437da2899SCharles.Forsyth #include "canvs.h"
537da2899SCharles.Forsyth #include "textw.h"
637da2899SCharles.Forsyth #include "kernel.h"
737da2899SCharles.Forsyth 
837da2899SCharles.Forsyth TkCtxt*
tknewctxt(Display * d)937da2899SCharles.Forsyth tknewctxt(Display *d)
1037da2899SCharles.Forsyth {
1137da2899SCharles.Forsyth 	TkCtxt *c;
1237da2899SCharles.Forsyth 	c = malloc(sizeof(TkCtxt));
1337da2899SCharles.Forsyth 	if(c == nil)
1437da2899SCharles.Forsyth 		return nil;
1537da2899SCharles.Forsyth 	c->lock = libqlalloc();
1637da2899SCharles.Forsyth 	if(c->lock == nil){
1737da2899SCharles.Forsyth 		free(c);
1837da2899SCharles.Forsyth 		return nil;
1937da2899SCharles.Forsyth 	}
2037da2899SCharles.Forsyth 	if (tkextnnewctxt(c) != 0) {
2137da2899SCharles.Forsyth 		free(c->lock);
2237da2899SCharles.Forsyth 		free(c);
2337da2899SCharles.Forsyth 		return nil;
2437da2899SCharles.Forsyth 	}
2537da2899SCharles.Forsyth 	c->display = d;
2637da2899SCharles.Forsyth 	return c;
2737da2899SCharles.Forsyth }
2837da2899SCharles.Forsyth 
2937da2899SCharles.Forsyth void
tkfreectxt(TkCtxt * c)3037da2899SCharles.Forsyth tkfreectxt(TkCtxt *c)
3137da2899SCharles.Forsyth {
3237da2899SCharles.Forsyth 	int locked;
3337da2899SCharles.Forsyth 	Display *d;
3437da2899SCharles.Forsyth 
3537da2899SCharles.Forsyth 	if(c == nil)
3637da2899SCharles.Forsyth 		return;
3737da2899SCharles.Forsyth 
3837da2899SCharles.Forsyth 	tkextnfreectxt(c);
3937da2899SCharles.Forsyth 
4037da2899SCharles.Forsyth 	d = c->display;
4137da2899SCharles.Forsyth 	locked = lockdisplay(d);
4237da2899SCharles.Forsyth 	tkfreecolcache(c);
4337da2899SCharles.Forsyth 	freeimage(c->i);
4437da2899SCharles.Forsyth 	freeimage(c->ia);
4537da2899SCharles.Forsyth 	if(locked)
4637da2899SCharles.Forsyth 		unlockdisplay(d);
4737da2899SCharles.Forsyth 	libqlfree(c->lock);
4837da2899SCharles.Forsyth 	free(c);
4937da2899SCharles.Forsyth }
5037da2899SCharles.Forsyth 
5137da2899SCharles.Forsyth Image*
tkitmp(TkEnv * e,Point p,int fillcol)5237da2899SCharles.Forsyth tkitmp(TkEnv *e, Point p, int fillcol)
5337da2899SCharles.Forsyth {
5437da2899SCharles.Forsyth 	Image *i, **ip;
5537da2899SCharles.Forsyth 	TkTop *t;
5637da2899SCharles.Forsyth 	TkCtxt *ti;
5737da2899SCharles.Forsyth 	Display *d;
5837da2899SCharles.Forsyth 	Rectangle r;
5937da2899SCharles.Forsyth 	ulong pix;
6037da2899SCharles.Forsyth 	int alpha;
6137da2899SCharles.Forsyth 
6237da2899SCharles.Forsyth 	t = e->top;
6337da2899SCharles.Forsyth 	ti = t->ctxt;
6437da2899SCharles.Forsyth 	d = t->display;
6537da2899SCharles.Forsyth 
6637da2899SCharles.Forsyth 	pix = e->colors[fillcol];
6737da2899SCharles.Forsyth 	alpha = (pix & 0xff) != 0xff;
6837da2899SCharles.Forsyth 	ip = alpha ? &ti->ia : &ti->i;
6937da2899SCharles.Forsyth 
7037da2899SCharles.Forsyth 	if(*ip != nil) {
7137da2899SCharles.Forsyth 		i = *ip;
7237da2899SCharles.Forsyth 		if(p.x <= i->r.max.x && p.y <= i->r.max.y) {
7337da2899SCharles.Forsyth 			r.min = ZP;
7437da2899SCharles.Forsyth 			r.max = p;
7537da2899SCharles.Forsyth 			if (alpha)
7637da2899SCharles.Forsyth 				drawop(i, r, nil, nil, ZP, Clear);
7737da2899SCharles.Forsyth 			draw(i, r, tkgc(e, fillcol), nil, ZP);
7837da2899SCharles.Forsyth 			return i;
7937da2899SCharles.Forsyth 		}
8037da2899SCharles.Forsyth 		r = i->r;
8137da2899SCharles.Forsyth 		freeimage(i);
8237da2899SCharles.Forsyth 		if(p.x < r.max.x)
8337da2899SCharles.Forsyth 			p.x = r.max.x;
8437da2899SCharles.Forsyth 		if(p.y < r.max.y)
8537da2899SCharles.Forsyth 			p.y = r.max.y;
8637da2899SCharles.Forsyth 	}
8737da2899SCharles.Forsyth 
8837da2899SCharles.Forsyth 	r.min = ZP;
8937da2899SCharles.Forsyth 	r.max = p;
9037da2899SCharles.Forsyth 	*ip = allocimage(d, r, alpha?RGBA32:d->image->chan, 0, pix);
9137da2899SCharles.Forsyth 
9237da2899SCharles.Forsyth 	return *ip;
9337da2899SCharles.Forsyth }
9437da2899SCharles.Forsyth 
9537da2899SCharles.Forsyth void
tkgeomchg(Tk * tk,TkGeom * g,int bd)9637da2899SCharles.Forsyth tkgeomchg(Tk *tk, TkGeom *g, int bd)
9737da2899SCharles.Forsyth {
9837da2899SCharles.Forsyth 	int w, h;
9937da2899SCharles.Forsyth 	void (*geomfn)(Tk*);
10037da2899SCharles.Forsyth 	if(memcmp(&tk->req, g, sizeof(TkGeom)) == 0 && bd == tk->borderwidth)
10137da2899SCharles.Forsyth 		return;
10237da2899SCharles.Forsyth 
10337da2899SCharles.Forsyth 	geomfn = tkmethod[tk->type]->geom;
10437da2899SCharles.Forsyth 	if(geomfn != nil)
10537da2899SCharles.Forsyth 		geomfn(tk);
10637da2899SCharles.Forsyth 
10737da2899SCharles.Forsyth 	if(tk->master != nil) {
10837da2899SCharles.Forsyth 		tkpackqit(tk->master);
10937da2899SCharles.Forsyth 		tkrunpack(tk->env->top);
11037da2899SCharles.Forsyth 	}
11137da2899SCharles.Forsyth 	else
11237da2899SCharles.Forsyth 	if(tk->geom != nil) {
11337da2899SCharles.Forsyth 		w = tk->req.width;
11437da2899SCharles.Forsyth 		h = tk->req.height;
11537da2899SCharles.Forsyth 		tk->req.width = 0;
11637da2899SCharles.Forsyth 		tk->req.height = 0;
11737da2899SCharles.Forsyth 		tk->geom(tk, tk->act.x, tk->act.y, w, h);
11837da2899SCharles.Forsyth 		if (tk->slave) {
11937da2899SCharles.Forsyth 			tkpackqit(tk);
12037da2899SCharles.Forsyth 			tkrunpack(tk->env->top);
12137da2899SCharles.Forsyth 		}
12237da2899SCharles.Forsyth 	}
12337da2899SCharles.Forsyth 	tkdeliver(tk, TkConfigure, g);
12437da2899SCharles.Forsyth }
12537da2899SCharles.Forsyth 
12637da2899SCharles.Forsyth /*
12737da2899SCharles.Forsyth  * return the widget within tk with by point p (in widget coords)
12837da2899SCharles.Forsyth  */
12937da2899SCharles.Forsyth Tk*
tkinwindow(Tk * tk,Point p,int descend)13037da2899SCharles.Forsyth tkinwindow(Tk *tk, Point p, int descend)
13137da2899SCharles.Forsyth {
13237da2899SCharles.Forsyth 	Tk *f;
13337da2899SCharles.Forsyth 	Point q;
13437da2899SCharles.Forsyth 	if (ptinrect(p, tkrect(tk, 1)) == 0)
13537da2899SCharles.Forsyth 		return nil;
13637da2899SCharles.Forsyth 	for (;;) {
13737da2899SCharles.Forsyth 		if (descend && tkmethod[tk->type]->inwindow != nil)
13837da2899SCharles.Forsyth 			f = tkmethod[tk->type]->inwindow(tk, &p);
13937da2899SCharles.Forsyth 		else {
140*6e425a9dSCharles.Forsyth 			q = p;
14137da2899SCharles.Forsyth 			for (f = tk->slave; f; f = f->next) {
14237da2899SCharles.Forsyth 				q.x = p.x - (f->act.x + f->borderwidth);
14337da2899SCharles.Forsyth 				q.y = p.y - (f->act.y + f->borderwidth);
14437da2899SCharles.Forsyth 				if (ptinrect(q, tkrect(f, 1)))
14537da2899SCharles.Forsyth 					break;
14637da2899SCharles.Forsyth 			}
14737da2899SCharles.Forsyth 			p = q;
14837da2899SCharles.Forsyth 		}
14937da2899SCharles.Forsyth 		if (f == nil || f == tk)
15037da2899SCharles.Forsyth 			return tk;
15137da2899SCharles.Forsyth 		tk = f;
15237da2899SCharles.Forsyth 	}
15337da2899SCharles.Forsyth }
15437da2899SCharles.Forsyth 
15537da2899SCharles.Forsyth Tk*
tkfindfocus(TkTop * t,int x,int y,int descend)15637da2899SCharles.Forsyth tkfindfocus(TkTop *t, int x, int y, int descend)
15737da2899SCharles.Forsyth {
15837da2899SCharles.Forsyth 	Point p, q;
15937da2899SCharles.Forsyth 	Tk *tk, *f;
16037da2899SCharles.Forsyth 	TkWin *tkw;
16137da2899SCharles.Forsyth 	p.x = x;
16237da2899SCharles.Forsyth 	p.y = y;
16337da2899SCharles.Forsyth 	for(f = t->windows; f != nil; f = TKobj(TkWin, f)->next) {
16437da2899SCharles.Forsyth 		assert(f->flag&Tkwindow);
16537da2899SCharles.Forsyth 		if(f->flag & Tkmapped) {
16637da2899SCharles.Forsyth 			tkw = TKobj(TkWin, f);
16737da2899SCharles.Forsyth 			q.x = p.x - (tkw->act.x+f->borderwidth);
16837da2899SCharles.Forsyth 			q.y = p.y - (tkw->act.y+f->borderwidth);
16937da2899SCharles.Forsyth 			tk = tkinwindow(f, q, descend);
17037da2899SCharles.Forsyth 			if(tk != nil)
17137da2899SCharles.Forsyth 				return tk;
17237da2899SCharles.Forsyth 		}
17337da2899SCharles.Forsyth 	}
17437da2899SCharles.Forsyth 	return nil;
17537da2899SCharles.Forsyth }
17637da2899SCharles.Forsyth 
17737da2899SCharles.Forsyth void
tkmovewin(Tk * tk,Point p)17837da2899SCharles.Forsyth tkmovewin(Tk *tk, Point p)
17937da2899SCharles.Forsyth {
18037da2899SCharles.Forsyth 	TkWin *tkw;
18137da2899SCharles.Forsyth 	if((tk->flag & Tkwindow) == 0)
18237da2899SCharles.Forsyth 		return;
18337da2899SCharles.Forsyth 	tkw = TKobj(TkWin, tk);
18437da2899SCharles.Forsyth 	if(! eqpt(p, tkw->req)){
18537da2899SCharles.Forsyth 		tkw->req = p;
18637da2899SCharles.Forsyth 		tkw->changed = 1;
18737da2899SCharles.Forsyth 	}
18837da2899SCharles.Forsyth }
18937da2899SCharles.Forsyth 
19037da2899SCharles.Forsyth void
tkmoveresize(Tk * tk,int x,int y,int w,int h)19137da2899SCharles.Forsyth tkmoveresize(Tk *tk, int x, int y, int w, int h)
19237da2899SCharles.Forsyth {
19337da2899SCharles.Forsyth 	TkWin *tkw;
19437da2899SCharles.Forsyth 	USED(x);
19537da2899SCharles.Forsyth 	USED(y);
19637da2899SCharles.Forsyth 	assert(tk->flag&Tkwindow);
19737da2899SCharles.Forsyth 	tkw = TKobj(TkWin, tk);
19837da2899SCharles.Forsyth 	if(w < 0)
19937da2899SCharles.Forsyth 		w = 0;
20037da2899SCharles.Forsyth 	if(h < 0)
20137da2899SCharles.Forsyth 		h = 0;
20237da2899SCharles.Forsyth //print("moveresize %s %d %d +[%d %d], callerpc %lux\n", tk->name->name, x, y, w, h, getcallerpc(&tk));
20337da2899SCharles.Forsyth 	tk->req.width = w;
20437da2899SCharles.Forsyth 	tk->req.height = h;
20537da2899SCharles.Forsyth 	tk->act = tk->req;
20637da2899SCharles.Forsyth 	/* XXX perhaps should actually suspend the window here? */
20737da2899SCharles.Forsyth 	tkw->changed = 1;
20837da2899SCharles.Forsyth }
20937da2899SCharles.Forsyth 
21037da2899SCharles.Forsyth static void
tkexterncreatewin(Tk * tk,Rectangle r)21137da2899SCharles.Forsyth tkexterncreatewin(Tk *tk, Rectangle r)
21237da2899SCharles.Forsyth {
21337da2899SCharles.Forsyth 	TkWin *tkw;
21437da2899SCharles.Forsyth 	TkTop *top;
21537da2899SCharles.Forsyth 	char *name;
21637da2899SCharles.Forsyth 
21737da2899SCharles.Forsyth 	top = tk->env->top;
21837da2899SCharles.Forsyth 	tkw = TKobj(TkWin, tk);
21937da2899SCharles.Forsyth 
22037da2899SCharles.Forsyth 	/*
22137da2899SCharles.Forsyth 	 * for a choicebutton menu, use the name of the choicebutton which created it
22237da2899SCharles.Forsyth 	 */
22337da2899SCharles.Forsyth 	if(tk->name == nil){
22437da2899SCharles.Forsyth 		name = tkw->cbname;
22537da2899SCharles.Forsyth 		assert(name != nil);
22637da2899SCharles.Forsyth 	} else
22737da2899SCharles.Forsyth 		name = tk->name->name;
22837da2899SCharles.Forsyth 
22937da2899SCharles.Forsyth 	tkw->reqid++;
23037da2899SCharles.Forsyth 	tkwreq(top, "!reshape %s %d %d %d %d %d", name, tkw->reqid, r.min.x, r.min.y, r.max.x, r.max.y);
23137da2899SCharles.Forsyth 	tkw->changed = 0;
23237da2899SCharles.Forsyth 	tk->flag |= Tksuspended;
23337da2899SCharles.Forsyth }
23437da2899SCharles.Forsyth 
23537da2899SCharles.Forsyth /*
23637da2899SCharles.Forsyth  * return non-zero if the window size has changed (XXX choose better return value/function name!)
23737da2899SCharles.Forsyth  */
23837da2899SCharles.Forsyth int
tkupdatewinsize(Tk * tk)23937da2899SCharles.Forsyth tkupdatewinsize(Tk *tk)
24037da2899SCharles.Forsyth {
24137da2899SCharles.Forsyth 	TkWin *tkw;
24237da2899SCharles.Forsyth 	Image *previ;
24337da2899SCharles.Forsyth 	Rectangle r, or;
24437da2899SCharles.Forsyth 	int bw2;
24537da2899SCharles.Forsyth 
24637da2899SCharles.Forsyth 	tkw = TKobj(TkWin, tk);
24737da2899SCharles.Forsyth 	bw2 = 2*tk->borderwidth;
24837da2899SCharles.Forsyth 	r.min.x = tkw->req.x;
24937da2899SCharles.Forsyth 	r.min.y = tkw->req.y;
25037da2899SCharles.Forsyth 	r.max.x = r.min.x + tk->act.width + bw2;
25137da2899SCharles.Forsyth 	r.max.y = r.min.y + tk->act.height + bw2;
25237da2899SCharles.Forsyth 	previ = tkw->image;
25337da2899SCharles.Forsyth 	if(previ != nil){
25437da2899SCharles.Forsyth 		or.min.x = tkw->act.x;
25537da2899SCharles.Forsyth 		or.min.y = tkw->act.y;
25637da2899SCharles.Forsyth 		or.max.x = tkw->act.x + Dx(previ->r);
25737da2899SCharles.Forsyth 		or.max.y = tkw->act.y + Dy(previ->r);
25837da2899SCharles.Forsyth 		if(eqrect(or, r))
25937da2899SCharles.Forsyth 			return 0;
26037da2899SCharles.Forsyth 	}
26137da2899SCharles.Forsyth 	tkexterncreatewin(tk, r);
26237da2899SCharles.Forsyth 	return 1;
26337da2899SCharles.Forsyth }
26437da2899SCharles.Forsyth 
26537da2899SCharles.Forsyth static char*
tkdrawslaves1(Tk * tk,Point orig,Image * dst,int * dirty)26637da2899SCharles.Forsyth tkdrawslaves1(Tk *tk, Point orig, Image *dst, int *dirty)
26737da2899SCharles.Forsyth {
26837da2899SCharles.Forsyth 	Tk *f;
26937da2899SCharles.Forsyth 	char *e = nil;
27037da2899SCharles.Forsyth 	Point worig;
27137da2899SCharles.Forsyth 	Rectangle r, oclip;
27237da2899SCharles.Forsyth 
27337da2899SCharles.Forsyth 	worig.x = orig.x + tk->act.x + tk->borderwidth;
27437da2899SCharles.Forsyth 	worig.y = orig.y + tk->act.y + tk->borderwidth;
27537da2899SCharles.Forsyth 
27637da2899SCharles.Forsyth 	r = rectaddpt(tk->dirty, worig);
27737da2899SCharles.Forsyth 	if (Dx(r) > 0 && rectXrect(r, dst->clipr)) {
27837da2899SCharles.Forsyth 		e = tkmethod[tk->type]->draw(tk, orig);
27937da2899SCharles.Forsyth 		tk->dirty = bbnil;
28037da2899SCharles.Forsyth 		*dirty = 1;
28137da2899SCharles.Forsyth 	}
28237da2899SCharles.Forsyth 	if(e != nil)
28337da2899SCharles.Forsyth 		return e;
28437da2899SCharles.Forsyth 
28537da2899SCharles.Forsyth 	/*
28637da2899SCharles.Forsyth 	 * grids need clipping
28737da2899SCharles.Forsyth 	 * XXX BUG: they can't, 'cos text widgets don't clip appropriately.
28837da2899SCharles.Forsyth 	 */
28937da2899SCharles.Forsyth 	if (tk->grid != nil) {
29037da2899SCharles.Forsyth 		r = rectaddpt(tkrect(tk, 0), worig);
29137da2899SCharles.Forsyth 		if (rectclip(&r, dst->clipr) == 0)
29237da2899SCharles.Forsyth 			return nil;
29337da2899SCharles.Forsyth 		oclip = dst->clipr;
29437da2899SCharles.Forsyth 		replclipr(dst, 0, r);
29537da2899SCharles.Forsyth 	}
29637da2899SCharles.Forsyth 	for(f = tk->slave; e == nil && f; f = f->next)
29737da2899SCharles.Forsyth 		e = tkdrawslaves1(f, worig, dst, dirty);
29837da2899SCharles.Forsyth 	if (tk->grid != nil)
29937da2899SCharles.Forsyth 		replclipr(dst, 0, oclip);
30037da2899SCharles.Forsyth 	return e;
30137da2899SCharles.Forsyth }
30237da2899SCharles.Forsyth 
30337da2899SCharles.Forsyth char*
tkdrawslaves(Tk * tk,Point orig,int * dirty)30437da2899SCharles.Forsyth tkdrawslaves(Tk *tk, Point orig, int *dirty)
30537da2899SCharles.Forsyth {
30637da2899SCharles.Forsyth 	Image *i;
30737da2899SCharles.Forsyth 	char *e;
30837da2899SCharles.Forsyth 	i = tkimageof(tk);
30937da2899SCharles.Forsyth 	if (i == nil)
31037da2899SCharles.Forsyth 		return nil;
31137da2899SCharles.Forsyth 	e =  tkdrawslaves1(tk, orig, i, dirty);
31237da2899SCharles.Forsyth 	return e;
31337da2899SCharles.Forsyth }
31437da2899SCharles.Forsyth 
31537da2899SCharles.Forsyth char*
tkupdate(TkTop * t)31637da2899SCharles.Forsyth tkupdate(TkTop *t)
31737da2899SCharles.Forsyth {
31837da2899SCharles.Forsyth 	Tk* tk;
31937da2899SCharles.Forsyth 	int locked;
32037da2899SCharles.Forsyth 	TkWin *tkw;
32137da2899SCharles.Forsyth 	Display *d;
32237da2899SCharles.Forsyth 	char *e;
32337da2899SCharles.Forsyth 	int dirty = 0;
32437da2899SCharles.Forsyth 	if(t->noupdate)
32537da2899SCharles.Forsyth 		return nil;
32637da2899SCharles.Forsyth 
32737da2899SCharles.Forsyth 	d = t->display;
32837da2899SCharles.Forsyth 	locked = lockdisplay(d);
32937da2899SCharles.Forsyth 	tk = t->windows;
33037da2899SCharles.Forsyth 	while(tk) {
33137da2899SCharles.Forsyth 		tkw = TKobj(TkWin, tk);
33237da2899SCharles.Forsyth 		if((tk->flag & (Tkmapped|Tksuspended)) == Tkmapped) {
33337da2899SCharles.Forsyth 			if (tkupdatewinsize(tk) == 0){
33437da2899SCharles.Forsyth 				e = tkdrawslaves(tk, ZP, &dirty);
33537da2899SCharles.Forsyth 				if(e != nil)
33637da2899SCharles.Forsyth 					return e;
33737da2899SCharles.Forsyth 			}
33837da2899SCharles.Forsyth 		}
33937da2899SCharles.Forsyth 		tk = tkw->next;
34037da2899SCharles.Forsyth 	}
34137da2899SCharles.Forsyth 	if (dirty || t->dirty) {
34237da2899SCharles.Forsyth 		flushimage(d, 1);
34337da2899SCharles.Forsyth 		t->dirty = 0;
34437da2899SCharles.Forsyth 	}
34537da2899SCharles.Forsyth 	if(locked)
34637da2899SCharles.Forsyth 		unlockdisplay(d);
34737da2899SCharles.Forsyth 	return nil;
34837da2899SCharles.Forsyth }
34937da2899SCharles.Forsyth 
35037da2899SCharles.Forsyth int
tkischild(Tk * tk,Tk * child)35137da2899SCharles.Forsyth tkischild(Tk *tk, Tk *child)
35237da2899SCharles.Forsyth {
35337da2899SCharles.Forsyth 	while(child != nil && child != tk){
35437da2899SCharles.Forsyth 		if(child->master)
35537da2899SCharles.Forsyth 			child = child->master;
35637da2899SCharles.Forsyth 		else
35737da2899SCharles.Forsyth 			child = child->parent;
35837da2899SCharles.Forsyth 	}
35937da2899SCharles.Forsyth 	return child == tk;
36037da2899SCharles.Forsyth }
36137da2899SCharles.Forsyth 
36237da2899SCharles.Forsyth void
tksetbits(Tk * tk,int mask)36337da2899SCharles.Forsyth tksetbits(Tk *tk, int mask)
36437da2899SCharles.Forsyth {
36537da2899SCharles.Forsyth 	tk->flag |= mask;
36637da2899SCharles.Forsyth 	for(tk = tk->slave; tk; tk = tk->next)
36737da2899SCharles.Forsyth 		tksetbits(tk, mask);
36837da2899SCharles.Forsyth }
36937da2899SCharles.Forsyth 
37037da2899SCharles.Forsyth char*
tkmap(Tk * tk)37137da2899SCharles.Forsyth tkmap(Tk *tk)
37237da2899SCharles.Forsyth {
37337da2899SCharles.Forsyth /*
37437da2899SCharles.Forsyth 	is this necessary?
37537da2899SCharles.Forsyth 	tkw = TKobj(TkWin, tk);
37637da2899SCharles.Forsyth 	if(tkw->image != nil)
37737da2899SCharles.Forsyth 		tkwreq(tk->env->top, "raise %s", tk->name->name);
37837da2899SCharles.Forsyth */
37937da2899SCharles.Forsyth 
38037da2899SCharles.Forsyth 	if(tk->flag & Tkmapped)
38137da2899SCharles.Forsyth 		return nil;
38237da2899SCharles.Forsyth 
38337da2899SCharles.Forsyth 	tk->flag |= Tkmapped;
38437da2899SCharles.Forsyth 	tkmoveresize(tk, 0, 0, tk->act.width, tk->act.height);
38537da2899SCharles.Forsyth 	tkdeliver(tk, TkMap, nil);
38637da2899SCharles.Forsyth 	return nil;
38737da2899SCharles.Forsyth //tkupdate(tk->env->top);
38837da2899SCharles.Forsyth }
38937da2899SCharles.Forsyth 
39037da2899SCharles.Forsyth void
tkunmap(Tk * tk)39137da2899SCharles.Forsyth tkunmap(Tk *tk)
39237da2899SCharles.Forsyth {
39337da2899SCharles.Forsyth 	TkTop *t;
39437da2899SCharles.Forsyth 	TkCtxt *c;
39537da2899SCharles.Forsyth 
39637da2899SCharles.Forsyth 	while(tk->master)
39737da2899SCharles.Forsyth 		tk = tk->master;
39837da2899SCharles.Forsyth 
39937da2899SCharles.Forsyth 	if((tk->flag & Tkmapped) == 0)
40037da2899SCharles.Forsyth 		return;
40137da2899SCharles.Forsyth 
40237da2899SCharles.Forsyth 	t = tk->env->top;
40337da2899SCharles.Forsyth 	c = t->ctxt;
40437da2899SCharles.Forsyth 
40537da2899SCharles.Forsyth 	if(tkischild(tk, c->mgrab))
40637da2899SCharles.Forsyth 		tksetmgrab(t, nil);
40737da2899SCharles.Forsyth 	if(tkischild(tk, c->entered)){
40837da2899SCharles.Forsyth 		tkdeliver(c->entered, TkLeave, nil);
40937da2899SCharles.Forsyth 		c->entered = nil;
41037da2899SCharles.Forsyth 	}
41137da2899SCharles.Forsyth 	if(tk == t->root)
41237da2899SCharles.Forsyth 		tksetglobalfocus(t, 0);
41337da2899SCharles.Forsyth 
41437da2899SCharles.Forsyth 	tk->flag &= ~(Tkmapped|Tksuspended);
41537da2899SCharles.Forsyth 
41637da2899SCharles.Forsyth 	tkdestroywinimage(tk);
41737da2899SCharles.Forsyth 	tkdeliver(tk, TkUnmap, nil);
41837da2899SCharles.Forsyth 	tkenterleave(t);
41937da2899SCharles.Forsyth 	/* XXX should unmap menus too */
42037da2899SCharles.Forsyth }
42137da2899SCharles.Forsyth 
42237da2899SCharles.Forsyth Image*
tkimageof(Tk * tk)42337da2899SCharles.Forsyth tkimageof(Tk *tk)
42437da2899SCharles.Forsyth {
42537da2899SCharles.Forsyth 	while(tk) {
42637da2899SCharles.Forsyth 		if(tk->flag & Tkwindow)
42737da2899SCharles.Forsyth 			return TKobj(TkWin, tk)->image;
42837da2899SCharles.Forsyth 		if(tk->parent != nil) {
42937da2899SCharles.Forsyth 			tk = tk->parent;
43037da2899SCharles.Forsyth 			switch(tk->type) {
43137da2899SCharles.Forsyth 			case TKmenu:
43237da2899SCharles.Forsyth 				return TKobj(TkWin, tk)->image;
43337da2899SCharles.Forsyth 			case TKcanvas:
43437da2899SCharles.Forsyth 				return TKobj(TkCanvas, tk)->image;
43537da2899SCharles.Forsyth 			case TKtext:
43637da2899SCharles.Forsyth 				return TKobj(TkText, tk)->image;
43737da2899SCharles.Forsyth 			}
43837da2899SCharles.Forsyth 			abort();
43937da2899SCharles.Forsyth 		}
44037da2899SCharles.Forsyth 		tk = tk->master;
44137da2899SCharles.Forsyth 	}
44237da2899SCharles.Forsyth 	return nil;
44337da2899SCharles.Forsyth }
44437da2899SCharles.Forsyth 
44537da2899SCharles.Forsyth void
tktopopt(Tk * tk,char * opt)44637da2899SCharles.Forsyth tktopopt(Tk *tk, char *opt)
44737da2899SCharles.Forsyth {
44837da2899SCharles.Forsyth 	TkTop *t;
44937da2899SCharles.Forsyth 	TkWin *tkw;
45037da2899SCharles.Forsyth 	TkOptab tko[4];
45137da2899SCharles.Forsyth 
45237da2899SCharles.Forsyth 	tkw = TKobj(TkWin, tk);
45337da2899SCharles.Forsyth 
45437da2899SCharles.Forsyth 	t = tk->env->top;
45537da2899SCharles.Forsyth 
45637da2899SCharles.Forsyth 	tko[0].ptr = tkw;
45737da2899SCharles.Forsyth 	tko[0].optab = tktop;
45837da2899SCharles.Forsyth 	tko[1].ptr = tk;
45937da2899SCharles.Forsyth 	tko[1].optab = tkgeneric;
46037da2899SCharles.Forsyth 	tko[2].ptr = t;
46137da2899SCharles.Forsyth 	tko[2].optab = tktopdbg;
46237da2899SCharles.Forsyth 	tko[3].ptr = nil;
46337da2899SCharles.Forsyth 
46437da2899SCharles.Forsyth 	tkparse(t, opt, tko, nil);
46537da2899SCharles.Forsyth }
46637da2899SCharles.Forsyth 
46737da2899SCharles.Forsyth /* general compare - compare top-left corners, y takes priority */
46837da2899SCharles.Forsyth static int
tkfcmpgen(void * ap,void * bp)46937da2899SCharles.Forsyth tkfcmpgen(void *ap, void *bp)
47037da2899SCharles.Forsyth {
47137da2899SCharles.Forsyth 	TkWinfo *a = ap, *b = bp;
47237da2899SCharles.Forsyth 
47337da2899SCharles.Forsyth 	if (a->r.min.y > b->r.min.y)
47437da2899SCharles.Forsyth 		return 1;
47537da2899SCharles.Forsyth 	if (a->r.min.y < b->r.min.y)
47637da2899SCharles.Forsyth 		return -1;
47737da2899SCharles.Forsyth 	if (a->r.min.x > b->r.min.x)
47837da2899SCharles.Forsyth 		return 1;
47937da2899SCharles.Forsyth 	if (a->r.min.x < b->r.min.x)
48037da2899SCharles.Forsyth 		return -1;
48137da2899SCharles.Forsyth 	return 0;
48237da2899SCharles.Forsyth }
48337da2899SCharles.Forsyth 
48437da2899SCharles.Forsyth /* compare x-coords only */
48537da2899SCharles.Forsyth static int
tkfcmpx(void * ap,void * bp)48637da2899SCharles.Forsyth tkfcmpx(void *ap, void *bp)
48737da2899SCharles.Forsyth {
48837da2899SCharles.Forsyth 	TkWinfo *a = ap, *b = bp;
48937da2899SCharles.Forsyth 	return a->r.min.x - b->r.min.x;
49037da2899SCharles.Forsyth }
49137da2899SCharles.Forsyth 
49237da2899SCharles.Forsyth /* compare y-coords only */
49337da2899SCharles.Forsyth static int
tkfcmpy(void * ap,void * bp)49437da2899SCharles.Forsyth tkfcmpy(void *ap, void *bp)
49537da2899SCharles.Forsyth {
49637da2899SCharles.Forsyth 	TkWinfo *a = ap, *b = bp;
49737da2899SCharles.Forsyth 	return a->r.min.y - b->r.min.y;
49837da2899SCharles.Forsyth }
49937da2899SCharles.Forsyth 
50037da2899SCharles.Forsyth static void
tkfintervalintersect(int min1,int max1,int min2,int max2,int * min,int * max)50137da2899SCharles.Forsyth tkfintervalintersect(int min1, int max1, int min2, int max2, int *min, int *max)
50237da2899SCharles.Forsyth {
50337da2899SCharles.Forsyth 	if (min1 < min2)
50437da2899SCharles.Forsyth 		min1 = min2;
50537da2899SCharles.Forsyth 	if (max1 > max2)
50637da2899SCharles.Forsyth 		max1 = max2;
50737da2899SCharles.Forsyth 	if (max1 > min1) {
50837da2899SCharles.Forsyth 		*min = min1;
50937da2899SCharles.Forsyth 		*max = max1;
51037da2899SCharles.Forsyth 	} else
51137da2899SCharles.Forsyth 		*max = *min;		/* no intersection */
51237da2899SCharles.Forsyth }
51337da2899SCharles.Forsyth 
51437da2899SCharles.Forsyth void
tksortfocusorder(TkWinfo * inf,int n)51537da2899SCharles.Forsyth tksortfocusorder(TkWinfo *inf, int n)
51637da2899SCharles.Forsyth {
51737da2899SCharles.Forsyth 	int i;
51837da2899SCharles.Forsyth 	Rectangle overlap, r;
51937da2899SCharles.Forsyth 	int (*cmpfn)(void*, void*);
52037da2899SCharles.Forsyth 
52137da2899SCharles.Forsyth 	overlap = inf[0].r;
52237da2899SCharles.Forsyth 	for (i = 0; i < n; i++) {
52337da2899SCharles.Forsyth 		r = inf[i].r;
52437da2899SCharles.Forsyth 		tkfintervalintersect(overlap.min.x, overlap.max.x,
52537da2899SCharles.Forsyth 				r.min.x, r.max.x, &overlap.min.x, &overlap.max.x);
52637da2899SCharles.Forsyth 		tkfintervalintersect(overlap.min.y, overlap.max.y,
52737da2899SCharles.Forsyth 				r.min.y, r.max.y, &overlap.min.y, &overlap.max.y);
52837da2899SCharles.Forsyth 	}
52937da2899SCharles.Forsyth 
53037da2899SCharles.Forsyth 	if (Dx(overlap) > 0)
53137da2899SCharles.Forsyth 		cmpfn = tkfcmpy;
53237da2899SCharles.Forsyth 	else if (Dy(overlap) > 0)
53337da2899SCharles.Forsyth 		cmpfn = tkfcmpx;
53437da2899SCharles.Forsyth 	else
53537da2899SCharles.Forsyth 		cmpfn = tkfcmpgen;
53637da2899SCharles.Forsyth 
53737da2899SCharles.Forsyth 	qsort(inf, n, sizeof(*inf), cmpfn);
53837da2899SCharles.Forsyth }
53937da2899SCharles.Forsyth 
54037da2899SCharles.Forsyth void
tkappendfocusorder(Tk * tk)54137da2899SCharles.Forsyth tkappendfocusorder(Tk *tk)
54237da2899SCharles.Forsyth {
54337da2899SCharles.Forsyth 	TkTop *tkt;
54437da2899SCharles.Forsyth 	tkt = tk->env->top;
54537da2899SCharles.Forsyth 	if (tk->flag & Tktakefocus)
54637da2899SCharles.Forsyth 		tkt->focusorder[tkt->nfocus++] = tk;
54737da2899SCharles.Forsyth 	if (tkmethod[tk->type]->focusorder != nil)
54837da2899SCharles.Forsyth 		tkmethod[tk->type]->focusorder(tk);
54937da2899SCharles.Forsyth }
55037da2899SCharles.Forsyth 
55137da2899SCharles.Forsyth void
tkbuildfocusorder(TkTop * tkt)55237da2899SCharles.Forsyth tkbuildfocusorder(TkTop *tkt)
55337da2899SCharles.Forsyth {
55437da2899SCharles.Forsyth 	Tk *tk;
55537da2899SCharles.Forsyth 	int n;
55637da2899SCharles.Forsyth 
55737da2899SCharles.Forsyth 	if (tkt->focusorder != nil)
55837da2899SCharles.Forsyth 		free(tkt->focusorder);
55937da2899SCharles.Forsyth 	n = 0;
56037da2899SCharles.Forsyth 	for (tk = tkt->root; tk != nil; tk = tk->siblings)
56137da2899SCharles.Forsyth 		if (tk->flag & Tktakefocus)
56237da2899SCharles.Forsyth 			n++;
56337da2899SCharles.Forsyth 	if (n == 0) {
56437da2899SCharles.Forsyth 		tkt->focusorder = nil;
56537da2899SCharles.Forsyth 		return;
56637da2899SCharles.Forsyth 	}
56737da2899SCharles.Forsyth 
56837da2899SCharles.Forsyth 	tkt->focusorder = malloc(sizeof(*tkt->focusorder) * n);
56937da2899SCharles.Forsyth 	tkt->nfocus = 0;
57037da2899SCharles.Forsyth 	if (tkt->focusorder == nil)
57137da2899SCharles.Forsyth 		return;
57237da2899SCharles.Forsyth 
57337da2899SCharles.Forsyth 	tkappendfocusorder(tkt->root);
57437da2899SCharles.Forsyth }
57537da2899SCharles.Forsyth 
57637da2899SCharles.Forsyth void
tkdirtyfocusorder(TkTop * tkt)57737da2899SCharles.Forsyth tkdirtyfocusorder(TkTop *tkt)
57837da2899SCharles.Forsyth {
57937da2899SCharles.Forsyth 	free(tkt->focusorder);
58037da2899SCharles.Forsyth 	tkt->focusorder = nil;
58137da2899SCharles.Forsyth 	tkt->nfocus = 0;
58237da2899SCharles.Forsyth }
58337da2899SCharles.Forsyth 
58437da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
58537da2899SCharles.Forsyth #define OA(t, e)	((long)(((t*)0)->e))
58637da2899SCharles.Forsyth 
58737da2899SCharles.Forsyth typedef struct TkSee TkSee;
58837da2899SCharles.Forsyth struct TkSee {
58937da2899SCharles.Forsyth 	int r[4];
59037da2899SCharles.Forsyth 	int p[2];
59137da2899SCharles.Forsyth 	int query;
59237da2899SCharles.Forsyth };
59337da2899SCharles.Forsyth 
59437da2899SCharles.Forsyth static
59537da2899SCharles.Forsyth TkOption seeopts[] = {
59637da2899SCharles.Forsyth 	"rectangle",		OPTfrac,	OA(TkSee, r),	IAUX(4),
59737da2899SCharles.Forsyth 	"point",			OPTfrac,	OA(TkSee, p),	IAUX(2),
59837da2899SCharles.Forsyth 	"where",			OPTbool,	O(TkSee, query),	nil,
59937da2899SCharles.Forsyth 	nil
60037da2899SCharles.Forsyth };
60137da2899SCharles.Forsyth 
60237da2899SCharles.Forsyth char*
tkseecmd(TkTop * t,char * arg,char ** ret)60337da2899SCharles.Forsyth tkseecmd(TkTop *t, char *arg, char **ret)
60437da2899SCharles.Forsyth {
60537da2899SCharles.Forsyth 	TkOptab tko[2];
60637da2899SCharles.Forsyth 	TkSee opts;
60737da2899SCharles.Forsyth 	TkName *names;
60837da2899SCharles.Forsyth 	Tk *tk;
60937da2899SCharles.Forsyth 	char *e;
61037da2899SCharles.Forsyth 	Rectangle vr;
61137da2899SCharles.Forsyth 	Point vp;
61237da2899SCharles.Forsyth 
61337da2899SCharles.Forsyth 	opts.r[0] = bbnil.min.x;
61437da2899SCharles.Forsyth 	opts.r[1] = bbnil.min.y;
61537da2899SCharles.Forsyth 	opts.r[2] = bbnil.max.x;
61637da2899SCharles.Forsyth 	opts.r[3] = bbnil.max.y;
61737da2899SCharles.Forsyth 	opts.p[0] = bbnil.max.x;
61837da2899SCharles.Forsyth 	opts.p[1] = bbnil.max.y;
61937da2899SCharles.Forsyth 	opts.query = 0;
62037da2899SCharles.Forsyth 
62137da2899SCharles.Forsyth 	tko[0].ptr = &opts;
62237da2899SCharles.Forsyth 	tko[0].optab = seeopts;
62337da2899SCharles.Forsyth 	tko[1].ptr = nil;
62437da2899SCharles.Forsyth 	names = nil;
62537da2899SCharles.Forsyth 	e = tkparse(t, arg, tko, &names);
62637da2899SCharles.Forsyth 	if (e != nil)
62737da2899SCharles.Forsyth 		return e;
62837da2899SCharles.Forsyth 	if (names == nil)
62937da2899SCharles.Forsyth 		return TkBadwp;
63037da2899SCharles.Forsyth 	tk = tklook(t, names->name, 0);
63137da2899SCharles.Forsyth 	tkfreename(names);
63237da2899SCharles.Forsyth 	if (tk == nil)
63337da2899SCharles.Forsyth 		return TkBadwp;
63437da2899SCharles.Forsyth 	if (opts.query) {
63537da2899SCharles.Forsyth 		if (!tkvisiblerect(tk, &vr))
63637da2899SCharles.Forsyth 			return nil;
63737da2899SCharles.Forsyth 		/* XXX should this be converted into screen coords? */
63837da2899SCharles.Forsyth 		return tkvalue(ret, "%d %d %d %d", vr.min.x, vr.min.y, vr.max.x, vr.max.y);
63937da2899SCharles.Forsyth 	}
64037da2899SCharles.Forsyth 	vr.min.x = opts.r[0];
64137da2899SCharles.Forsyth 	vr.min.y = opts.r[1];
64237da2899SCharles.Forsyth 	vr.max.x = opts.r[2];
64337da2899SCharles.Forsyth 	vr.max.y = opts.r[3];
64437da2899SCharles.Forsyth 	vp.x = opts.p[0];
64537da2899SCharles.Forsyth 	vp.y = opts.p[1];
64637da2899SCharles.Forsyth 
64737da2899SCharles.Forsyth 	if (eqrect(vr, bbnil))
64837da2899SCharles.Forsyth 		vr = tkrect(tk, 1);
64937da2899SCharles.Forsyth 	if (eqpt(vp, bbnil.max))
65037da2899SCharles.Forsyth 		vp = vr.min;
65137da2899SCharles.Forsyth 	tksee(tk, vr, vp);
65237da2899SCharles.Forsyth 	return nil;
65337da2899SCharles.Forsyth }
65437da2899SCharles.Forsyth 
65537da2899SCharles.Forsyth /*
65637da2899SCharles.Forsyth  * make rectangle r in widget tk visible if possible;
65737da2899SCharles.Forsyth  * if not possible, at least make point p visible.
65837da2899SCharles.Forsyth  */
65937da2899SCharles.Forsyth void
tksee(Tk * tk,Rectangle r,Point p)66037da2899SCharles.Forsyth tksee(Tk *tk, Rectangle r, Point p)
66137da2899SCharles.Forsyth {
66237da2899SCharles.Forsyth 	Point g;
66337da2899SCharles.Forsyth //print("tksee %R, %P in %s\n", r, p, tk->name->name);
66437da2899SCharles.Forsyth 	g = Pt(tk->borderwidth, tk->borderwidth);
66537da2899SCharles.Forsyth 	if(tk->parent != nil) {
66637da2899SCharles.Forsyth 		g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
66737da2899SCharles.Forsyth 		tk = tk->parent;
66837da2899SCharles.Forsyth 	} else {
66937da2899SCharles.Forsyth 		g.x += tk->act.x;
67037da2899SCharles.Forsyth 		g.y += tk->act.y;
67137da2899SCharles.Forsyth 		tk = tk->master;
67237da2899SCharles.Forsyth 	}
67337da2899SCharles.Forsyth 	r = rectaddpt(r, g);
67437da2899SCharles.Forsyth 	p = addpt(p, g);
67537da2899SCharles.Forsyth 	while (tk != nil) {
67637da2899SCharles.Forsyth 		if (tkmethod[tk->type]->see != nil){
67737da2899SCharles.Forsyth //print("see r %R, p %P in %s\n", r, p, tk->name->name);
67837da2899SCharles.Forsyth 			tkmethod[tk->type]->see(tk, &r, &p);
67937da2899SCharles.Forsyth //print("now r %R, p %P\n", r, p);
68037da2899SCharles.Forsyth 		}
68137da2899SCharles.Forsyth 		g = Pt(tk->borderwidth, tk->borderwidth);
68237da2899SCharles.Forsyth 		if (tk->parent != nil) {
68337da2899SCharles.Forsyth 			g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
68437da2899SCharles.Forsyth 			tk = tk->parent;
68537da2899SCharles.Forsyth 		} else {
68637da2899SCharles.Forsyth 			g.x += tk->act.x;
68737da2899SCharles.Forsyth 			g.y += tk->act.y;
68837da2899SCharles.Forsyth 			tk = tk->master;
68937da2899SCharles.Forsyth 		}
69037da2899SCharles.Forsyth 		r = rectaddpt(r, g);
69137da2899SCharles.Forsyth 		p = addpt(p, g);
69237da2899SCharles.Forsyth 	}
69337da2899SCharles.Forsyth }
694