xref: /inferno-os/libtk/utils.c (revision 5849851a19380dbb62a47d9c4d868a81e42fa79b)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "tk.h"
437da2899SCharles.Forsyth 
50db9190eSforsyth struct TkCol
60db9190eSforsyth {
70db9190eSforsyth 	ulong	rgba1;
80db9190eSforsyth 	ulong	rgba3;	/* if mixed, otherwise DNotacolor */
90db9190eSforsyth 	Image*	i;
100db9190eSforsyth 	TkCol*	forw;
110db9190eSforsyth };
120db9190eSforsyth 
1337da2899SCharles.Forsyth extern void	rptwakeup(void*, void*);
1437da2899SCharles.Forsyth extern void*	rptproc(char*, int, void*, int (*)(void*), int (*)(void*,int), void (*)(void*));
1537da2899SCharles.Forsyth 
1637da2899SCharles.Forsyth typedef struct Cmd Cmd;
1737da2899SCharles.Forsyth struct Cmd
1837da2899SCharles.Forsyth {
1937da2899SCharles.Forsyth 	char*	name;
2037da2899SCharles.Forsyth 	char*	(*fn)(TkTop*, char*, char**);
2137da2899SCharles.Forsyth };
2237da2899SCharles.Forsyth static struct Cmd cmdmain[] =
2337da2899SCharles.Forsyth {
2437da2899SCharles.Forsyth 	"bind",		tkbind,
2537da2899SCharles.Forsyth 	"button",	tkbutton,
2637da2899SCharles.Forsyth 	"canvas",	tkcanvas,
2737da2899SCharles.Forsyth 	"checkbutton",	tkcheckbutton,
2837da2899SCharles.Forsyth 	"choicebutton", tkchoicebutton,
2937da2899SCharles.Forsyth 	"cursor",	tkcursorcmd,
3037da2899SCharles.Forsyth 	"destroy",	tkdestroy,
3137da2899SCharles.Forsyth 	"entry",	tkentry,
3237da2899SCharles.Forsyth 	"focus",	tkfocus,
3337da2899SCharles.Forsyth 	"frame",	tkframe,
3437da2899SCharles.Forsyth 	"grab",		tkgrab,
3537da2899SCharles.Forsyth 	"grid",	tkgrid,
3637da2899SCharles.Forsyth 	"image",	tkimage,
3737da2899SCharles.Forsyth 	"label",	tklabel,
3837da2899SCharles.Forsyth 	"listbox",	tklistbox,
3937da2899SCharles.Forsyth 	"lower",	tklower,
4037da2899SCharles.Forsyth 	"menu",		tkmenu,
4137da2899SCharles.Forsyth 	"menubutton",	tkmenubutton,
4237da2899SCharles.Forsyth 	"pack",		tkpack,
4337da2899SCharles.Forsyth 	"panel",		tkpanel,
4437da2899SCharles.Forsyth 	"puts",		tkputs,
4537da2899SCharles.Forsyth 	"radiobutton",	tkradiobutton,
4637da2899SCharles.Forsyth 	"raise",	tkraise,
4737da2899SCharles.Forsyth 	"scale",	tkscale,
4837da2899SCharles.Forsyth 	"scrollbar",	tkscrollbar,
4937da2899SCharles.Forsyth 	"see",	tkseecmd,
5037da2899SCharles.Forsyth 	"send",		tksend,
5137da2899SCharles.Forsyth 	"text",		tktext,
5237da2899SCharles.Forsyth 	"update",	tkupdatecmd,
5337da2899SCharles.Forsyth 	"variable",	tkvariable,
5437da2899SCharles.Forsyth 	"winfo",	tkwinfo,
5537da2899SCharles.Forsyth };
5637da2899SCharles.Forsyth 
5737da2899SCharles.Forsyth char*	tkfont;
5837da2899SCharles.Forsyth 
59*5849851aSforsyth /*
60*5849851aSforsyth  * auto-repeating support
6137da2899SCharles.Forsyth  * should perhaps be one rptproc per TkCtxt
6237da2899SCharles.Forsyth  * This is not done for the moment as there isn't
6337da2899SCharles.Forsyth  * a mechanism for terminating the rptproc
6437da2899SCharles.Forsyth  */
6537da2899SCharles.Forsyth static void *autorpt;
6637da2899SCharles.Forsyth static int rptid;
6737da2899SCharles.Forsyth static Tk *rptw;
6837da2899SCharles.Forsyth static void *rptnote;
6937da2899SCharles.Forsyth static void (*rptcb)(Tk*, void*, int);
7037da2899SCharles.Forsyth static long rptto;
7137da2899SCharles.Forsyth static int rptint;
7237da2899SCharles.Forsyth 
7337da2899SCharles.Forsyth /* blinking carets - should be per TkCtxt */
7437da2899SCharles.Forsyth static void *blinkrpt;
7537da2899SCharles.Forsyth static Tk *blinkw;
7637da2899SCharles.Forsyth static void (*blinkcb)(Tk*, int);
7737da2899SCharles.Forsyth static int blinkignore;
7837da2899SCharles.Forsyth static int blinkon;
7937da2899SCharles.Forsyth 
8037da2899SCharles.Forsyth 
8137da2899SCharles.Forsyth ulong
tkrgba(int r,int g,int b,int a)8237da2899SCharles.Forsyth tkrgba(int r, int g, int b, int a)
8337da2899SCharles.Forsyth {
8437da2899SCharles.Forsyth 	ulong p;
8537da2899SCharles.Forsyth 
8637da2899SCharles.Forsyth 	if(r < 0)
8737da2899SCharles.Forsyth 		r = 0;
8837da2899SCharles.Forsyth 	else if(r > 255)
8937da2899SCharles.Forsyth 		r = 255;
9037da2899SCharles.Forsyth 	if(g < 0)
9137da2899SCharles.Forsyth 		g = 0;
9237da2899SCharles.Forsyth 	else if(g > 255)
9337da2899SCharles.Forsyth 		g = 255;
9437da2899SCharles.Forsyth 	if(b < 0)
9537da2899SCharles.Forsyth 		b = 0;
9637da2899SCharles.Forsyth 	else if(b > 255)
9737da2899SCharles.Forsyth 		b = 255;
9837da2899SCharles.Forsyth 	p = (r<<24)|(g<<16)|(b<<8)|0xFF;
9937da2899SCharles.Forsyth 	if(a == 255)
10037da2899SCharles.Forsyth 		return p;
10137da2899SCharles.Forsyth 	return setalpha(p, a);
10237da2899SCharles.Forsyth }
10337da2899SCharles.Forsyth 
10437da2899SCharles.Forsyth /* to be replaced */
10537da2899SCharles.Forsyth static int
revalpha(int c,int a)10637da2899SCharles.Forsyth revalpha(int c, int a)
10737da2899SCharles.Forsyth {
10837da2899SCharles.Forsyth 	if (a == 0)
10937da2899SCharles.Forsyth 		return 0;
11037da2899SCharles.Forsyth 	return (c & 0xff) * 255 / a;
11137da2899SCharles.Forsyth }
11237da2899SCharles.Forsyth 
11337da2899SCharles.Forsyth void
tkrgbavals(ulong rgba,int * R,int * G,int * B,int * A)11437da2899SCharles.Forsyth tkrgbavals(ulong rgba, int *R, int *G, int *B, int *A)
11537da2899SCharles.Forsyth {
11637da2899SCharles.Forsyth 	int a;
11737da2899SCharles.Forsyth 
11837da2899SCharles.Forsyth 	a = rgba & 0xff;
11937da2899SCharles.Forsyth 	*A = a;
12037da2899SCharles.Forsyth 	if (a != 0xff) {
12137da2899SCharles.Forsyth 		*R = revalpha(rgba>>24, a);
12237da2899SCharles.Forsyth 		*G = revalpha((rgba>>16) & 0xFF, a);
12337da2899SCharles.Forsyth 		*B = revalpha((rgba >> 8) & 0xFF, a);
12437da2899SCharles.Forsyth 	} else {
12537da2899SCharles.Forsyth 		*R = (rgba>>24);
12637da2899SCharles.Forsyth 		*G = ((rgba>>16) & 0xFF);
12737da2899SCharles.Forsyth 		*B = ((rgba >> 8) & 0xFF);
12837da2899SCharles.Forsyth 	}
12937da2899SCharles.Forsyth }
13037da2899SCharles.Forsyth 
1310db9190eSforsyth static int
tkcachecol(TkCtxt * c,Image * i,ulong one,ulong three)1320db9190eSforsyth tkcachecol(TkCtxt *c, Image *i, ulong one, ulong three)
1330db9190eSforsyth {
1340db9190eSforsyth 	TkCol *cc;
1350db9190eSforsyth 
1360db9190eSforsyth 	cc = malloc(sizeof(*cc));
1370db9190eSforsyth 	if(cc == nil)
1380db9190eSforsyth 		return 0;
1390db9190eSforsyth 	cc->rgba1 = one;
1400db9190eSforsyth 	cc->rgba3 = three;
1410db9190eSforsyth 	cc->i = i;
1420db9190eSforsyth 	cc->forw = c->chead;
1430db9190eSforsyth 	c->chead = cc;
1440db9190eSforsyth 	c->ncol++;
1450db9190eSforsyth 	/* we'll do LRU management at some point */
1460db9190eSforsyth 	if(c->ncol > TkColcachesize){
1470db9190eSforsyth 		static int warn;
1480db9190eSforsyth 		if(warn == 0){
1490db9190eSforsyth 			warn = 1;
1500db9190eSforsyth 			print("tk: %d colours cached\n", TkColcachesize);
1510db9190eSforsyth 		}
1520db9190eSforsyth 	}
1530db9190eSforsyth 	return 1;
1540db9190eSforsyth }
1550db9190eSforsyth 
1560db9190eSforsyth static Image*
tkfindcol(TkCtxt * c,ulong one,ulong three)1570db9190eSforsyth tkfindcol(TkCtxt *c, ulong one, ulong three)
1580db9190eSforsyth {
1590db9190eSforsyth 	TkCol *cc, **l;
1600db9190eSforsyth 
1610db9190eSforsyth 	for(l = &c->chead; (cc = *l) != nil; l = &cc->forw)
1620db9190eSforsyth 		if(cc->rgba1 == one && cc->rgba3 == three){
1630db9190eSforsyth 			/* move it up in the list */
1640db9190eSforsyth 			*l = cc->forw;
1650db9190eSforsyth 			cc->forw = c->chead;
1660db9190eSforsyth 			c->chead = cc;
1670db9190eSforsyth 			/* we assume it will be used right away and not stored */
1680db9190eSforsyth 			return cc->i;
1690db9190eSforsyth 		}
1700db9190eSforsyth 	return nil;
1710db9190eSforsyth }
1720db9190eSforsyth 
17337da2899SCharles.Forsyth void
tkfreecolcache(TkCtxt * c)17437da2899SCharles.Forsyth tkfreecolcache(TkCtxt *c)
17537da2899SCharles.Forsyth {
17637da2899SCharles.Forsyth 	TkCol *cc;
17737da2899SCharles.Forsyth 
17837da2899SCharles.Forsyth 	if(c == nil)
17937da2899SCharles.Forsyth 		return;
18037da2899SCharles.Forsyth 	while((cc = c->chead) != nil){
18137da2899SCharles.Forsyth 		c->chead = cc->forw;
18237da2899SCharles.Forsyth 		freeimage(cc->i);
18337da2899SCharles.Forsyth 		free(cc);
18437da2899SCharles.Forsyth 	}
18537da2899SCharles.Forsyth 	c->ctail = nil;
18637da2899SCharles.Forsyth 	c->ncol = 0;
18737da2899SCharles.Forsyth }
18837da2899SCharles.Forsyth 
18937da2899SCharles.Forsyth Image*
tkcolormix(TkCtxt * c,ulong one,ulong three)1900db9190eSforsyth tkcolormix(TkCtxt *c, ulong one, ulong three)
1910db9190eSforsyth {
1920db9190eSforsyth 	Image *i;
1930db9190eSforsyth 	Display *d;
1940db9190eSforsyth 
1950db9190eSforsyth 	i = tkfindcol(c, one, three);
1960db9190eSforsyth 	if(i != nil)
1970db9190eSforsyth 		return i;
1980db9190eSforsyth 	d = c->display;
1990db9190eSforsyth 	i = allocimagemix(d, one, three);
2000db9190eSforsyth 	if(i == nil)
2010db9190eSforsyth 		return d->black;
2020db9190eSforsyth 	if(!tkcachecol(c, i, one, three)){
2030db9190eSforsyth 		freeimage(i);
2040db9190eSforsyth 		return d->black;
2050db9190eSforsyth 	}
2060db9190eSforsyth 	return i;
2070db9190eSforsyth }
2080db9190eSforsyth 
2090db9190eSforsyth Image*
tkcolor(TkCtxt * c,ulong pix)21037da2899SCharles.Forsyth tkcolor(TkCtxt *c, ulong pix)
21137da2899SCharles.Forsyth {
21237da2899SCharles.Forsyth 	Image *i;
21337da2899SCharles.Forsyth 	Display *d;
21437da2899SCharles.Forsyth 	Rectangle r;
21537da2899SCharles.Forsyth 
21637da2899SCharles.Forsyth 	d = c->display;
21737da2899SCharles.Forsyth 	if(pix == DWhite)
21837da2899SCharles.Forsyth 		return d->white;
21937da2899SCharles.Forsyth 	if(pix == DBlack)
22037da2899SCharles.Forsyth 		return d->black;
2210db9190eSforsyth 	i = tkfindcol(c, pix, DNotacolor);
2220db9190eSforsyth 	if(i != nil)
2230db9190eSforsyth 		return i;
22437da2899SCharles.Forsyth 	r.min = ZP;
22537da2899SCharles.Forsyth 	r.max.x = 1;
22637da2899SCharles.Forsyth 	r.max.y = 1;
22737da2899SCharles.Forsyth 	if ((pix & 0xff) == 0xff)
22837da2899SCharles.Forsyth 		i = allocimage(d, r, RGB24, 1, pix);
22937da2899SCharles.Forsyth 	else
23037da2899SCharles.Forsyth 		i = allocimage(d, r, RGBA32, 1, pix);
23137da2899SCharles.Forsyth 	if(i == nil)
23237da2899SCharles.Forsyth 		return d->black;
2330db9190eSforsyth 	if(!tkcachecol(c, i, pix, DNotacolor)) {
23437da2899SCharles.Forsyth 		freeimage(i);
23537da2899SCharles.Forsyth 		return d->black;
23637da2899SCharles.Forsyth 	}
2370db9190eSforsyth 	return i;
23837da2899SCharles.Forsyth }
2390db9190eSforsyth 
2400db9190eSforsyth Image*
tkgradient(TkCtxt * c,Rectangle r,int dir,ulong pix0,ulong pix1)2410db9190eSforsyth tkgradient(TkCtxt *c, Rectangle r, int dir, ulong pix0, ulong pix1)
2420db9190eSforsyth {
2430db9190eSforsyth 	Display *d;
2440db9190eSforsyth 	Image *i;
2450db9190eSforsyth 	uchar *b, *p, *e;
2460db9190eSforsyth 	int c0[3], c1[3], delta[3], a, j, x, y, n, locked;
2470db9190eSforsyth 	Rectangle s;
2480db9190eSforsyth 
2490db9190eSforsyth 	d = c->display;
2500db9190eSforsyth 	y = Dy(r);
2510db9190eSforsyth 	x = Dx(r);
25234077fb0Sforsyth 	if(x <= 0 || y <= 0) {
25334077fb0Sforsyth 		r = Rect(0, 0, 1, 1);
25434077fb0Sforsyth 		x = y = 1;
25534077fb0Sforsyth 	}
2560db9190eSforsyth 	/* TO DO: diagonal */
2570db9190eSforsyth 	s = r;
2580db9190eSforsyth 	if(dir == Tkhorizontal){
2590db9190eSforsyth 		n = x;
2600db9190eSforsyth 		r.max.y = r.min.y+1;
2610db9190eSforsyth 	}else{
2620db9190eSforsyth 		n = y;
2630db9190eSforsyth 		r.max.x = r.min.x+1;
26437da2899SCharles.Forsyth 	}
2650db9190eSforsyth 	b = mallocz(3*n, 0);
2660db9190eSforsyth 	if(b == nil)
26734077fb0Sforsyth 		return nil;
2680db9190eSforsyth 	locked = lockdisplay(d);
2690db9190eSforsyth 	i = allocimage(d, r, RGB24, 1, DNofill);
2700db9190eSforsyth 	if(i == nil)
2710db9190eSforsyth 		goto Ret;
2720db9190eSforsyth 	tkrgbavals(pix0, &c0[2], &c0[1], &c0[0], &a);
2730db9190eSforsyth 	tkrgbavals(pix1, &c1[2], &c1[1], &c1[0], &a);
2740db9190eSforsyth 	for(j = 0; j < 3; j++){
2750db9190eSforsyth 		c0[j] <<= 12;
2760db9190eSforsyth 		c1[j] <<= 12;
2770db9190eSforsyth 		delta[j] = ((c1[j]-c0[j])+(1<<11))/n;
2780db9190eSforsyth 	}
2790db9190eSforsyth 	e = b+3*n;
2800db9190eSforsyth 	for(p = b; p < e; p += 3) {
2810db9190eSforsyth 		p[0] = c0[0]>>12;
2820db9190eSforsyth 		p[1] = c0[1]>>12;
2830db9190eSforsyth 		p[2] = c0[2]>>12;
2840db9190eSforsyth 		c0[0] += delta[0];
2850db9190eSforsyth 		c0[1] += delta[1];
2860db9190eSforsyth 		c0[2] += delta[2];
2870db9190eSforsyth 	}
2880db9190eSforsyth 	loadimage(i, r, b, 3*n);
2890db9190eSforsyth 	replclipr(i, 1, s);
2900db9190eSforsyth Ret:
2910db9190eSforsyth 	if(locked)
2920db9190eSforsyth 		unlockdisplay(d);
2930db9190eSforsyth 	free(b);
29437da2899SCharles.Forsyth 	return i;
29537da2899SCharles.Forsyth }
29637da2899SCharles.Forsyth 
29737da2899SCharles.Forsyth /*
29837da2899SCharles.Forsyth  * XXX should be in libdraw?
29937da2899SCharles.Forsyth  */
30037da2899SCharles.Forsyth int
tkchanhastype(ulong c,int t)30137da2899SCharles.Forsyth tkchanhastype(ulong c, int t)
30237da2899SCharles.Forsyth {
30337da2899SCharles.Forsyth 	for(; c; c>>=8)
30437da2899SCharles.Forsyth 		if(TYPE(c) == t)
30537da2899SCharles.Forsyth 			return 1;
30637da2899SCharles.Forsyth 	return 0;
30737da2899SCharles.Forsyth }
30837da2899SCharles.Forsyth 
30937da2899SCharles.Forsyth void
tksettransparent(Tk * tk,int transparent)31037da2899SCharles.Forsyth tksettransparent(Tk *tk, int transparent)
31137da2899SCharles.Forsyth {
31237da2899SCharles.Forsyth 	if (transparent)
31337da2899SCharles.Forsyth 		tk->flag |= Tktransparent;
31437da2899SCharles.Forsyth 	else
31537da2899SCharles.Forsyth 		tk->flag &= ~Tktransparent;
31637da2899SCharles.Forsyth }
31737da2899SCharles.Forsyth 
31837da2899SCharles.Forsyth int
tkhasalpha(TkEnv * e,int col)31937da2899SCharles.Forsyth tkhasalpha(TkEnv *e, int col)
32037da2899SCharles.Forsyth {
32137da2899SCharles.Forsyth 	return (e->colors[col] & 0xff) != 0xff;
32237da2899SCharles.Forsyth }
32337da2899SCharles.Forsyth 
32437da2899SCharles.Forsyth Image*
tkgc(TkEnv * e,int col)32537da2899SCharles.Forsyth tkgc(TkEnv *e, int col)
32637da2899SCharles.Forsyth {
32737da2899SCharles.Forsyth 	return tkcolor(e->top->ctxt, e->colors[col]);
32837da2899SCharles.Forsyth }
32937da2899SCharles.Forsyth 
33037da2899SCharles.Forsyth 
33137da2899SCharles.Forsyth /*
33237da2899SCharles.Forsyth  * Todo: improve the fixed-point code
33337da2899SCharles.Forsyth  * the 255 scale factor is used because RGB ranges 0-255
33437da2899SCharles.Forsyth  */
33537da2899SCharles.Forsyth static void
rgb2hsv(int r,int g,int b,int * h,int * s,int * v)33637da2899SCharles.Forsyth rgb2hsv(int r, int g, int b, int *h, int *s, int *v)
33737da2899SCharles.Forsyth {
33837da2899SCharles.Forsyth 	int min, max, delta;
33937da2899SCharles.Forsyth 
34037da2899SCharles.Forsyth 	max = r;
34137da2899SCharles.Forsyth 	if(g > max)
34237da2899SCharles.Forsyth 		max = g;
34337da2899SCharles.Forsyth 	if(b > max)
34437da2899SCharles.Forsyth 		max = b;
34537da2899SCharles.Forsyth 	min = r;
34637da2899SCharles.Forsyth 	if(g < min)
34737da2899SCharles.Forsyth 		min = g;
34837da2899SCharles.Forsyth 	if(b < min)
34937da2899SCharles.Forsyth 		min = b;
35037da2899SCharles.Forsyth 	*v = max;
35137da2899SCharles.Forsyth 	if (max != 0)
35237da2899SCharles.Forsyth 		*s = ((max - min)*255) / max;
35337da2899SCharles.Forsyth 	else
35437da2899SCharles.Forsyth 		*s = 0;
35537da2899SCharles.Forsyth 
35637da2899SCharles.Forsyth 	if (*s == 0) {
35737da2899SCharles.Forsyth 		*h = 0;	/* undefined */
35837da2899SCharles.Forsyth 	} else {
35937da2899SCharles.Forsyth 		delta = max - min;
36037da2899SCharles.Forsyth 		if (r == max)
36137da2899SCharles.Forsyth 			*h = (g - b)*255 / delta;
36237da2899SCharles.Forsyth 		else if (g == max)
36337da2899SCharles.Forsyth 			*h = (2*255) + ((b - r)*255) / delta;
36437da2899SCharles.Forsyth 		else if (b == max)
36537da2899SCharles.Forsyth 			*h = (4*255) + ((r - g)*255)/ delta;
36637da2899SCharles.Forsyth 		*h *= 60;
36737da2899SCharles.Forsyth 		if (*h < 0)
36837da2899SCharles.Forsyth 			*h += 360*255;
36937da2899SCharles.Forsyth 		*h /= 255;
37037da2899SCharles.Forsyth 	}
37137da2899SCharles.Forsyth }
37237da2899SCharles.Forsyth 
37337da2899SCharles.Forsyth static void
hsv2rgb(int h,int s,int v,int * r,int * g,int * b)37437da2899SCharles.Forsyth hsv2rgb(int h, int s, int v, int *r, int *g, int *b)
37537da2899SCharles.Forsyth {
37637da2899SCharles.Forsyth 	int	i;
37737da2899SCharles.Forsyth 	int	f,p,q,t;
37837da2899SCharles.Forsyth 
37937da2899SCharles.Forsyth 	if (s == 0 && h == 0) {
38037da2899SCharles.Forsyth 		*r = *g = *b = v;	/* achromatic case */
38137da2899SCharles.Forsyth 	} else {
38237da2899SCharles.Forsyth 		if (h >= 360)
38337da2899SCharles.Forsyth 			h = 0;
38437da2899SCharles.Forsyth 		i = h / 60;
38537da2899SCharles.Forsyth 		h *= 255;
38637da2899SCharles.Forsyth 		h /= 60;
38737da2899SCharles.Forsyth 
38837da2899SCharles.Forsyth 		f = h % 255;
38937da2899SCharles.Forsyth 		p = v * (255 - s);
39037da2899SCharles.Forsyth 		q = v * (255 - ((s * f)/255));
39137da2899SCharles.Forsyth 		t = v * (255- ((s * (255 - f))/255));
39237da2899SCharles.Forsyth 		p /= 255;
39337da2899SCharles.Forsyth 		q /= 255;
39437da2899SCharles.Forsyth 		t /= 255;
39537da2899SCharles.Forsyth 		switch (i) {
39637da2899SCharles.Forsyth 		case 0: *r = v; *g = t; *b = p; break;
39737da2899SCharles.Forsyth 		case 1: *r = q; *g = v; *b = p; break;
39837da2899SCharles.Forsyth 		case 2: *r = p; *g = v; *b = t; break;
39937da2899SCharles.Forsyth 		case 3: *r = p; *g = q; *b = v; break;
40037da2899SCharles.Forsyth 		case 4: *r = t; *g = p; *b = v; break;
40137da2899SCharles.Forsyth 		case 5: *r = v; *g = p; *b = q; break;
40237da2899SCharles.Forsyth 		}
40337da2899SCharles.Forsyth 	}
40437da2899SCharles.Forsyth }
40537da2899SCharles.Forsyth 
40637da2899SCharles.Forsyth enum {
40737da2899SCharles.Forsyth 	MINDELTA	= 0x10,
40837da2899SCharles.Forsyth 	DELTA	= 0x30,
40937da2899SCharles.Forsyth };
41037da2899SCharles.Forsyth 
41137da2899SCharles.Forsyth ulong
tkrgbashade(ulong rgba,int shade)41237da2899SCharles.Forsyth tkrgbashade(ulong rgba, int shade)
41337da2899SCharles.Forsyth {
41437da2899SCharles.Forsyth 	int R, G, B, A, h, s, v, vl, vd;
41537da2899SCharles.Forsyth 
41637da2899SCharles.Forsyth 	if (shade == TkSameshade)
41737da2899SCharles.Forsyth 		return rgba;
41837da2899SCharles.Forsyth 
41937da2899SCharles.Forsyth 	tkrgbavals(rgba, &R, &G, &B, &A);
4206e425a9dSCharles.Forsyth 	h = s = v = 0;
42137da2899SCharles.Forsyth 	rgb2hsv(R, G, B, &h, &s, &v);
42237da2899SCharles.Forsyth 
42337da2899SCharles.Forsyth 	if (v < MINDELTA) {
42437da2899SCharles.Forsyth 		vd = v+DELTA;
42537da2899SCharles.Forsyth 		vl = vd+DELTA;
42637da2899SCharles.Forsyth 	} else if (v > 255-MINDELTA) {
42737da2899SCharles.Forsyth 		vl = v-DELTA;
42837da2899SCharles.Forsyth 		vd = vl-DELTA;
42937da2899SCharles.Forsyth 	} else {
43037da2899SCharles.Forsyth 		vl = v+DELTA;
43137da2899SCharles.Forsyth 		vd = v-DELTA;
43237da2899SCharles.Forsyth 	}
43337da2899SCharles.Forsyth 
43437da2899SCharles.Forsyth 	v = (shade == TkLightshade)?vl:vd;
43537da2899SCharles.Forsyth 	if (v < 0)
43637da2899SCharles.Forsyth 		v = 0;
43737da2899SCharles.Forsyth 	if (v > 255)
43837da2899SCharles.Forsyth 		v = 255;
43937da2899SCharles.Forsyth 	hsv2rgb(h, s, v, &R, &G, &B);
44037da2899SCharles.Forsyth 
44137da2899SCharles.Forsyth 	return tkrgba(R, G, B, A);
44237da2899SCharles.Forsyth }
44337da2899SCharles.Forsyth 
44437da2899SCharles.Forsyth Image*
tkgshade(TkEnv * e,int col,int shade)44537da2899SCharles.Forsyth tkgshade(TkEnv *e, int col, int shade)
44637da2899SCharles.Forsyth {
44737da2899SCharles.Forsyth 	ulong rgba;
44837da2899SCharles.Forsyth 
44937da2899SCharles.Forsyth 	if (col == TkCbackgnd || col == TkCselectbgnd || col == TkCactivebgnd)
45037da2899SCharles.Forsyth 		return tkgc(e, col+shade);
45137da2899SCharles.Forsyth 	rgba = tkrgbashade(e->colors[col], shade);
45237da2899SCharles.Forsyth 	return tkcolor(e->top->ctxt, rgba);
45337da2899SCharles.Forsyth }
45437da2899SCharles.Forsyth 
45537da2899SCharles.Forsyth TkEnv*
tknewenv(TkTop * t)45637da2899SCharles.Forsyth tknewenv(TkTop *t)
45737da2899SCharles.Forsyth {
45837da2899SCharles.Forsyth 	TkEnv *e;
45937da2899SCharles.Forsyth 
46037da2899SCharles.Forsyth 	e = malloc(sizeof(TkEnv));
46137da2899SCharles.Forsyth 	if(e == nil)
46237da2899SCharles.Forsyth 		return nil;
46337da2899SCharles.Forsyth 
46437da2899SCharles.Forsyth 	e->ref = 1;
46537da2899SCharles.Forsyth 	e->top = t;
46637da2899SCharles.Forsyth 	return e;
46737da2899SCharles.Forsyth }
46837da2899SCharles.Forsyth 
46937da2899SCharles.Forsyth TkEnv*
tkdefaultenv(TkTop * t)47037da2899SCharles.Forsyth tkdefaultenv(TkTop *t)
47137da2899SCharles.Forsyth {
47237da2899SCharles.Forsyth 	int locked;
47337da2899SCharles.Forsyth 	TkEnv *env;
47437da2899SCharles.Forsyth 	Display *d;
47537da2899SCharles.Forsyth 
47637da2899SCharles.Forsyth 	if(t->env != nil) {
47737da2899SCharles.Forsyth 		t->env->ref++;
47837da2899SCharles.Forsyth 		return t->env;
47937da2899SCharles.Forsyth 	}
48037da2899SCharles.Forsyth 	t->env = malloc(sizeof(TkEnv));
48137da2899SCharles.Forsyth 	if(t->env == nil)
48237da2899SCharles.Forsyth 		return nil;
48337da2899SCharles.Forsyth 
48437da2899SCharles.Forsyth 	env = t->env;
48537da2899SCharles.Forsyth 	env->ref = 1;
48637da2899SCharles.Forsyth 	env->top = t;
48737da2899SCharles.Forsyth 
48837da2899SCharles.Forsyth 	if(tkfont == nil)
48937da2899SCharles.Forsyth 		tkfont = "/fonts/pelm/unicode.8.font";
49037da2899SCharles.Forsyth 
49137da2899SCharles.Forsyth 	d = t->display;
49237da2899SCharles.Forsyth 	env->font = font_open(d, tkfont);
49337da2899SCharles.Forsyth 	if(env->font == nil) {
49437da2899SCharles.Forsyth 		static int warn;
49537da2899SCharles.Forsyth 		if(warn == 0) {
49637da2899SCharles.Forsyth 			warn = 1;
49737da2899SCharles.Forsyth 			print("tk: font not found: %s\n", tkfont);
49837da2899SCharles.Forsyth 		}
49937da2899SCharles.Forsyth 		env->font = font_open(d, "*default*");
50037da2899SCharles.Forsyth 		if(env->font == nil) {
50137da2899SCharles.Forsyth 			free(t->env);
50237da2899SCharles.Forsyth 			t->env = nil;
50337da2899SCharles.Forsyth 			return nil;
50437da2899SCharles.Forsyth 		}
50537da2899SCharles.Forsyth 	}
50637da2899SCharles.Forsyth 
50737da2899SCharles.Forsyth 	locked = lockdisplay(d);
50837da2899SCharles.Forsyth 	env->wzero = stringwidth(env->font, "0");
50937da2899SCharles.Forsyth 	if ( env->wzero <= 0 )
51037da2899SCharles.Forsyth 		env->wzero = env->font->height / 2;
51137da2899SCharles.Forsyth 	if(locked)
51237da2899SCharles.Forsyth 		unlockdisplay(d);
51337da2899SCharles.Forsyth 
51437da2899SCharles.Forsyth 	tksetenvcolours(env);
51537da2899SCharles.Forsyth 	return env;
51637da2899SCharles.Forsyth }
51737da2899SCharles.Forsyth 
51837da2899SCharles.Forsyth void
tkputenv(TkEnv * env)51937da2899SCharles.Forsyth tkputenv(TkEnv *env)
52037da2899SCharles.Forsyth {
52137da2899SCharles.Forsyth 	Display *d;
52237da2899SCharles.Forsyth 	int locked;
52337da2899SCharles.Forsyth 
52437da2899SCharles.Forsyth 	if(env == nil)
52537da2899SCharles.Forsyth 		return;
52637da2899SCharles.Forsyth 
52737da2899SCharles.Forsyth 	env->ref--;
52837da2899SCharles.Forsyth 	if(env->ref != 0)
52937da2899SCharles.Forsyth 		return;
53037da2899SCharles.Forsyth 
53137da2899SCharles.Forsyth 	d = env->top->display;
53237da2899SCharles.Forsyth 	locked = lockdisplay(d);
53337da2899SCharles.Forsyth 
53437da2899SCharles.Forsyth 	if(env->font != nil)
53537da2899SCharles.Forsyth 		font_close(env->font);
53637da2899SCharles.Forsyth 
53737da2899SCharles.Forsyth 	if(locked)
53837da2899SCharles.Forsyth 		unlockdisplay(d);
53937da2899SCharles.Forsyth 
54037da2899SCharles.Forsyth 	free(env);
54137da2899SCharles.Forsyth }
54237da2899SCharles.Forsyth 
54337da2899SCharles.Forsyth TkEnv*
tkdupenv(TkEnv ** env)54437da2899SCharles.Forsyth tkdupenv(TkEnv **env)
54537da2899SCharles.Forsyth {
54637da2899SCharles.Forsyth 	Display *d;
54737da2899SCharles.Forsyth 	TkEnv *e, *ne;
54837da2899SCharles.Forsyth 
54937da2899SCharles.Forsyth 	e = *env;
55037da2899SCharles.Forsyth 	if(e->ref == 1)
55137da2899SCharles.Forsyth 		return e;
55237da2899SCharles.Forsyth 
55337da2899SCharles.Forsyth 	ne = malloc(sizeof(TkEnv));
55437da2899SCharles.Forsyth 	if(ne == nil)
55537da2899SCharles.Forsyth 		return nil;
55637da2899SCharles.Forsyth 
55737da2899SCharles.Forsyth 	ne->ref = 1;
55837da2899SCharles.Forsyth 	ne->top = e->top;
55937da2899SCharles.Forsyth 
56037da2899SCharles.Forsyth 	d = e->top->display;
56137da2899SCharles.Forsyth 	memmove(ne->colors, e->colors, sizeof(e->colors));
56237da2899SCharles.Forsyth 	ne->set = e->set;
56337da2899SCharles.Forsyth 	ne->font = font_open(d, e->font->name);
56437da2899SCharles.Forsyth 	ne->wzero = e->wzero;
56537da2899SCharles.Forsyth 
56637da2899SCharles.Forsyth 	e->ref--;
56737da2899SCharles.Forsyth 	*env = ne;
56837da2899SCharles.Forsyth 	return ne;
56937da2899SCharles.Forsyth }
57037da2899SCharles.Forsyth 
57137da2899SCharles.Forsyth Tk*
tknewobj(TkTop * t,int type,int n)57237da2899SCharles.Forsyth tknewobj(TkTop *t, int type, int n)
57337da2899SCharles.Forsyth {
57437da2899SCharles.Forsyth 	Tk *tk;
57537da2899SCharles.Forsyth 
57637da2899SCharles.Forsyth 	tk = malloc(n);
57737da2899SCharles.Forsyth 	if(tk == 0)
57837da2899SCharles.Forsyth 		return 0;
57937da2899SCharles.Forsyth 
58037da2899SCharles.Forsyth 	tk->type = type;		/* Defaults */
58137da2899SCharles.Forsyth 	tk->flag = Tktop;
58237da2899SCharles.Forsyth 	tk->relief = TKflat;
58337da2899SCharles.Forsyth 	tk->env = tkdefaultenv(t);
58437da2899SCharles.Forsyth 	if(tk->env == nil) {
58537da2899SCharles.Forsyth 		free(tk);
58637da2899SCharles.Forsyth 		return nil;
58737da2899SCharles.Forsyth 	}
58837da2899SCharles.Forsyth 
58937da2899SCharles.Forsyth 	return tk;
59037da2899SCharles.Forsyth }
59137da2899SCharles.Forsyth 
59237da2899SCharles.Forsyth void
tkfreebind(TkAction * a)59337da2899SCharles.Forsyth tkfreebind(TkAction *a)
59437da2899SCharles.Forsyth {
59537da2899SCharles.Forsyth 	TkAction *next;
59637da2899SCharles.Forsyth 
59737da2899SCharles.Forsyth 	while(a != nil) {
59837da2899SCharles.Forsyth 		next = a->link;
59937da2899SCharles.Forsyth 		if((a->type & 0xff) == TkDynamic)
60037da2899SCharles.Forsyth 			free(a->arg);
60137da2899SCharles.Forsyth 		free(a);
60237da2899SCharles.Forsyth 		a = next;
60337da2899SCharles.Forsyth 	}
60437da2899SCharles.Forsyth }
60537da2899SCharles.Forsyth 
60637da2899SCharles.Forsyth void
tkfreename(TkName * f)60737da2899SCharles.Forsyth tkfreename(TkName *f)
60837da2899SCharles.Forsyth {
60937da2899SCharles.Forsyth 	TkName *n;
61037da2899SCharles.Forsyth 
61137da2899SCharles.Forsyth 	while(f != nil) {
61237da2899SCharles.Forsyth 		n = f->link;
61337da2899SCharles.Forsyth 		free(f);
61437da2899SCharles.Forsyth 		f = n;
61537da2899SCharles.Forsyth 	}
61637da2899SCharles.Forsyth }
61737da2899SCharles.Forsyth 
61837da2899SCharles.Forsyth void
tkfreeobj(Tk * tk)61937da2899SCharles.Forsyth tkfreeobj(Tk *tk)
62037da2899SCharles.Forsyth {
62137da2899SCharles.Forsyth 	TkCtxt *c;
62237da2899SCharles.Forsyth 
62337da2899SCharles.Forsyth 	c = tk->env->top->ctxt;
62437da2899SCharles.Forsyth 	if(c != nil) {
62537da2899SCharles.Forsyth 		if(c->tkkeygrab == tk)
62637da2899SCharles.Forsyth 			c->tkkeygrab = nil;
62737da2899SCharles.Forsyth 		if(c->mgrab == tk)
62837da2899SCharles.Forsyth 			tksetmgrab(tk->env->top, nil);
62937da2899SCharles.Forsyth 		if(c->mfocus == tk)
63037da2899SCharles.Forsyth 			c->mfocus = nil;
63137da2899SCharles.Forsyth 		if(c->entered == tk)
63237da2899SCharles.Forsyth 			c->entered = nil;
63337da2899SCharles.Forsyth 	}
63437da2899SCharles.Forsyth 
63537da2899SCharles.Forsyth 	if (tk == rptw) {
63637da2899SCharles.Forsyth 		/* cancel the autorepeat without notifying the widget */
63737da2899SCharles.Forsyth 		rptid++;
63837da2899SCharles.Forsyth 		rptw = nil;
63937da2899SCharles.Forsyth 	}
64037da2899SCharles.Forsyth 	if (tk == blinkw)
64137da2899SCharles.Forsyth 		blinkw = nil;
64237da2899SCharles.Forsyth 	tkextnfreeobj(tk);
64337da2899SCharles.Forsyth 	tkmethod[tk->type]->free(tk);
64437da2899SCharles.Forsyth 	tkputenv(tk->env);
64537da2899SCharles.Forsyth 	tkfreebind(tk->binds);
64637da2899SCharles.Forsyth 	if(tk->name != nil)
64737da2899SCharles.Forsyth 		free(tk->name);
64837da2899SCharles.Forsyth 	free(tk);
64937da2899SCharles.Forsyth }
65037da2899SCharles.Forsyth 
65137da2899SCharles.Forsyth char*
tkaddchild(TkTop * t,Tk * tk,TkName ** names)65237da2899SCharles.Forsyth tkaddchild(TkTop *t, Tk *tk, TkName **names)
65337da2899SCharles.Forsyth {
65437da2899SCharles.Forsyth 	TkName *n;
65537da2899SCharles.Forsyth 	Tk *f, **l;
65637da2899SCharles.Forsyth 	int found, len;
65737da2899SCharles.Forsyth 	char *s, *ep;
65837da2899SCharles.Forsyth 
65937da2899SCharles.Forsyth 	n = *names;
66037da2899SCharles.Forsyth 	if(n == nil || n->name[0] != '.'){
66137da2899SCharles.Forsyth 		if(n != nil)
66237da2899SCharles.Forsyth 			tkerr(t, n->name);
66337da2899SCharles.Forsyth 		return TkBadwp;
66437da2899SCharles.Forsyth 	}
66537da2899SCharles.Forsyth 
66637da2899SCharles.Forsyth 	if (n->name[1] == '\0')
66737da2899SCharles.Forsyth 		return TkDupli;
66837da2899SCharles.Forsyth 
66937da2899SCharles.Forsyth 	/*
67037da2899SCharles.Forsyth 	 * check that the name is well-formed.
67137da2899SCharles.Forsyth 	 * ep will point to end of parent component of the name.
67237da2899SCharles.Forsyth 	 */
67337da2899SCharles.Forsyth 	ep = nil;
67437da2899SCharles.Forsyth 	for (s = n->name + 1; *s; s++) {
67537da2899SCharles.Forsyth 		if (*s == '.'){
67637da2899SCharles.Forsyth 			tkerr(t, n->name);
67737da2899SCharles.Forsyth 			return TkBadwp;
67837da2899SCharles.Forsyth 		}
67937da2899SCharles.Forsyth 		for (; *s && *s != '.'; s++)
68037da2899SCharles.Forsyth 			;
68137da2899SCharles.Forsyth 		if (*s == '\0')
68237da2899SCharles.Forsyth 			break;
68337da2899SCharles.Forsyth 		ep = s;
68437da2899SCharles.Forsyth 	}
68537da2899SCharles.Forsyth 	if (ep == s - 1){
68637da2899SCharles.Forsyth 		tkerr(t, n->name);
68737da2899SCharles.Forsyth 		return TkBadwp;
68837da2899SCharles.Forsyth 	}
68937da2899SCharles.Forsyth 	if (ep == nil)
69037da2899SCharles.Forsyth 		ep = n->name + 1;
69137da2899SCharles.Forsyth 	len = ep - n->name;
69237da2899SCharles.Forsyth 
69337da2899SCharles.Forsyth 	found = 0;
69437da2899SCharles.Forsyth 	l = &t->root;
69537da2899SCharles.Forsyth 	for(f = *l; f; f = f->siblings) {
69637da2899SCharles.Forsyth 		if (f->name != nil) {
69737da2899SCharles.Forsyth 			if (strcmp(n->name, f->name->name) == 0)
69837da2899SCharles.Forsyth 				return TkDupli;
69937da2899SCharles.Forsyth 			if (!found &&
70037da2899SCharles.Forsyth 					strncmp(n->name, f->name->name, len) == 0 &&
70137da2899SCharles.Forsyth 					f->name->name[len] == '\0')
70237da2899SCharles.Forsyth 				found = 1;
70337da2899SCharles.Forsyth 		}
70437da2899SCharles.Forsyth 		l = &f->siblings;
70537da2899SCharles.Forsyth 	}
70637da2899SCharles.Forsyth 	if (0) {		/* don't enable this until a reasonably major release... if ever */
70737da2899SCharles.Forsyth 		/*
70837da2899SCharles.Forsyth 		 * parent widget must already exist
70937da2899SCharles.Forsyth 		 */
71037da2899SCharles.Forsyth 		if (!found){
71137da2899SCharles.Forsyth 			tkerr(t, n->name);
71237da2899SCharles.Forsyth 			return TkBadwp;
71337da2899SCharles.Forsyth 		}
71437da2899SCharles.Forsyth 	}
71537da2899SCharles.Forsyth 	*l = tk;
71637da2899SCharles.Forsyth 	tk->name = n;
71737da2899SCharles.Forsyth 	*names = n->link;
71837da2899SCharles.Forsyth 
71937da2899SCharles.Forsyth 	return nil;
72037da2899SCharles.Forsyth }
72137da2899SCharles.Forsyth 
72237da2899SCharles.Forsyth Tk*
tklook(TkTop * t,char * wp,int parent)72337da2899SCharles.Forsyth tklook(TkTop *t, char *wp, int parent)
72437da2899SCharles.Forsyth {
72537da2899SCharles.Forsyth 	Tk *f;
72637da2899SCharles.Forsyth 	char *p, *q;
72737da2899SCharles.Forsyth 
72837da2899SCharles.Forsyth 	if(wp == nil)
72937da2899SCharles.Forsyth 		return nil;
73037da2899SCharles.Forsyth 
73137da2899SCharles.Forsyth 	if(parent) {
73237da2899SCharles.Forsyth 		p = strdup(wp);
73337da2899SCharles.Forsyth 		if(p == nil)
73437da2899SCharles.Forsyth 			return nil;
73537da2899SCharles.Forsyth 		q = strrchr(p, '.');
73637da2899SCharles.Forsyth 		if(q == nil)
73737da2899SCharles.Forsyth 			abort();
73837da2899SCharles.Forsyth 		if(q == p) {
73937da2899SCharles.Forsyth 			free(p);
74037da2899SCharles.Forsyth 			return t->root;
74137da2899SCharles.Forsyth 		}
74237da2899SCharles.Forsyth 		*q = '\0';
74337da2899SCharles.Forsyth 	} else
74437da2899SCharles.Forsyth 		p = wp;
74537da2899SCharles.Forsyth 
74637da2899SCharles.Forsyth 	for(f = t->root; f; f = f->siblings)
74737da2899SCharles.Forsyth 		if ((f->name != nil) && (strcmp(f->name->name, p) == 0))
74837da2899SCharles.Forsyth 			break;
74937da2899SCharles.Forsyth 
75037da2899SCharles.Forsyth 	if(f != nil && (f->flag & Tkdestroy))
75137da2899SCharles.Forsyth 		f = nil;
75237da2899SCharles.Forsyth 
75337da2899SCharles.Forsyth 	if (parent)
75437da2899SCharles.Forsyth 		free(p);
75537da2899SCharles.Forsyth 	return f;
75637da2899SCharles.Forsyth }
75737da2899SCharles.Forsyth 
75837da2899SCharles.Forsyth void
tktextsdraw(Image * img,Rectangle r,TkEnv * e,int sbw)75937da2899SCharles.Forsyth tktextsdraw(Image *img, Rectangle r, TkEnv *e, int sbw)
76037da2899SCharles.Forsyth {
76137da2899SCharles.Forsyth 	Image *l, *d;
76237da2899SCharles.Forsyth 	Rectangle s;
76337da2899SCharles.Forsyth 
76437da2899SCharles.Forsyth 	draw(img, r, tkgc(e, TkCselectbgnd), nil, ZP);
76537da2899SCharles.Forsyth 	s.min = r.min;
76637da2899SCharles.Forsyth 	s.min.x -= sbw;
76737da2899SCharles.Forsyth 	s.min.y -= sbw;
76837da2899SCharles.Forsyth 	s.max.x = r.max.x;
76937da2899SCharles.Forsyth 	s.max.y = r.min.y;
77037da2899SCharles.Forsyth 	l = tkgc(e, TkCselectbgndlght);
77137da2899SCharles.Forsyth 	draw(img, s, l, nil, ZP);
77237da2899SCharles.Forsyth 	s.max.x = s.min.x + sbw;
77337da2899SCharles.Forsyth 	s.max.y = r.max.y + sbw;
77437da2899SCharles.Forsyth 	draw(img, s, l, nil, ZP);
77537da2899SCharles.Forsyth 	s.max = r.max;
77637da2899SCharles.Forsyth 	s.max.x += sbw;
77737da2899SCharles.Forsyth 	s.max.y += sbw;
77837da2899SCharles.Forsyth 	s.min.x = r.min.x;
77937da2899SCharles.Forsyth 	s.min.y = r.max.y;
78037da2899SCharles.Forsyth 	d = tkgc(e, TkCselectbgnddark);
78137da2899SCharles.Forsyth 	draw(img, s, d, nil, ZP);
78237da2899SCharles.Forsyth 	s.min.x = r.max.x;
78337da2899SCharles.Forsyth 	s.min.y = r.min.y - sbw;
78437da2899SCharles.Forsyth 	draw(img, s, d, nil, ZP);
78537da2899SCharles.Forsyth }
78637da2899SCharles.Forsyth 
78737da2899SCharles.Forsyth void
tkbox(Image * i,Rectangle r,int bd,Image * fill)78837da2899SCharles.Forsyth tkbox(Image *i, Rectangle r, int bd, Image *fill)
78937da2899SCharles.Forsyth {
79037da2899SCharles.Forsyth 	if (bd > 0) {
79137da2899SCharles.Forsyth 		draw(i, Rect(r.min.x, r.min.y, r.max.x, r.min.y+bd), fill, nil, ZP);
79237da2899SCharles.Forsyth 		draw(i, Rect(r.min.x, r.min.y+bd, r.min.x+bd, r.max.y-bd), fill, nil, ZP);
79337da2899SCharles.Forsyth 		draw(i, Rect(r.min.x, r.max.y-bd, r.max.x, r.max.y), fill, nil, ZP);
79437da2899SCharles.Forsyth 		draw(i, Rect(r.max.x-bd, r.min.y+bd, r.max.x, r.max.y), fill, nil, ZP);
79537da2899SCharles.Forsyth 	}
79637da2899SCharles.Forsyth }
79737da2899SCharles.Forsyth 
79837da2899SCharles.Forsyth void
tkbevel(Image * i,Point o,int w,int h,int bw,Image * top,Image * bottom)79937da2899SCharles.Forsyth tkbevel(Image *i, Point o, int w, int h, int bw, Image *top, Image *bottom)
80037da2899SCharles.Forsyth {
80137da2899SCharles.Forsyth 	Rectangle r;
80237da2899SCharles.Forsyth 	int x, border;
80337da2899SCharles.Forsyth 
80437da2899SCharles.Forsyth 	border = 2 * bw;
80537da2899SCharles.Forsyth 
80637da2899SCharles.Forsyth 	r.min = o;
80737da2899SCharles.Forsyth 	r.max.x = r.min.x + w + border;
80837da2899SCharles.Forsyth 	r.max.y = r.min.y + bw;
80937da2899SCharles.Forsyth 	draw(i, r, top, nil, ZP);
81037da2899SCharles.Forsyth 
81137da2899SCharles.Forsyth 	r.max.x = r.min.x + bw;
81237da2899SCharles.Forsyth 	r.max.y = r.min.y + h + border;
81337da2899SCharles.Forsyth 	draw(i, r, top, nil, ZP);
81437da2899SCharles.Forsyth 
81537da2899SCharles.Forsyth 	r.max.x = o.x + w + border;
81637da2899SCharles.Forsyth 	r.max.y = o.y + h + border;
81737da2899SCharles.Forsyth 	r.min.x = o.x + bw;
81837da2899SCharles.Forsyth 	r.min.y = r.max.y - bw;
81937da2899SCharles.Forsyth 	for(x = 0; x < bw; x++) {
82037da2899SCharles.Forsyth 		draw(i, r, bottom, nil, ZP);
82137da2899SCharles.Forsyth 		r.min.x--;
82237da2899SCharles.Forsyth 		r.min.y++;
82337da2899SCharles.Forsyth 	}
82437da2899SCharles.Forsyth 	r.min.x = o.x + bw + w;
82537da2899SCharles.Forsyth 	r.min.y = o.y + bw;
82637da2899SCharles.Forsyth 	for(x = bw; x >= 0; x--) {
82737da2899SCharles.Forsyth 		draw(i, r, bottom, nil, ZP);
82837da2899SCharles.Forsyth 		r.min.x++;
82937da2899SCharles.Forsyth 		r.min.y--;
83037da2899SCharles.Forsyth 	}
83137da2899SCharles.Forsyth }
83237da2899SCharles.Forsyth 
83337da2899SCharles.Forsyth /*
83437da2899SCharles.Forsyth  * draw a relief border.
83537da2899SCharles.Forsyth  * color is an index into tk->env->colors and assumes
83637da2899SCharles.Forsyth  * light and dark versions following immediately after
83737da2899SCharles.Forsyth  * that index
83837da2899SCharles.Forsyth  */
83937da2899SCharles.Forsyth void
tkdrawrelief(Image * i,Tk * tk,Point o,int color,int rlf)84037da2899SCharles.Forsyth tkdrawrelief(Image *i, Tk *tk, Point o, int color, int rlf)
84137da2899SCharles.Forsyth {
84237da2899SCharles.Forsyth 	TkEnv *e;
84337da2899SCharles.Forsyth 	Image *l, *d, *t;
84437da2899SCharles.Forsyth 	int h, w, bd, bd1, bd2;
84537da2899SCharles.Forsyth 
84637da2899SCharles.Forsyth 	if(tk->borderwidth == 0)
84737da2899SCharles.Forsyth 		return;
84837da2899SCharles.Forsyth 
84937da2899SCharles.Forsyth 	h = tk->act.height;
85037da2899SCharles.Forsyth 	w = tk->act.width;
85137da2899SCharles.Forsyth 
85237da2899SCharles.Forsyth 	e = tk->env;
85337da2899SCharles.Forsyth 	if (color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
85437da2899SCharles.Forsyth 		l = tkgc(e, color+TkLightshade);
85537da2899SCharles.Forsyth 		d = tkgc(e, color+TkDarkshade);
85637da2899SCharles.Forsyth 	} else {
85737da2899SCharles.Forsyth 		l = tkgshade(e, color, TkLightshade);
85837da2899SCharles.Forsyth 		d = tkgshade(e, color, TkDarkshade);
85937da2899SCharles.Forsyth 	}
86037da2899SCharles.Forsyth 	bd = tk->borderwidth;
86137da2899SCharles.Forsyth 	if(rlf < 0)
86237da2899SCharles.Forsyth 		rlf = TKraised;
86337da2899SCharles.Forsyth 	switch(rlf) {
86437da2899SCharles.Forsyth 	case TKflat:
86537da2899SCharles.Forsyth 		break;
86637da2899SCharles.Forsyth 	case TKsunken:
86737da2899SCharles.Forsyth 		tkbevel(i, o, w, h, bd, d, l);
86837da2899SCharles.Forsyth 		break;
86937da2899SCharles.Forsyth 	case TKraised:
87037da2899SCharles.Forsyth 		tkbevel(i, o, w, h, bd, l, d);
87137da2899SCharles.Forsyth 		break;
87237da2899SCharles.Forsyth 	case TKgroove:
87337da2899SCharles.Forsyth 		t = d;
87437da2899SCharles.Forsyth 		d = l;
87537da2899SCharles.Forsyth 		l = t;
87637da2899SCharles.Forsyth 		/* fall through */
87737da2899SCharles.Forsyth 	case TKridge:
87837da2899SCharles.Forsyth 		bd1 = bd/2;
87937da2899SCharles.Forsyth 		bd2 = bd - bd1;
88037da2899SCharles.Forsyth 		if(bd1 > 0)
88137da2899SCharles.Forsyth 			tkbevel(i, o, w + 2*bd2, h + 2*bd2, bd1, l, d);
88237da2899SCharles.Forsyth 		o.x += bd1;
88337da2899SCharles.Forsyth 		o.y += bd1;
88437da2899SCharles.Forsyth 		tkbevel(i, o, w, h, bd2, d, l);
88537da2899SCharles.Forsyth 		break;
88637da2899SCharles.Forsyth 	}
88737da2899SCharles.Forsyth }
88837da2899SCharles.Forsyth 
88937da2899SCharles.Forsyth Point
tkstringsize(Tk * tk,char * text)89037da2899SCharles.Forsyth tkstringsize(Tk *tk, char *text)
89137da2899SCharles.Forsyth {
89237da2899SCharles.Forsyth 	char *q;
89337da2899SCharles.Forsyth 	int locked;
89437da2899SCharles.Forsyth 	Display *d;
89537da2899SCharles.Forsyth 	Point p, t;
89637da2899SCharles.Forsyth 
89737da2899SCharles.Forsyth 	if(text == nil) {
89837da2899SCharles.Forsyth 		p.x = 0;
89937da2899SCharles.Forsyth 		p.y = tk->env->font->height;
90037da2899SCharles.Forsyth 		return p;
90137da2899SCharles.Forsyth 	}
90237da2899SCharles.Forsyth 
90337da2899SCharles.Forsyth 	d = tk->env->top->display;
90437da2899SCharles.Forsyth 	locked = lockdisplay(d);
90537da2899SCharles.Forsyth 
90637da2899SCharles.Forsyth 	p = ZP;
90737da2899SCharles.Forsyth 	while(*text) {
90837da2899SCharles.Forsyth 		q = strchr(text, '\n');
90937da2899SCharles.Forsyth 		if(q != nil)
91037da2899SCharles.Forsyth 			*q = '\0';
91137da2899SCharles.Forsyth 		t = stringsize(tk->env->font, text);
91237da2899SCharles.Forsyth 		p.y += t.y;
91337da2899SCharles.Forsyth 		if(p.x < t.x)
91437da2899SCharles.Forsyth 			p.x = t.x;
91537da2899SCharles.Forsyth 		if(q == nil)
91637da2899SCharles.Forsyth 			break;
91737da2899SCharles.Forsyth 		text = q+1;
91837da2899SCharles.Forsyth 		*q = '\n';
91937da2899SCharles.Forsyth 	}
92037da2899SCharles.Forsyth 	if(locked)
92137da2899SCharles.Forsyth 		unlockdisplay(d);
92237da2899SCharles.Forsyth 
92337da2899SCharles.Forsyth 	return p;
92437da2899SCharles.Forsyth }
92537da2899SCharles.Forsyth 
9260db9190eSforsyth static void
tkulall(Image * i,Point o,Image * col,Font * f,char * text)9270db9190eSforsyth tkulall(Image *i, Point o, Image *col, Font *f, char *text)
9280db9190eSforsyth {
9290db9190eSforsyth 	Rectangle r;
9300db9190eSforsyth 
9310db9190eSforsyth 	r.max = stringsize(f, text);
9320db9190eSforsyth 	r.max = addpt(r.max, o);
9330db9190eSforsyth 	r.min.x = o.x;
9340db9190eSforsyth 	r.min.y = r.max.y - 1;
9350db9190eSforsyth 	draw(i, r, col, nil, ZP);
9360db9190eSforsyth }
9370db9190eSforsyth 
9380db9190eSforsyth static void
tkul(Image * i,Point o,Image * col,int ul,Font * f,char * text)93937da2899SCharles.Forsyth tkul(Image *i, Point o, Image *col, int ul, Font *f, char *text)
94037da2899SCharles.Forsyth {
94137da2899SCharles.Forsyth 	char c, *v;
94237da2899SCharles.Forsyth 	Rectangle r;
94337da2899SCharles.Forsyth 
94437da2899SCharles.Forsyth 	v = text+ul+1;
94537da2899SCharles.Forsyth 	c = *v;
94637da2899SCharles.Forsyth 	*v = '\0';
94737da2899SCharles.Forsyth 	r.max = stringsize(f, text);
94837da2899SCharles.Forsyth 	r.max = addpt(r.max, o);
94937da2899SCharles.Forsyth 	r.min = stringsize(f, v-1);
95037da2899SCharles.Forsyth 	*v = c;
95137da2899SCharles.Forsyth 	r.min.x = r.max.x - r.min.x;
95237da2899SCharles.Forsyth 	r.min.y = r.max.y - 1;
9531b078c23Sforsyth 	r.max.y++;
95437da2899SCharles.Forsyth 	draw(i, r, col, nil, ZP);
95537da2899SCharles.Forsyth }
95637da2899SCharles.Forsyth 
9577668638cSforsyth void
tkdrawstring(Tk * tk,Image * i,Point o,char * text,int ul,Image * col,int j)95837da2899SCharles.Forsyth tkdrawstring(Tk *tk, Image *i, Point o, char *text, int ul, Image *col, int j)
95937da2899SCharles.Forsyth {
96037da2899SCharles.Forsyth 	int n, l, maxl, sox;
96137da2899SCharles.Forsyth 	char *q, *txt;
96237da2899SCharles.Forsyth 	Point p;
96337da2899SCharles.Forsyth 	TkEnv *e;
96437da2899SCharles.Forsyth 
96537da2899SCharles.Forsyth 	e = tk->env;
96637da2899SCharles.Forsyth 	sox = maxl = 0;
96737da2899SCharles.Forsyth 	if(j != Tkleft){
96837da2899SCharles.Forsyth 		maxl = 0;
96937da2899SCharles.Forsyth 		txt = text;
97037da2899SCharles.Forsyth 		while(*txt){
97137da2899SCharles.Forsyth 			q = strchr(txt, '\n');
97237da2899SCharles.Forsyth 			if(q != nil)
97337da2899SCharles.Forsyth 				*q = '\0';
97437da2899SCharles.Forsyth 			l = stringwidth(e->font, txt);
97537da2899SCharles.Forsyth 			if(l > maxl)
97637da2899SCharles.Forsyth 				maxl = l;
97737da2899SCharles.Forsyth 			if(q == nil)
97837da2899SCharles.Forsyth 				break;
97937da2899SCharles.Forsyth 			txt = q+1;
98037da2899SCharles.Forsyth 			*q = '\n';
98137da2899SCharles.Forsyth 		}
98237da2899SCharles.Forsyth 		sox = o.x;
98337da2899SCharles.Forsyth 	}
98437da2899SCharles.Forsyth 	while(*text) {
98537da2899SCharles.Forsyth 		q = strchr(text, '\n');
98637da2899SCharles.Forsyth 		if(q != nil)
98737da2899SCharles.Forsyth 			*q = '\0';
98837da2899SCharles.Forsyth 		if(j != Tkleft){
98937da2899SCharles.Forsyth 			o.x = sox;
99037da2899SCharles.Forsyth 			l = stringwidth(e->font, text);
99137da2899SCharles.Forsyth 			if(j == Tkcenter)
99237da2899SCharles.Forsyth 				o.x += (maxl-l)/2;
99337da2899SCharles.Forsyth 			else
99437da2899SCharles.Forsyth 				o.x += maxl-l;
99537da2899SCharles.Forsyth 		}
99637da2899SCharles.Forsyth 		p = string(i, o, col, o, e->font, text);
99737da2899SCharles.Forsyth 		if(ul >= 0) {
99837da2899SCharles.Forsyth 			n = strlen(text);
99937da2899SCharles.Forsyth 			if(ul < n) {
10000db9190eSforsyth 				tkul(i, o, col, ul, e->font, text);
100137da2899SCharles.Forsyth 				ul = -1;
10020db9190eSforsyth 			} else if(ul == n) {
10030db9190eSforsyth 				tkulall(i, o, col, e->font, text);
10040db9190eSforsyth 				ul = -1;
10050db9190eSforsyth 			} else
100637da2899SCharles.Forsyth 				ul -= n;
100737da2899SCharles.Forsyth 		}
100837da2899SCharles.Forsyth 		o.y += e->font->height;
100937da2899SCharles.Forsyth 		if(q == nil)
101037da2899SCharles.Forsyth 			break;
101137da2899SCharles.Forsyth 		text = q+1;
101237da2899SCharles.Forsyth 		*q = '\n';
101337da2899SCharles.Forsyth 	}
101437da2899SCharles.Forsyth }
101537da2899SCharles.Forsyth 
101637da2899SCharles.Forsyth /* for debugging */
101737da2899SCharles.Forsyth char*
tkname(Tk * tk)101837da2899SCharles.Forsyth tkname(Tk *tk)
101937da2899SCharles.Forsyth {
1020*5849851aSforsyth 	if(tk == nil)
1021*5849851aSforsyth 		return "(nil)";
1022*5849851aSforsyth 	if(tk->name == nil)
1023*5849851aSforsyth 		return "(noname)";
1024*5849851aSforsyth 	return tk->name->name;
102537da2899SCharles.Forsyth }
102637da2899SCharles.Forsyth 
102737da2899SCharles.Forsyth Tk*
tkdeliver(Tk * tk,int event,void * data)102837da2899SCharles.Forsyth tkdeliver(Tk *tk, int event, void *data)
102937da2899SCharles.Forsyth {
103037da2899SCharles.Forsyth 	Tk *dest;
1031*5849851aSforsyth 
1032*5849851aSforsyth 	if(tk != nil && ((ulong)tk->type >= TKwidgets || (ulong)tk->name < 4096 && tk->name != nil)){
1033*5849851aSforsyth 		print("invalid Tk: type %d name %p\n", tk->type, tk->name);
1034*5849851aSforsyth 		abort();
1035*5849851aSforsyth 	}
103637da2899SCharles.Forsyth //print("tkdeliver %v to %s\n", event, tkname(tk));
103737da2899SCharles.Forsyth 	if(tk == nil || ((tk->flag&Tkdestroy) && event != TkDestroy))
103837da2899SCharles.Forsyth 		return tk;
103937da2899SCharles.Forsyth 	if(event&(TkFocusin|TkFocusout) && (tk->flag&Tktakefocus))
104037da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
104137da2899SCharles.Forsyth 
104237da2899SCharles.Forsyth 	if (tkmethod[tk->type]->deliver != nil) {
104337da2899SCharles.Forsyth 		dest = tkmethod[tk->type]->deliver(tk, event, data);
104437da2899SCharles.Forsyth 		if (dest == nil)
104537da2899SCharles.Forsyth 			return tk;
104637da2899SCharles.Forsyth 		tkdirty(tk);
104737da2899SCharles.Forsyth 		return dest;
104837da2899SCharles.Forsyth 	}
104937da2899SCharles.Forsyth 
105037da2899SCharles.Forsyth 	if((tk->flag & Tkdisabled) == 0)
105137da2899SCharles.Forsyth 		tksubdeliver(tk, tk->binds, event, data, 0);
105237da2899SCharles.Forsyth 	tkdirty(tk);
105337da2899SCharles.Forsyth 	return tk;
105437da2899SCharles.Forsyth }
105537da2899SCharles.Forsyth 
105637da2899SCharles.Forsyth static int
nullop(char * fmt,...)105737da2899SCharles.Forsyth nullop(char *fmt, ...)
105837da2899SCharles.Forsyth {
105937da2899SCharles.Forsyth 	USED(fmt);
106037da2899SCharles.Forsyth 	return 0;
106137da2899SCharles.Forsyth }
106237da2899SCharles.Forsyth 
106337da2899SCharles.Forsyth int
tksubdeliver(Tk * tk,TkAction * binds,int event,void * data,int extn)106437da2899SCharles.Forsyth tksubdeliver(Tk *tk, TkAction *binds, int event, void *data, int extn)
106537da2899SCharles.Forsyth {
106637da2899SCharles.Forsyth 
106737da2899SCharles.Forsyth 	TkAction *a;
106837da2899SCharles.Forsyth 	int delivered, genkey, delivered2, iskey;
106937da2899SCharles.Forsyth //int (*debug)(char *fmt, ...);
1070*5849851aSforsyth 
107137da2899SCharles.Forsyth 	if (!extn)
107237da2899SCharles.Forsyth 		return tkextndeliver(tk, binds, event, data);
107337da2899SCharles.Forsyth 
107437da2899SCharles.Forsyth //debug = (tk->name && !strcmp(tk->name->name, ".cd")) ? print : nullop;
107537da2899SCharles.Forsyth //debug("subdeliver %v\n", event);
107637da2899SCharles.Forsyth 
107737da2899SCharles.Forsyth 	if (event & TkTakefocus) {
107837da2899SCharles.Forsyth 		if (tk->flag & Tktakefocus)
107937da2899SCharles.Forsyth 			tksetkeyfocus(tk->env->top, tk, 0);
108037da2899SCharles.Forsyth 		return TkDdelivered;
108137da2899SCharles.Forsyth 	}
108237da2899SCharles.Forsyth 
108337da2899SCharles.Forsyth 	delivered = TkDnone;
108437da2899SCharles.Forsyth 	genkey = 0;
108537da2899SCharles.Forsyth 	for(a = binds; a != nil; a = a->link) {
108637da2899SCharles.Forsyth 		if(event == a->event) {
108737da2899SCharles.Forsyth //debug("  exact match on %v\n", a->event);
108837da2899SCharles.Forsyth 			tkcmdbind(tk, event, a->arg, data);
108937da2899SCharles.Forsyth 			delivered = TkDdelivered;
109037da2899SCharles.Forsyth 		} else if (a->event == TkKey && (a->type>>8)==TkAadd)
109137da2899SCharles.Forsyth 			genkey = 1;
109237da2899SCharles.Forsyth 	}
109337da2899SCharles.Forsyth 	if(delivered != TkDnone && !((event & TkKey) && genkey))
109437da2899SCharles.Forsyth 		return delivered;
109537da2899SCharles.Forsyth 
109637da2899SCharles.Forsyth 	delivered2 = delivered;
109737da2899SCharles.Forsyth 	for(a = binds; a != nil; a = a->link) {
109837da2899SCharles.Forsyth 		/*
109937da2899SCharles.Forsyth 		 * only bind to non-specific key events; if a specific
110037da2899SCharles.Forsyth 		 * key event has already been delivered, only deliver event if
110137da2899SCharles.Forsyth 		 * the non-specific binding was added. (TkAadd)
110237da2899SCharles.Forsyth 		 */
110337da2899SCharles.Forsyth 		if (a->event & TkExtns)
110437da2899SCharles.Forsyth 			continue;
110537da2899SCharles.Forsyth 		iskey = (a->event & TkKey);
110637da2899SCharles.Forsyth 		if (iskey ^ (event & TkKey))
110737da2899SCharles.Forsyth 			continue;
110837da2899SCharles.Forsyth 		if(iskey && (TKKEY(a->event) != 0
110937da2899SCharles.Forsyth 					|| ((a->type>>8) != TkAadd && delivered != TkDnone)))
111037da2899SCharles.Forsyth 			continue;
111137da2899SCharles.Forsyth 		if(!iskey && (a->event & TkMotion) && (a->event&TkEpress) != 0)
111237da2899SCharles.Forsyth 			continue;
111337da2899SCharles.Forsyth 		if(!(event & TkDouble) && (a->event & TkDouble))
111437da2899SCharles.Forsyth 			continue;
111537da2899SCharles.Forsyth 		if((event & ~TkDouble) & a->event) {
111637da2899SCharles.Forsyth //debug("  partial match on %v\n", a->event);
111737da2899SCharles.Forsyth 			tkcmdbind(tk, event, a->arg, data);
111837da2899SCharles.Forsyth 			delivered2 = TkDdelivered;
111937da2899SCharles.Forsyth 		}
112037da2899SCharles.Forsyth 	}
112137da2899SCharles.Forsyth 	return delivered2;
112237da2899SCharles.Forsyth }
112337da2899SCharles.Forsyth 
112437da2899SCharles.Forsyth void
tkcancel(TkAction ** l,int event)112537da2899SCharles.Forsyth tkcancel(TkAction **l, int event)
112637da2899SCharles.Forsyth {
112737da2899SCharles.Forsyth 	TkAction *a;
112837da2899SCharles.Forsyth 
112937da2899SCharles.Forsyth 	for(a = *l; a; a = *l) {
113037da2899SCharles.Forsyth 		if(a->event == event) {
113137da2899SCharles.Forsyth 			*l = a->link;
113237da2899SCharles.Forsyth 			a->link = nil;
113337da2899SCharles.Forsyth 			tkfreebind(a);
113437da2899SCharles.Forsyth 			continue;
113537da2899SCharles.Forsyth 		}
113637da2899SCharles.Forsyth 		l = &a->link;
113737da2899SCharles.Forsyth 	}
113837da2899SCharles.Forsyth }
113937da2899SCharles.Forsyth 
114037da2899SCharles.Forsyth static void
tkcancela(TkAction ** l,int event,int type,char * arg)114137da2899SCharles.Forsyth tkcancela(TkAction **l, int event, int type, char *arg)
114237da2899SCharles.Forsyth {
114337da2899SCharles.Forsyth 	TkAction *a;
114437da2899SCharles.Forsyth 
114537da2899SCharles.Forsyth 	for(a = *l; a; a = *l) {
114637da2899SCharles.Forsyth 		if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
114737da2899SCharles.Forsyth 			*l = a->link;
114837da2899SCharles.Forsyth 			a->link = nil;
114937da2899SCharles.Forsyth 			tkfreebind(a);
115037da2899SCharles.Forsyth 			continue;
115137da2899SCharles.Forsyth 		}
115237da2899SCharles.Forsyth 		l = &a->link;
115337da2899SCharles.Forsyth 	}
115437da2899SCharles.Forsyth }
115537da2899SCharles.Forsyth 
115637da2899SCharles.Forsyth char*
tkaction(TkAction ** l,int event,int type,char * arg,int how)115737da2899SCharles.Forsyth tkaction(TkAction **l, int event, int type, char *arg, int how)
115837da2899SCharles.Forsyth {
115937da2899SCharles.Forsyth 	TkAction *a;
116037da2899SCharles.Forsyth 
116137da2899SCharles.Forsyth 	if(arg == nil)
116237da2899SCharles.Forsyth 		return nil;
116337da2899SCharles.Forsyth 	if(how == TkArepl)
116437da2899SCharles.Forsyth 		tkcancel(l, event);
116537da2899SCharles.Forsyth 	else if(how == TkAadd){
116637da2899SCharles.Forsyth 		for(a = *l; a; a = a->link)
116737da2899SCharles.Forsyth 			if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
116837da2899SCharles.Forsyth 				a->type = type + (how << 8);
116937da2899SCharles.Forsyth 				return nil;
117037da2899SCharles.Forsyth 			}
117137da2899SCharles.Forsyth 	}
117237da2899SCharles.Forsyth 	else if(how == TkAsub){
117337da2899SCharles.Forsyth 		tkcancela(l, event, type, arg);
117437da2899SCharles.Forsyth 		if(type == TkDynamic)	/* should always be the case */
117537da2899SCharles.Forsyth 			free(arg);
117637da2899SCharles.Forsyth 		return nil;
117737da2899SCharles.Forsyth 	}
117837da2899SCharles.Forsyth 
117937da2899SCharles.Forsyth 	a = malloc(sizeof(TkAction));
118037da2899SCharles.Forsyth 	if(a == nil) {
118137da2899SCharles.Forsyth 		if(type == TkDynamic)
118237da2899SCharles.Forsyth 			free(arg);
118337da2899SCharles.Forsyth 		return TkNomem;
118437da2899SCharles.Forsyth 	}
118537da2899SCharles.Forsyth 
118637da2899SCharles.Forsyth 	a->event = event;
118737da2899SCharles.Forsyth 	a->arg = arg;
118837da2899SCharles.Forsyth 	a->type = type + (how << 8);
118937da2899SCharles.Forsyth 
119037da2899SCharles.Forsyth 	a->link = *l;
119137da2899SCharles.Forsyth 	*l = a;
119237da2899SCharles.Forsyth 
119337da2899SCharles.Forsyth 	return nil;
119437da2899SCharles.Forsyth }
119537da2899SCharles.Forsyth 
119637da2899SCharles.Forsyth char*
tkitem(char * buf,char * a)119737da2899SCharles.Forsyth tkitem(char *buf, char *a)
119837da2899SCharles.Forsyth {
119937da2899SCharles.Forsyth 	char *e;
120037da2899SCharles.Forsyth 
120137da2899SCharles.Forsyth 	while(*a && (*a == ' ' || *a == '\t'))
120237da2899SCharles.Forsyth 		a++;
120337da2899SCharles.Forsyth 
120437da2899SCharles.Forsyth 	e = buf + Tkmaxitem - 1;
120537da2899SCharles.Forsyth 	while(*a && *a != ' ' && *a != '\t' && buf < e)
120637da2899SCharles.Forsyth 		*buf++ = *a++;
120737da2899SCharles.Forsyth 
120837da2899SCharles.Forsyth 	*buf = '\0';
120937da2899SCharles.Forsyth 	while(*a && (*a == ' ' || *a == '\t'))
121037da2899SCharles.Forsyth 		a++;
121137da2899SCharles.Forsyth 	return a;
121237da2899SCharles.Forsyth }
121337da2899SCharles.Forsyth 
1214*5849851aSforsyth /*
1215*5849851aSforsyth  * if tk is a subwindow or a descendent, return the subwindow;
1216*5849851aSforsyth  * return nil otherwise
121737da2899SCharles.Forsyth  */
1218*5849851aSforsyth Tk*
tkfindsub(Tk * tk)1219*5849851aSforsyth tkfindsub(Tk *tk)
1220*5849851aSforsyth {
1221*5849851aSforsyth 	for(; tk != nil; tk = tk->master){
1222*5849851aSforsyth 		if(tk->parent != nil)
1223*5849851aSforsyth 			return tk;	/* tk->parent is canvas or text */
1224*5849851aSforsyth 	}
1225*5849851aSforsyth 	return nil;
122637da2899SCharles.Forsyth }
122737da2899SCharles.Forsyth 
122837da2899SCharles.Forsyth /*
122937da2899SCharles.Forsyth  * Return absolute screen position of tk (just outside its top-left border).
123037da2899SCharles.Forsyth  * When a widget is embedded in a text or canvas widget, we need to
123137da2899SCharles.Forsyth  * use the text or canvas's relpos() function instead of act{x,y}, and we
123237da2899SCharles.Forsyth  * need to folow up the parent pointer rather than the master one.
123337da2899SCharles.Forsyth  */
123437da2899SCharles.Forsyth Point
tkposn(Tk * tk)123537da2899SCharles.Forsyth tkposn(Tk *tk)
123637da2899SCharles.Forsyth {
123737da2899SCharles.Forsyth 	Tk *f, *last;
123837da2899SCharles.Forsyth 	Point g;
123937da2899SCharles.Forsyth 
124037da2899SCharles.Forsyth 	last = tk;
124137da2899SCharles.Forsyth 	if(tk->parent != nil) {
124237da2899SCharles.Forsyth 		g = tkmethod[tk->parent->type]->relpos(tk);
124337da2899SCharles.Forsyth 		f = tk->parent;
1244*5849851aSforsyth 	} else {
124537da2899SCharles.Forsyth 		g.x = tk->act.x;
124637da2899SCharles.Forsyth 		g.y = tk->act.y;
124737da2899SCharles.Forsyth 		f = tk->master;
124837da2899SCharles.Forsyth 	}
1249*5849851aSforsyth 	while(f != nil) {
125037da2899SCharles.Forsyth 		g.x += f->borderwidth;
125137da2899SCharles.Forsyth 		g.y += f->borderwidth;
125237da2899SCharles.Forsyth 		last = f;
125337da2899SCharles.Forsyth 		if(f->parent != nil) {
125437da2899SCharles.Forsyth 			g = addpt(g, tkmethod[f->parent->type]->relpos(f));
125537da2899SCharles.Forsyth 			f = f->parent;
1256*5849851aSforsyth 		} else {
125737da2899SCharles.Forsyth 			g.x += f->act.x;
125837da2899SCharles.Forsyth 			g.y += f->act.y;
125937da2899SCharles.Forsyth 			f = f->master;
126037da2899SCharles.Forsyth 		}
126137da2899SCharles.Forsyth 	}
126237da2899SCharles.Forsyth 	if (last->flag & Tkwindow)
126337da2899SCharles.Forsyth 		g = addpt(g, TKobj(TkWin, last)->req);
126437da2899SCharles.Forsyth 	return g;
126537da2899SCharles.Forsyth }
126637da2899SCharles.Forsyth 
126737da2899SCharles.Forsyth /*
126837da2899SCharles.Forsyth  * convert screen coords to local widget coords
126937da2899SCharles.Forsyth  */
127037da2899SCharles.Forsyth Point
tkscrn2local(Tk * tk,Point p)127137da2899SCharles.Forsyth tkscrn2local(Tk *tk, Point p)
127237da2899SCharles.Forsyth {
127337da2899SCharles.Forsyth 	p = subpt(p, tkposn(tk));
127437da2899SCharles.Forsyth 	p.x -= tk->borderwidth;
127537da2899SCharles.Forsyth 	p.y -= tk->borderwidth;
127637da2899SCharles.Forsyth 	return p;
127737da2899SCharles.Forsyth }
127837da2899SCharles.Forsyth 
127937da2899SCharles.Forsyth int
tkvisiblerect(Tk * tk,Rectangle * rr)128037da2899SCharles.Forsyth tkvisiblerect(Tk *tk, Rectangle *rr)
128137da2899SCharles.Forsyth {
128237da2899SCharles.Forsyth 	Rectangle r;
128337da2899SCharles.Forsyth 	Point g;
128437da2899SCharles.Forsyth 	Tk *f, *last;
128537da2899SCharles.Forsyth 	g = Pt(tk->borderwidth, tk->borderwidth);
128637da2899SCharles.Forsyth 	last = tk;
128737da2899SCharles.Forsyth 	if(tk->parent != nil) {
128837da2899SCharles.Forsyth 		g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
128937da2899SCharles.Forsyth 		f = tk->parent;
129037da2899SCharles.Forsyth 	} else {
129137da2899SCharles.Forsyth 		g.x += tk->act.x;
129237da2899SCharles.Forsyth 		g.y += tk->act.y;
129337da2899SCharles.Forsyth 		f = tk->master;
129437da2899SCharles.Forsyth 	}
129537da2899SCharles.Forsyth 	if (f == nil) {
129637da2899SCharles.Forsyth 		*rr = tkrect(tk, 1);
129737da2899SCharles.Forsyth 		return 1;
129837da2899SCharles.Forsyth 	}
129937da2899SCharles.Forsyth 	r = rectaddpt(tkrect(tk, 1), g);
130037da2899SCharles.Forsyth 	while (f) {
130137da2899SCharles.Forsyth 		if (!rectclip(&r, tkrect(f, 0)))
130237da2899SCharles.Forsyth 			return 0;
130337da2899SCharles.Forsyth 		g.x = f->borderwidth;
130437da2899SCharles.Forsyth 		g.y = f->borderwidth;
130537da2899SCharles.Forsyth 		last = f;
130637da2899SCharles.Forsyth 		if (f->parent != nil) {
130737da2899SCharles.Forsyth 			g = addpt(g, tkmethod[f->parent->type]->relpos(f));
130837da2899SCharles.Forsyth 			f = f->parent;
130937da2899SCharles.Forsyth 		} else {
131037da2899SCharles.Forsyth 			g.x += f->act.x;
131137da2899SCharles.Forsyth 			g.y += f->act.y;
131237da2899SCharles.Forsyth 			f = f->master;
131337da2899SCharles.Forsyth 		}
131437da2899SCharles.Forsyth 		r = rectaddpt(r, g);
131537da2899SCharles.Forsyth 	}
131637da2899SCharles.Forsyth 	if (last->flag & Tkwindow)
131737da2899SCharles.Forsyth 		r = rectaddpt(r, TKobj(TkWin, last)->act);
131837da2899SCharles.Forsyth 	/*
131937da2899SCharles.Forsyth 	 * now we have the visible rectangle in screen coords;
132037da2899SCharles.Forsyth 	 * subtract actx+borderwidth and we've got it back in
132137da2899SCharles.Forsyth 	 * widget-local coords again
132237da2899SCharles.Forsyth 	 */
132337da2899SCharles.Forsyth 	r = rectsubpt(r, tkposn(tk));
132437da2899SCharles.Forsyth 	*rr = rectsubpt(r, Pt(tk->borderwidth, tk->borderwidth));
132537da2899SCharles.Forsyth 	return 1;
132637da2899SCharles.Forsyth }
132737da2899SCharles.Forsyth 
132837da2899SCharles.Forsyth Point
tkanchorpoint(Rectangle r,Point size,int anchor)132937da2899SCharles.Forsyth tkanchorpoint(Rectangle r, Point size, int anchor)
133037da2899SCharles.Forsyth {
133137da2899SCharles.Forsyth 	int dx, dy;
133237da2899SCharles.Forsyth 	Point p;
133337da2899SCharles.Forsyth 
133437da2899SCharles.Forsyth 	p = r.min;
133537da2899SCharles.Forsyth 	dx = Dx(r) - size.x;
133637da2899SCharles.Forsyth 	dy = Dy(r) - size.y;
133737da2899SCharles.Forsyth 	if((anchor & (Tknorth|Tksouth)) == 0)
133837da2899SCharles.Forsyth 		p.y += dy/2;
13390db9190eSforsyth 	else if(anchor & Tksouth)
134037da2899SCharles.Forsyth 		p.y += dy;
134137da2899SCharles.Forsyth 
134237da2899SCharles.Forsyth 	if((anchor & (Tkeast|Tkwest)) == 0)
134337da2899SCharles.Forsyth 		p.x += dx/2;
13440db9190eSforsyth 	else if(anchor & Tkeast)
134537da2899SCharles.Forsyth 		p.x += dx;
134637da2899SCharles.Forsyth 	return p;
134737da2899SCharles.Forsyth }
134837da2899SCharles.Forsyth 
134937da2899SCharles.Forsyth static char*
tkunits(char c,int * d,TkEnv * e)135037da2899SCharles.Forsyth tkunits(char c, int *d, TkEnv *e)
135137da2899SCharles.Forsyth {
135237da2899SCharles.Forsyth 	switch(c) {
135337da2899SCharles.Forsyth 	default:
135437da2899SCharles.Forsyth 		if(c >= '0' || c <= '9' || c == '.')
135537da2899SCharles.Forsyth 			break;
135637da2899SCharles.Forsyth 		return TkBadvl;
135737da2899SCharles.Forsyth 	case '\0':
135837da2899SCharles.Forsyth 		break;
135937da2899SCharles.Forsyth 	case 'c':		/* Centimeters */
136037da2899SCharles.Forsyth 		*d *= (Tkdpi*100)/254;
136137da2899SCharles.Forsyth 		break;
136237da2899SCharles.Forsyth 	case 'm':		/* Millimeters */
136337da2899SCharles.Forsyth 		*d *= (Tkdpi*10)/254;
136437da2899SCharles.Forsyth 		break;
136537da2899SCharles.Forsyth 	case 'i':		/* Inches */
136637da2899SCharles.Forsyth 		*d *= Tkdpi;
136737da2899SCharles.Forsyth 		break;
136837da2899SCharles.Forsyth 	case 'p':		/* Points */
136937da2899SCharles.Forsyth 		*d = (*d*Tkdpi)/72;
137037da2899SCharles.Forsyth 		break;
137137da2899SCharles.Forsyth 	case 'w':		/* Character width */
137237da2899SCharles.Forsyth 		if(e == nil)
137337da2899SCharles.Forsyth 			return TkBadvl;
137437da2899SCharles.Forsyth 		*d = *d * e->wzero;
137537da2899SCharles.Forsyth 		break;
137637da2899SCharles.Forsyth 	case 'h':		/* Character height */
137737da2899SCharles.Forsyth 		if(e == nil)
137837da2899SCharles.Forsyth 			return TkBadvl;
137937da2899SCharles.Forsyth 		*d = *d * e->font->height;
138037da2899SCharles.Forsyth 		break;
138137da2899SCharles.Forsyth 	}
138237da2899SCharles.Forsyth 	return nil;
138337da2899SCharles.Forsyth }
138437da2899SCharles.Forsyth 
138537da2899SCharles.Forsyth int
TKF2I(int f)138637da2899SCharles.Forsyth TKF2I(int f)
138737da2899SCharles.Forsyth {
138837da2899SCharles.Forsyth 	if (f >= 0)
138937da2899SCharles.Forsyth 		return (f + Tkfpscalar/2) / Tkfpscalar;
139037da2899SCharles.Forsyth 	return (f - Tkfpscalar/2) / Tkfpscalar;
139137da2899SCharles.Forsyth }
139237da2899SCharles.Forsyth 
139337da2899SCharles.Forsyth /*
139437da2899SCharles.Forsyth  * Parse a floating point number into a decimal fixed point representation
139537da2899SCharles.Forsyth  */
139637da2899SCharles.Forsyth char*
tkfrac(char ** arg,int * f,TkEnv * env)139737da2899SCharles.Forsyth tkfrac(char **arg, int *f, TkEnv *env)
139837da2899SCharles.Forsyth {
139937da2899SCharles.Forsyth 	int c, minus, i, fscale, seendigit;
140037da2899SCharles.Forsyth 	char *p, *e;
140137da2899SCharles.Forsyth 
140237da2899SCharles.Forsyth 	seendigit = 0;
140337da2899SCharles.Forsyth 
140437da2899SCharles.Forsyth 	p = *arg;
140537da2899SCharles.Forsyth 	p = tkskip(p, " \t");
140637da2899SCharles.Forsyth 
140737da2899SCharles.Forsyth 	minus = 0;
140837da2899SCharles.Forsyth 	if(*p == '-') {
140937da2899SCharles.Forsyth 		minus = 1;
141037da2899SCharles.Forsyth 		p++;
141137da2899SCharles.Forsyth 	}
141237da2899SCharles.Forsyth 	i = 0;
141337da2899SCharles.Forsyth 	while(*p) {
141437da2899SCharles.Forsyth 		c = *p;
141537da2899SCharles.Forsyth 		if(c == '.')
141637da2899SCharles.Forsyth 			break;
141737da2899SCharles.Forsyth 		if(c < '0' || c > '9')
141837da2899SCharles.Forsyth 			break;
141937da2899SCharles.Forsyth 		i = i*10 + (c - '0');
142037da2899SCharles.Forsyth 		seendigit = 1;
142137da2899SCharles.Forsyth 		p++;
142237da2899SCharles.Forsyth 	}
142337da2899SCharles.Forsyth 	i *= Tkfpscalar;
142437da2899SCharles.Forsyth 	if(*p == '.')
142537da2899SCharles.Forsyth 		p++;
142637da2899SCharles.Forsyth 	fscale = Tkfpscalar;
142737da2899SCharles.Forsyth 	while(*p && *p >= '0' && *p <= '9') {
142837da2899SCharles.Forsyth 		fscale /= 10;
142937da2899SCharles.Forsyth 		i += fscale * (*p++ - '0');
143037da2899SCharles.Forsyth 		seendigit = 1;
143137da2899SCharles.Forsyth 	}
143237da2899SCharles.Forsyth 
143337da2899SCharles.Forsyth 	if(minus)
143437da2899SCharles.Forsyth 		i = -i;
143537da2899SCharles.Forsyth 
143637da2899SCharles.Forsyth 	if(!seendigit)
143737da2899SCharles.Forsyth 		return TkBadvl;
143837da2899SCharles.Forsyth 	e = tkunits(*p, &i, env);
143937da2899SCharles.Forsyth 	if (e != nil)
144037da2899SCharles.Forsyth 		return e;
144137da2899SCharles.Forsyth 	while (*p && *p != ' ' && *p != '\t')
144237da2899SCharles.Forsyth 		p++;
144337da2899SCharles.Forsyth 	*arg = p;
144437da2899SCharles.Forsyth 	*f = i;
144537da2899SCharles.Forsyth 	return nil;
144637da2899SCharles.Forsyth }
144737da2899SCharles.Forsyth 
144837da2899SCharles.Forsyth char*
tkfracword(TkTop * t,char ** arg,int * f,TkEnv * env)144937da2899SCharles.Forsyth tkfracword(TkTop *t, char **arg, int *f, TkEnv *env)
145037da2899SCharles.Forsyth {
145137da2899SCharles.Forsyth 	char *p;
145237da2899SCharles.Forsyth 	char buf[Tkminitem];
145337da2899SCharles.Forsyth 
145437da2899SCharles.Forsyth 	*arg = tkword(t, *arg, buf, buf+sizeof(buf), nil);
145537da2899SCharles.Forsyth 	p = buf;
145637da2899SCharles.Forsyth 	return tkfrac(&p, f, env);
145737da2899SCharles.Forsyth }
145837da2899SCharles.Forsyth 
145937da2899SCharles.Forsyth char*
tkfprint(char * v,int frac)146037da2899SCharles.Forsyth tkfprint(char *v, int frac)
146137da2899SCharles.Forsyth {
146237da2899SCharles.Forsyth 	int fscale;
146337da2899SCharles.Forsyth 
146437da2899SCharles.Forsyth 	if(frac < 0) {
146537da2899SCharles.Forsyth 		*v++ = '-';
146637da2899SCharles.Forsyth 		frac = -frac;
146737da2899SCharles.Forsyth 	}
146837da2899SCharles.Forsyth 	v += sprint(v, "%d", frac/Tkfpscalar);
146937da2899SCharles.Forsyth 	frac = frac%Tkfpscalar;
147037da2899SCharles.Forsyth 	if(frac != 0)
147137da2899SCharles.Forsyth 		*v++ = '.';
147237da2899SCharles.Forsyth 	fscale = Tkfpscalar/10;
147337da2899SCharles.Forsyth 	while(frac) {
147437da2899SCharles.Forsyth 		*v++ = '0' + frac/fscale;
147537da2899SCharles.Forsyth 		frac %= fscale;
147637da2899SCharles.Forsyth 		fscale /= 10;
147737da2899SCharles.Forsyth 	}
147837da2899SCharles.Forsyth 	*v = '\0';
147937da2899SCharles.Forsyth 	return v;
148037da2899SCharles.Forsyth }
148137da2899SCharles.Forsyth 
148237da2899SCharles.Forsyth char*
tkvalue(char ** val,char * fmt,...)148337da2899SCharles.Forsyth tkvalue(char **val, char *fmt, ...)
148437da2899SCharles.Forsyth {
148537da2899SCharles.Forsyth 	va_list arg;
148637da2899SCharles.Forsyth 	Fmt fmtx;
148737da2899SCharles.Forsyth 
148837da2899SCharles.Forsyth 	if(val == nil)
148937da2899SCharles.Forsyth 		return nil;
149037da2899SCharles.Forsyth 
149137da2899SCharles.Forsyth 	fmtstrinit(&fmtx);
149237da2899SCharles.Forsyth 	if(*val != nil)
149337da2899SCharles.Forsyth 		if(fmtprint(&fmtx, "%s", *val) < 0)
149437da2899SCharles.Forsyth 			return TkNomem;
149537da2899SCharles.Forsyth 	va_start(arg, fmt);
149637da2899SCharles.Forsyth 	fmtvprint(&fmtx, fmt, arg);
149737da2899SCharles.Forsyth 	va_end(arg);
149837da2899SCharles.Forsyth 	free(*val);
149937da2899SCharles.Forsyth 	*val = fmtstrflush(&fmtx);
150037da2899SCharles.Forsyth 	if(*val == nil)
150137da2899SCharles.Forsyth 		return TkNomem;
150237da2899SCharles.Forsyth 	return nil;
150337da2899SCharles.Forsyth }
150437da2899SCharles.Forsyth 
150537da2899SCharles.Forsyth static char*
tkwidgetcmd(TkTop * t,Tk * tk,char * arg,char ** val)150637da2899SCharles.Forsyth tkwidgetcmd(TkTop *t, Tk *tk, char *arg, char **val)
150737da2899SCharles.Forsyth {
150837da2899SCharles.Forsyth 	TkMethod *cm;
150937da2899SCharles.Forsyth 	TkCmdtab *ct;
151037da2899SCharles.Forsyth 	int bot, top, new, r;
151137da2899SCharles.Forsyth 	char *e, *buf;
151237da2899SCharles.Forsyth 
151337da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
151437da2899SCharles.Forsyth 	if(buf == nil)
151537da2899SCharles.Forsyth 		return TkNomem;
151637da2899SCharles.Forsyth 
151737da2899SCharles.Forsyth 	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
151837da2899SCharles.Forsyth 	if(val != nil)
151937da2899SCharles.Forsyth 		*val = nil;
152037da2899SCharles.Forsyth 
152137da2899SCharles.Forsyth 	cm = tkmethod[tk->type];
152237da2899SCharles.Forsyth 
152337da2899SCharles.Forsyth 	e = TkBadcm;
152437da2899SCharles.Forsyth 	bot = 0;
152537da2899SCharles.Forsyth 	top = cm->ncmd - 1;
152637da2899SCharles.Forsyth 
152737da2899SCharles.Forsyth 	while(bot <= top) {
152837da2899SCharles.Forsyth 		new = (bot + top)/2;
152937da2899SCharles.Forsyth 		ct = &cm->cmd[new];
153037da2899SCharles.Forsyth 		r = strcmp(ct->name, buf);
153137da2899SCharles.Forsyth 		if(r == 0) {
153237da2899SCharles.Forsyth 			e = ct->fn(tk, arg, val);
153337da2899SCharles.Forsyth 			break;
153437da2899SCharles.Forsyth 		}
153537da2899SCharles.Forsyth 		if(r < 0)
153637da2899SCharles.Forsyth 			bot = new + 1;
153737da2899SCharles.Forsyth 		else
153837da2899SCharles.Forsyth 			top = new - 1;
153937da2899SCharles.Forsyth 	}
154037da2899SCharles.Forsyth 	free(buf);
154137da2899SCharles.Forsyth 	tkdirty(tk);
154237da2899SCharles.Forsyth 	return e;
154337da2899SCharles.Forsyth }
154437da2899SCharles.Forsyth 
154537da2899SCharles.Forsyth Rectangle
tkrect(Tk * tk,int withborder)154637da2899SCharles.Forsyth tkrect(Tk *tk, int withborder)
154737da2899SCharles.Forsyth {
154837da2899SCharles.Forsyth 	Rectangle r;
154937da2899SCharles.Forsyth 	int bd;
15500b978350Sforsyth 
155137da2899SCharles.Forsyth 	bd = withborder? tk->borderwidth: 0;
155237da2899SCharles.Forsyth 	r.min.x = -bd;
155337da2899SCharles.Forsyth 	r.min.y = -bd;
155437da2899SCharles.Forsyth 	r.max.x = tk->act.width + bd;
155537da2899SCharles.Forsyth 	r.max.y = tk->act.height + bd;
155637da2899SCharles.Forsyth 	return r;
155737da2899SCharles.Forsyth }
155837da2899SCharles.Forsyth 
155937da2899SCharles.Forsyth void
tkdirty(Tk * tk)156037da2899SCharles.Forsyth tkdirty(Tk *tk)
156137da2899SCharles.Forsyth {
156237da2899SCharles.Forsyth 	Tk *sub;
156337da2899SCharles.Forsyth 	Point rel;
156437da2899SCharles.Forsyth 	Rectangle dirty;
156537da2899SCharles.Forsyth 	int isdirty, transparent;
156637da2899SCharles.Forsyth 
156737da2899SCharles.Forsyth 	/*
156837da2899SCharles.Forsyth 	 * mark as dirty all views underneath a dirty transparent widget
156937da2899SCharles.Forsyth 	 *	down to the first opaque widget.
157037da2899SCharles.Forsyth 	 * inform parents about any dirtiness.
157137da2899SCharles.Forsyth 
157237da2899SCharles.Forsyth 	 * XXX as Tksubsub never gets reset, testing against Tksubsub doesn't *exactly* test
157337da2899SCharles.Forsyth 	 * whether we're in a canvas/text widget, but merely
157437da2899SCharles.Forsyth 	 * whether it has ever been. Tksubsub should probably be reset on unpack.
157537da2899SCharles.Forsyth 	 */
157637da2899SCharles.Forsyth 	isdirty = Dx(tk->dirty) > 0;
157737da2899SCharles.Forsyth 	transparent = tk->flag & Tktransparent;
157837da2899SCharles.Forsyth 	sub = tk;
157937da2899SCharles.Forsyth 	while (isdirty && ((tk->flag&Tksubsub) || transparent)) {
158037da2899SCharles.Forsyth 		if (tk->master != nil) {
158137da2899SCharles.Forsyth 			if (transparent) {
158237da2899SCharles.Forsyth 				rel.x = tk->act.x + tk->borderwidth;
158337da2899SCharles.Forsyth 				rel.y = tk->act.y + tk->borderwidth;
158437da2899SCharles.Forsyth 				dirty = rectaddpt(sub->dirty, rel);
158537da2899SCharles.Forsyth 				sub = tk->master;
158637da2899SCharles.Forsyth 				combinerect(&sub->dirty, dirty);
158737da2899SCharles.Forsyth 				transparent = sub->flag & Tktransparent;
158837da2899SCharles.Forsyth 			}
158937da2899SCharles.Forsyth 			tk = tk->master;
159037da2899SCharles.Forsyth 		} else if (tk->parent != nil) {
159137da2899SCharles.Forsyth 			tkmethod[tk->parent->type]->dirtychild(sub);
159237da2899SCharles.Forsyth 			tk = sub = tk->parent;
159337da2899SCharles.Forsyth 			isdirty = Dx(sub->dirty) > 0;
159437da2899SCharles.Forsyth 			transparent = sub->flag & Tktransparent;
159537da2899SCharles.Forsyth 		} else
159637da2899SCharles.Forsyth 			break;
159737da2899SCharles.Forsyth 	}
159837da2899SCharles.Forsyth }
159937da2899SCharles.Forsyth 
160037da2899SCharles.Forsyth static int
qcmdcmp(const void * a,const void * b)160137da2899SCharles.Forsyth qcmdcmp(const void *a, const void *b)
160237da2899SCharles.Forsyth {
160337da2899SCharles.Forsyth 	return strcmp(((TkCmdtab*)a)->name, ((TkCmdtab*)b)->name);
160437da2899SCharles.Forsyth }
160537da2899SCharles.Forsyth 
160637da2899SCharles.Forsyth void
tksorttable(void)160737da2899SCharles.Forsyth tksorttable(void)
160837da2899SCharles.Forsyth {
160937da2899SCharles.Forsyth 	int i;
161037da2899SCharles.Forsyth 	TkMethod *c;
161137da2899SCharles.Forsyth 	TkCmdtab *cmd;
161237da2899SCharles.Forsyth 
161337da2899SCharles.Forsyth 	for(i = 0; i < TKwidgets; i++) {
161437da2899SCharles.Forsyth 		c = tkmethod[i];
161537da2899SCharles.Forsyth 		if(c->cmd == nil)
161637da2899SCharles.Forsyth 			continue;
161737da2899SCharles.Forsyth 
161837da2899SCharles.Forsyth 		for(cmd = c->cmd; cmd->name != nil; cmd++)
161937da2899SCharles.Forsyth 			;
162037da2899SCharles.Forsyth 		c->ncmd = cmd - c->cmd;
162137da2899SCharles.Forsyth 
162237da2899SCharles.Forsyth 		qsort(c->cmd, c->ncmd, sizeof(TkCmdtab), qcmdcmp);
162337da2899SCharles.Forsyth 	}
162437da2899SCharles.Forsyth }
162537da2899SCharles.Forsyth 
162637da2899SCharles.Forsyth static char*
tksinglecmd(TkTop * t,char * arg,char ** val)162737da2899SCharles.Forsyth tksinglecmd(TkTop *t, char *arg, char **val)
162837da2899SCharles.Forsyth {
162937da2899SCharles.Forsyth 	Tk *tk;
163037da2899SCharles.Forsyth 	int bot, top, new;
163137da2899SCharles.Forsyth 	char *e, *buf;
163237da2899SCharles.Forsyth 
163337da2899SCharles.Forsyth 	if(t->debug)
163437da2899SCharles.Forsyth 		print("tk: '%s'\n", arg);
163537da2899SCharles.Forsyth 
163637da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
163737da2899SCharles.Forsyth 	if(buf == nil)
163837da2899SCharles.Forsyth 		return TkNomem;
163937da2899SCharles.Forsyth 
164037da2899SCharles.Forsyth 	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
164137da2899SCharles.Forsyth 	switch(buf[0]) {
164237da2899SCharles.Forsyth 	case '\0':
164337da2899SCharles.Forsyth 		free(buf);
164437da2899SCharles.Forsyth 		return nil;
164537da2899SCharles.Forsyth 	case '.':
164637da2899SCharles.Forsyth 		tk = tklook(t, buf, 0);
164737da2899SCharles.Forsyth 		if(tk == nil){
164837da2899SCharles.Forsyth 			tkerr(t, buf);
164937da2899SCharles.Forsyth 			free(buf);
165037da2899SCharles.Forsyth 			return TkBadwp;
165137da2899SCharles.Forsyth 		}
165237da2899SCharles.Forsyth 		e = tkwidgetcmd(t, tk, arg, val);
165337da2899SCharles.Forsyth 		free(buf);
165437da2899SCharles.Forsyth 		return e;
165537da2899SCharles.Forsyth 	}
165637da2899SCharles.Forsyth 
165737da2899SCharles.Forsyth 	bot = 0;
165837da2899SCharles.Forsyth 	top = nelem(cmdmain) - 1;
165937da2899SCharles.Forsyth 	e = TkBadcm;
166037da2899SCharles.Forsyth 	while(bot <= top) {
166137da2899SCharles.Forsyth 		int rc;
166237da2899SCharles.Forsyth 		new = (bot + top)/2;
166337da2899SCharles.Forsyth 		rc = strcmp(cmdmain[new].name, buf);
166437da2899SCharles.Forsyth 		if(!rc) {
166537da2899SCharles.Forsyth 			e = cmdmain[new].fn(t, arg, val);
166637da2899SCharles.Forsyth 			break;
166737da2899SCharles.Forsyth 		}
166837da2899SCharles.Forsyth 
166937da2899SCharles.Forsyth 		if(rc < 0)
167037da2899SCharles.Forsyth 			bot = new + 1;
167137da2899SCharles.Forsyth 		else
167237da2899SCharles.Forsyth 			top = new - 1;
167337da2899SCharles.Forsyth 	}
167437da2899SCharles.Forsyth 	free(buf);
167537da2899SCharles.Forsyth 	return e;
167637da2899SCharles.Forsyth }
167737da2899SCharles.Forsyth 
167837da2899SCharles.Forsyth static char*
tkmatch(int inc,int dec,char * p)167937da2899SCharles.Forsyth tkmatch(int inc, int dec, char *p)
168037da2899SCharles.Forsyth {
168137da2899SCharles.Forsyth 	int depth, esc, c;
168237da2899SCharles.Forsyth 
168337da2899SCharles.Forsyth 	esc = 0;
168437da2899SCharles.Forsyth 	depth = 1;
168537da2899SCharles.Forsyth 	while(*p) {
168637da2899SCharles.Forsyth 		c = *p;
168737da2899SCharles.Forsyth 		if(esc == 0) {
168837da2899SCharles.Forsyth 			if(c == inc)
168937da2899SCharles.Forsyth 				depth++;
169037da2899SCharles.Forsyth 			if(c == dec)
169137da2899SCharles.Forsyth 				depth--;
169237da2899SCharles.Forsyth 			if(depth == 0)
169337da2899SCharles.Forsyth 				return p;
169437da2899SCharles.Forsyth 		}
169537da2899SCharles.Forsyth 		if(c == '\\' && esc == 0)
169637da2899SCharles.Forsyth 			esc = 1;
169737da2899SCharles.Forsyth 		else
169837da2899SCharles.Forsyth 			esc = 0;
169937da2899SCharles.Forsyth 		p++;
170037da2899SCharles.Forsyth 	}
170137da2899SCharles.Forsyth 	return nil;
170237da2899SCharles.Forsyth }
170337da2899SCharles.Forsyth 
170437da2899SCharles.Forsyth char*
tkexec(TkTop * t,char * arg,char ** val)170537da2899SCharles.Forsyth tkexec(TkTop *t, char *arg, char **val)
170637da2899SCharles.Forsyth {
170737da2899SCharles.Forsyth 	int cmdsz, n;
170837da2899SCharles.Forsyth 	char *p, *cmd, *e, *c;
170937da2899SCharles.Forsyth 
171037da2899SCharles.Forsyth 	if(t->execdepth >= 0 && ++t->execdepth > 128)
171137da2899SCharles.Forsyth 		return TkDepth;
171237da2899SCharles.Forsyth 
171337da2899SCharles.Forsyth 	cmd = nil;
171437da2899SCharles.Forsyth 	cmdsz = 0;
171537da2899SCharles.Forsyth 
171637da2899SCharles.Forsyth 	p = arg;
171737da2899SCharles.Forsyth 	for(;;) {
171837da2899SCharles.Forsyth 		switch(*p++) {
171937da2899SCharles.Forsyth 		case '[':
172037da2899SCharles.Forsyth 			p = tkmatch('[', ']', p);
172137da2899SCharles.Forsyth 			if(p == nil){
172237da2899SCharles.Forsyth 				free(cmd);
172337da2899SCharles.Forsyth 				return TkSyntx;
172437da2899SCharles.Forsyth 			}
172537da2899SCharles.Forsyth 			break;
172637da2899SCharles.Forsyth 		case '{':
172737da2899SCharles.Forsyth 			p = tkmatch('{', '}', p);
172837da2899SCharles.Forsyth 			if(p == nil){
172937da2899SCharles.Forsyth 				free(cmd);
173037da2899SCharles.Forsyth 				return TkSyntx;
173137da2899SCharles.Forsyth 			}
173237da2899SCharles.Forsyth 			break;
173337da2899SCharles.Forsyth 		case ';':
173437da2899SCharles.Forsyth 			n = p - arg - 1;
173537da2899SCharles.Forsyth 			if(cmdsz < n)
173637da2899SCharles.Forsyth 				cmdsz = n;
173737da2899SCharles.Forsyth 			c = realloc(cmd, cmdsz+1);
173837da2899SCharles.Forsyth 			if(c == nil){
173937da2899SCharles.Forsyth 				free(cmd);
174037da2899SCharles.Forsyth 				return TkNomem;
174137da2899SCharles.Forsyth 			}
174237da2899SCharles.Forsyth 			cmd = c;
174337da2899SCharles.Forsyth 			memmove(cmd, arg, n);
174437da2899SCharles.Forsyth 			cmd[n] = '\0';
174537da2899SCharles.Forsyth 			e = tksinglecmd(t, cmd, nil);
174637da2899SCharles.Forsyth 			if(e != nil) {
174737da2899SCharles.Forsyth 				t->err = e;
174837da2899SCharles.Forsyth 				strncpy(t->errcmd, cmd, sizeof(t->errcmd));
174937da2899SCharles.Forsyth 				t->errcmd[sizeof(t->errcmd)-1] = '\0';
175037da2899SCharles.Forsyth 				free(cmd);
175137da2899SCharles.Forsyth 				return e;
175237da2899SCharles.Forsyth 			}
175337da2899SCharles.Forsyth 			arg = p;
175437da2899SCharles.Forsyth 			break;
175537da2899SCharles.Forsyth 		case '\0':
175637da2899SCharles.Forsyth 		case '\'':
175737da2899SCharles.Forsyth 			free(cmd);
175837da2899SCharles.Forsyth 			e = tksinglecmd(t, arg, val);
175937da2899SCharles.Forsyth 			if(e != nil) {
176037da2899SCharles.Forsyth 				t->err = e;
176137da2899SCharles.Forsyth 				strncpy(t->errcmd, arg, sizeof(t->errcmd));
176237da2899SCharles.Forsyth 				t->errcmd[sizeof(t->errcmd)-1] = '\0';
176337da2899SCharles.Forsyth 			}
176437da2899SCharles.Forsyth 			return e;
176537da2899SCharles.Forsyth 		}
176637da2899SCharles.Forsyth 	}
176737da2899SCharles.Forsyth }
176837da2899SCharles.Forsyth 
176937da2899SCharles.Forsyth static struct {
177037da2899SCharles.Forsyth 	char *name;
177137da2899SCharles.Forsyth 	int mask;
177237da2899SCharles.Forsyth } events[] = {
177337da2899SCharles.Forsyth 	"Button1P",	TkButton1P,
177437da2899SCharles.Forsyth 	"Button1R",	TkButton1R,
177537da2899SCharles.Forsyth 	"Button2P",	TkButton2P,
177637da2899SCharles.Forsyth 	"Button2R",	TkButton2R,
177737da2899SCharles.Forsyth 	"Button3P",	TkButton3P,
177837da2899SCharles.Forsyth 	"Button3R",	TkButton3R,
177937da2899SCharles.Forsyth 	"Button4P",	TkButton4P,
178037da2899SCharles.Forsyth 	"Button4R",	TkButton4R,
178137da2899SCharles.Forsyth 	"Button5P",	TkButton5P,
178237da2899SCharles.Forsyth 	"Button5R",	TkButton5R,
178337da2899SCharles.Forsyth 	"Button6P",	TkButton6P,
178437da2899SCharles.Forsyth 	"Button6R",	TkButton6R,
178537da2899SCharles.Forsyth 	"Extn1",		TkExtn1,
178637da2899SCharles.Forsyth 	"Extn2",		TkExtn2,
178737da2899SCharles.Forsyth 	"Takefocus",	TkTakefocus,
178837da2899SCharles.Forsyth 	"Destroy",		TkDestroy,
178937da2899SCharles.Forsyth 	"Enter",		TkEnter,
179037da2899SCharles.Forsyth 	"Leave",		TkLeave,
179137da2899SCharles.Forsyth 	"Motion",		TkMotion,
179237da2899SCharles.Forsyth 	"Map",		TkMap,
179337da2899SCharles.Forsyth 	"Unmap",		TkUnmap,
179437da2899SCharles.Forsyth 	"Key",		TkKey,
179537da2899SCharles.Forsyth 	"Focusin",		TkFocusin,
179637da2899SCharles.Forsyth 	"Focusout",	TkFocusout,
179737da2899SCharles.Forsyth 	"Configure",	TkConfigure,
179837da2899SCharles.Forsyth 	"Double",		TkDouble,
179937da2899SCharles.Forsyth 	0
180037da2899SCharles.Forsyth };
180137da2899SCharles.Forsyth 
180237da2899SCharles.Forsyth int
tkeventfmt(Fmt * f)180337da2899SCharles.Forsyth tkeventfmt(Fmt *f)
180437da2899SCharles.Forsyth {
180537da2899SCharles.Forsyth 	int k, i, d;
180637da2899SCharles.Forsyth 	int e;
180737da2899SCharles.Forsyth 
180837da2899SCharles.Forsyth 	e = va_arg(f->args, int);
180937da2899SCharles.Forsyth 
181037da2899SCharles.Forsyth 	if ((f->flags & FmtSharp) && e == TkMotion)
181137da2899SCharles.Forsyth 		return 0;
181237da2899SCharles.Forsyth 	fmtprint(f, "<");
181337da2899SCharles.Forsyth 	k = -1;
181437da2899SCharles.Forsyth 	if (e & TkKey) {
181537da2899SCharles.Forsyth 		k = e & 0xffff;
181637da2899SCharles.Forsyth 		e &= ~0xffff;
181737da2899SCharles.Forsyth 	}
181837da2899SCharles.Forsyth 	d = 0;
181937da2899SCharles.Forsyth 	for (i = 0; events[i].name; i++) {
182037da2899SCharles.Forsyth 		if (e & events[i].mask) {
182137da2899SCharles.Forsyth 			if (d++)
182237da2899SCharles.Forsyth 				fmtprint(f, "|");
182337da2899SCharles.Forsyth 			fmtprint(f, "%s", events[i].name);
182437da2899SCharles.Forsyth 		}
182537da2899SCharles.Forsyth 	}
182637da2899SCharles.Forsyth 	if (k != -1) {
182737da2899SCharles.Forsyth 		fmtprint(f, "[%c]", k);
182837da2899SCharles.Forsyth 	} else if (e == 0)
182937da2899SCharles.Forsyth 		fmtprint(f, "Noevent");
183037da2899SCharles.Forsyth 	fmtprint(f, ">");
183137da2899SCharles.Forsyth 	return 0;
183237da2899SCharles.Forsyth }
183337da2899SCharles.Forsyth 
183437da2899SCharles.Forsyth void
tkerr(TkTop * t,char * e)183537da2899SCharles.Forsyth tkerr(TkTop *t, char *e)
183637da2899SCharles.Forsyth {
183737da2899SCharles.Forsyth 	if(t != nil && e != nil){
183837da2899SCharles.Forsyth 		strncpy(t->errx, e, sizeof(t->errx));
183937da2899SCharles.Forsyth 		t->errx[sizeof(t->errx)-1] = '\0';
184037da2899SCharles.Forsyth 	}
184137da2899SCharles.Forsyth }
184237da2899SCharles.Forsyth 
184337da2899SCharles.Forsyth char*
tkerrstr(TkTop * t,char * e)184437da2899SCharles.Forsyth tkerrstr(TkTop *t, char *e)
184537da2899SCharles.Forsyth {
184637da2899SCharles.Forsyth 	char *s = malloc(strlen(e)+1+strlen(t->errx)+1);
184737da2899SCharles.Forsyth 
184837da2899SCharles.Forsyth 	if(s == nil)
184937da2899SCharles.Forsyth 		return nil;
185037da2899SCharles.Forsyth 	strcpy(s, e);
185137da2899SCharles.Forsyth 	if(*e == '!'){
185237da2899SCharles.Forsyth 		strcat(s, " ");
185337da2899SCharles.Forsyth 		strcat(s, t->errx);
185437da2899SCharles.Forsyth 	}
185537da2899SCharles.Forsyth 	t->errx[0] = '\0';
185637da2899SCharles.Forsyth 	return s;
185737da2899SCharles.Forsyth }
185837da2899SCharles.Forsyth 
185937da2899SCharles.Forsyth char*
tksetmgrab(TkTop * t,Tk * tk)186037da2899SCharles.Forsyth tksetmgrab(TkTop *t, Tk *tk)
186137da2899SCharles.Forsyth {
186237da2899SCharles.Forsyth 	Tk *omgrab;
186337da2899SCharles.Forsyth 	TkCtxt *c;
186437da2899SCharles.Forsyth 	c = t->ctxt;
186537da2899SCharles.Forsyth 	if (tk == nil) {
186637da2899SCharles.Forsyth 		omgrab = c->mgrab;
186737da2899SCharles.Forsyth 		c->mgrab = nil;
186837da2899SCharles.Forsyth 		/*
186937da2899SCharles.Forsyth 		 * don't enterleave if grab reset would cause no leave event
187037da2899SCharles.Forsyth 		 */
187137da2899SCharles.Forsyth 		if (!(omgrab != nil && (omgrab->flag & Tknograb) &&
187237da2899SCharles.Forsyth 				c->entered != nil && (c->entered->flag & Tknograb)))
187337da2899SCharles.Forsyth 			tkenterleave(t);
187437da2899SCharles.Forsyth 	} else {
187537da2899SCharles.Forsyth 		if (c->focused && c->mfocus != nil && c->mfocus->env->top != tk->env->top)
187637da2899SCharles.Forsyth 			return "!grab already taken on another toplevel";
187737da2899SCharles.Forsyth 		c->mgrab = tk;
187837da2899SCharles.Forsyth 		if (tk->flag & Tknograb) {
187937da2899SCharles.Forsyth 			if (c->focused) {
188037da2899SCharles.Forsyth 				c->focused = 0;
188137da2899SCharles.Forsyth 				c->mfocus = nil;
188237da2899SCharles.Forsyth 			}
188337da2899SCharles.Forsyth 		} else if (c->focused || c->mstate.b != 0) {
188437da2899SCharles.Forsyth 			c->focused = 1;
188537da2899SCharles.Forsyth 			c->mfocus = tk;
188637da2899SCharles.Forsyth 		}
188737da2899SCharles.Forsyth //print("setmgrab(%s) focus now %s\n", tkname(tk), tkname(c->mfocus));
188837da2899SCharles.Forsyth 		tkenterleave(t);
188937da2899SCharles.Forsyth 	}
189037da2899SCharles.Forsyth 	return nil;
189137da2899SCharles.Forsyth }
189237da2899SCharles.Forsyth 
189337da2899SCharles.Forsyth int
tkinsidepoly(Point * poly,int np,int winding,Point p)189437da2899SCharles.Forsyth tkinsidepoly(Point *poly, int np, int winding, Point p)
189537da2899SCharles.Forsyth {
189637da2899SCharles.Forsyth 	Point pi, pj;
189737da2899SCharles.Forsyth 	int i, j, hit;
189837da2899SCharles.Forsyth 
189937da2899SCharles.Forsyth 	hit = 0;
190037da2899SCharles.Forsyth 	j = np - 1;
190137da2899SCharles.Forsyth 	for(i = 0; i < np; j = i++) {
190237da2899SCharles.Forsyth 		pi = poly[i];
190337da2899SCharles.Forsyth 		pj = poly[j];
190437da2899SCharles.Forsyth 		if((pi.y <= p.y && p.y < pj.y || pj.y <= p.y && p.y < pi.y) &&
190537da2899SCharles.Forsyth 				p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) {
190637da2899SCharles.Forsyth 			if(winding == 1 || pi.y > p.y)
190737da2899SCharles.Forsyth 				hit++;
190837da2899SCharles.Forsyth 			else
190937da2899SCharles.Forsyth 				hit--;
191037da2899SCharles.Forsyth 		}
191137da2899SCharles.Forsyth 	}
191237da2899SCharles.Forsyth 	return (hit & winding) != 0;
191337da2899SCharles.Forsyth }
191437da2899SCharles.Forsyth 
191537da2899SCharles.Forsyth int
tklinehit(Point * a,int np,int w,Point p)191637da2899SCharles.Forsyth tklinehit(Point *a, int np, int w, Point p)
191737da2899SCharles.Forsyth {
191837da2899SCharles.Forsyth 	Point *b;
191937da2899SCharles.Forsyth 	int z, nx, ny, nrm;
19200b978350Sforsyth 
192137da2899SCharles.Forsyth 	while(np-- > 1) {
192237da2899SCharles.Forsyth 		b = a+1;
192337da2899SCharles.Forsyth 		nx = a->y - b->y;
192437da2899SCharles.Forsyth 		ny = b->x - a->x;
192537da2899SCharles.Forsyth 		nrm = (nx < 0? -nx : nx) + (ny < 0? -ny : ny);
192637da2899SCharles.Forsyth 		if(nrm)
192737da2899SCharles.Forsyth 			z = (p.x-b->x)*nx/nrm + (p.y-b->y)*ny/nrm;
192837da2899SCharles.Forsyth 		else
192937da2899SCharles.Forsyth 			z = (p.x-b->x) + (p.y-b->y);
193037da2899SCharles.Forsyth 		if(z < 0)
193137da2899SCharles.Forsyth 			z = -z;
193237da2899SCharles.Forsyth 		if(z < w)
193337da2899SCharles.Forsyth 			return 1;
193437da2899SCharles.Forsyth 		a++;
193537da2899SCharles.Forsyth 	}
193637da2899SCharles.Forsyth 	return 0;
193737da2899SCharles.Forsyth }
193837da2899SCharles.Forsyth 
193937da2899SCharles.Forsyth int
tkiswordchar(int c)194037da2899SCharles.Forsyth tkiswordchar(int c)
194137da2899SCharles.Forsyth {
194237da2899SCharles.Forsyth 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c >= 0xA0;
194337da2899SCharles.Forsyth }
194437da2899SCharles.Forsyth 
194537da2899SCharles.Forsyth int
tkhaskeyfocus(Tk * tk)194637da2899SCharles.Forsyth tkhaskeyfocus(Tk *tk)
194737da2899SCharles.Forsyth {
194837da2899SCharles.Forsyth 	if (tk == nil || tk->env->top->focused == 0)
194937da2899SCharles.Forsyth 		return 0;
195037da2899SCharles.Forsyth 	return tk == tk->env->top->ctxt->tkkeygrab;
195137da2899SCharles.Forsyth }
195237da2899SCharles.Forsyth 
195337da2899SCharles.Forsyth static int
rptactive(void * v)195437da2899SCharles.Forsyth rptactive(void *v)
195537da2899SCharles.Forsyth {
195637da2899SCharles.Forsyth 	int id = (int)v;
195737da2899SCharles.Forsyth 	if (id == rptid)
195837da2899SCharles.Forsyth 		return 1;
195937da2899SCharles.Forsyth 	return 0;
196037da2899SCharles.Forsyth }
196137da2899SCharles.Forsyth 
196237da2899SCharles.Forsyth static int
ckrpt(void * v,int interval)196337da2899SCharles.Forsyth ckrpt(void *v, int interval)
196437da2899SCharles.Forsyth {
196537da2899SCharles.Forsyth 	int id = (int)v;
196637da2899SCharles.Forsyth 	if (id != rptid)
196737da2899SCharles.Forsyth 		return -1;
196837da2899SCharles.Forsyth 	if (interval < rptto)
196937da2899SCharles.Forsyth 		return 0;
197037da2899SCharles.Forsyth 	return 1;
197137da2899SCharles.Forsyth }
197237da2899SCharles.Forsyth 
197337da2899SCharles.Forsyth static void
dorpt(void * v)197437da2899SCharles.Forsyth dorpt(void *v)
197537da2899SCharles.Forsyth {
197637da2899SCharles.Forsyth 	int id = (int)v;
197737da2899SCharles.Forsyth 
197837da2899SCharles.Forsyth 	if (id == rptid) {
197937da2899SCharles.Forsyth 		rptto = rptint;
198037da2899SCharles.Forsyth 		(*rptcb)(rptw, rptnote, 0);
198137da2899SCharles.Forsyth 		if (rptint <= 0) {
198237da2899SCharles.Forsyth 			rptid++;
198337da2899SCharles.Forsyth 			rptw = nil;
198437da2899SCharles.Forsyth 		}
198537da2899SCharles.Forsyth 	}
198637da2899SCharles.Forsyth }
198737da2899SCharles.Forsyth 
198837da2899SCharles.Forsyth void
tkcancelrepeat(Tk * tk)198937da2899SCharles.Forsyth tkcancelrepeat(Tk *tk)
199037da2899SCharles.Forsyth {
199137da2899SCharles.Forsyth 	if (tk == rptw) {
199237da2899SCharles.Forsyth 		rptid++;
199337da2899SCharles.Forsyth 		rptw = nil;
199437da2899SCharles.Forsyth 	}
199537da2899SCharles.Forsyth }
199637da2899SCharles.Forsyth 
199737da2899SCharles.Forsyth void
tkrepeat(Tk * tk,void (* callback)(Tk *,void *,int),void * note,int pause,int interval)199837da2899SCharles.Forsyth tkrepeat(Tk *tk, void (*callback)(Tk*, void*, int), void *note, int pause, int interval)
199937da2899SCharles.Forsyth {
200037da2899SCharles.Forsyth 	rptid++;
200137da2899SCharles.Forsyth 	if (tk != rptw && rptw != nil)
200237da2899SCharles.Forsyth 		/* existing callback being replaced- report to owner */
200337da2899SCharles.Forsyth 		(*rptcb)(rptw, rptnote, 1);
200437da2899SCharles.Forsyth 	rptw = tk;
200537da2899SCharles.Forsyth 	if (tk == nil || callback == nil)
200637da2899SCharles.Forsyth 		return;
200737da2899SCharles.Forsyth 	rptnote = note;
200837da2899SCharles.Forsyth 	rptcb = callback;
200937da2899SCharles.Forsyth 	rptto = pause;
201037da2899SCharles.Forsyth 	rptint = interval;
201137da2899SCharles.Forsyth 	if (!autorpt)
201237da2899SCharles.Forsyth 		autorpt = rptproc("autorepeat", TkRptclick, (void*)rptid, rptactive, ckrpt, dorpt);
201337da2899SCharles.Forsyth 	else
201437da2899SCharles.Forsyth 		rptwakeup((void*)rptid, autorpt);
201537da2899SCharles.Forsyth }
201637da2899SCharles.Forsyth 
201737da2899SCharles.Forsyth static int
blinkactive(void * v)201837da2899SCharles.Forsyth blinkactive(void *v)
201937da2899SCharles.Forsyth {
202037da2899SCharles.Forsyth 	USED(v);
202137da2899SCharles.Forsyth 	return blinkw != nil;
202237da2899SCharles.Forsyth }
202337da2899SCharles.Forsyth 
202437da2899SCharles.Forsyth static int
ckblink(void * v,int interval)202537da2899SCharles.Forsyth ckblink(void *v, int interval)
202637da2899SCharles.Forsyth {
202737da2899SCharles.Forsyth 	USED(v);
202837da2899SCharles.Forsyth 	USED(interval);
202937da2899SCharles.Forsyth 
203037da2899SCharles.Forsyth 	if (blinkw == nil)
203137da2899SCharles.Forsyth 		return -1;
203237da2899SCharles.Forsyth 	if (blinkignore) {
203337da2899SCharles.Forsyth 		blinkignore = 0;
203437da2899SCharles.Forsyth 		return 0;
203537da2899SCharles.Forsyth 	}
203637da2899SCharles.Forsyth 	return 1;
203737da2899SCharles.Forsyth }
203837da2899SCharles.Forsyth 
203937da2899SCharles.Forsyth static void
doblink(void * v)204037da2899SCharles.Forsyth doblink(void *v)
204137da2899SCharles.Forsyth {
204237da2899SCharles.Forsyth 	USED(v);
204337da2899SCharles.Forsyth 
204437da2899SCharles.Forsyth 	if (blinkw == nil)
204537da2899SCharles.Forsyth 		return;
204637da2899SCharles.Forsyth 	blinkcb(blinkw, blinkon++ & 1);
204737da2899SCharles.Forsyth 	tkupdate(blinkw->env->top);
204837da2899SCharles.Forsyth }
204937da2899SCharles.Forsyth 
205037da2899SCharles.Forsyth void
tkblinkreset(Tk * tk)205137da2899SCharles.Forsyth tkblinkreset(Tk *tk)
205237da2899SCharles.Forsyth {
205337da2899SCharles.Forsyth 	if (blinkw == tk) {
205437da2899SCharles.Forsyth 		blinkignore = 1;
205537da2899SCharles.Forsyth 		blinkon = 0;
205637da2899SCharles.Forsyth 	}
205737da2899SCharles.Forsyth }
205837da2899SCharles.Forsyth 
205937da2899SCharles.Forsyth void
tkblink(Tk * tk,void (* callback)(Tk *,int))206037da2899SCharles.Forsyth tkblink(Tk *tk, void (*callback)(Tk*, int))
206137da2899SCharles.Forsyth {
206237da2899SCharles.Forsyth 	if (tk == nil || callback == nil) {
206337da2899SCharles.Forsyth 		blinkw = nil;
206437da2899SCharles.Forsyth 		return;
206537da2899SCharles.Forsyth 	}
206637da2899SCharles.Forsyth 	blinkw = tk;
206737da2899SCharles.Forsyth 	blinkcb = callback;
206837da2899SCharles.Forsyth 	if (!blinkrpt)
206937da2899SCharles.Forsyth 		blinkrpt = rptproc("blinker", TkBlinkinterval, nil, blinkactive, ckblink, doblink);
207037da2899SCharles.Forsyth 	else
207137da2899SCharles.Forsyth 		rptwakeup(nil, blinkrpt);
207237da2899SCharles.Forsyth }
2073*5849851aSforsyth 
2074*5849851aSforsyth /*
2075*5849851aSforsyth  * debugging
2076*5849851aSforsyth  */
2077*5849851aSforsyth void
tkdump(Tk * tk)2078*5849851aSforsyth tkdump(Tk *tk)
2079*5849851aSforsyth {
2080*5849851aSforsyth 	Tk *sl;
2081*5849851aSforsyth 
2082*5849851aSforsyth 	if(tk == nil)
2083*5849851aSforsyth 		return;
2084*5849851aSforsyth 	if((uint)tk->type < TKwidgets)
2085*5849851aSforsyth 		print("%s", tkmethod[tk->type]->name);
2086*5849851aSforsyth 	else
2087*5849851aSforsyth 		print("TYPE#%#ux", tk->type);
2088*5849851aSforsyth 	if(tk->name == nil || (ulong)tk->name < 512)
2089*5849851aSforsyth 		print(" NAME %p", tk->name);
2090*5849851aSforsyth 	else
2091*5849851aSforsyth 		print(" %s", tkname(tk));
2092*5849851aSforsyth 	print(" # tk %#p flag %#ux grid %#p", tk, tk->flag, tk->grid);
2093*5849851aSforsyth 	if(tk->parent != nil)
2094*5849851aSforsyth 		print(" parent [%#p %q]", tk->parent, tkname(tk->parent));
2095*5849851aSforsyth 	if(tk->master != nil)
2096*5849851aSforsyth 		print(" master [%#p %q]", tk->master, tkname(tk->master));
2097*5849851aSforsyth 	if(tk->slave != nil){
2098*5849851aSforsyth 		print(" slaves");
2099*5849851aSforsyth 		for(sl = tk->slave; sl != nil; sl = sl->next)
2100*5849851aSforsyth 			print(" [%#p %q]", sl, tkname(sl));
2101*5849851aSforsyth 	}
2102*5849851aSforsyth 	print("\n");
2103*5849851aSforsyth 	if(tk->type != TKcanvas)
2104*5849851aSforsyth 		return;
2105*5849851aSforsyth 	tkcvsdump(tk);
2106*5849851aSforsyth }
2107*5849851aSforsyth 
2108*5849851aSforsyth void
tktopdump(Tk * tk)2109*5849851aSforsyth tktopdump(Tk *tk)
2110*5849851aSforsyth {
2111*5849851aSforsyth 	TkTop *top;
2112*5849851aSforsyth 	Tk *sub;
2113*5849851aSforsyth 
2114*5849851aSforsyth 	if(tk == nil || tk->env == nil){
2115*5849851aSforsyth 		print("# %#p no top\n", tk);
2116*5849851aSforsyth 		return;
2117*5849851aSforsyth 	}
2118*5849851aSforsyth 	top = tk->env->top;
2119*5849851aSforsyth 	print("# env %#p top %#p\n", tk->env, top);
2120*5849851aSforsyth 	if(top != nil){
2121*5849851aSforsyth 		for(sub = top->root; sub != nil; sub = sub->siblings)
2122*5849851aSforsyth 			tkdump(sub);
2123*5849851aSforsyth 	}
2124*5849851aSforsyth }
2125