xref: /inferno-os/libtk/ebind.c (revision 5849851a19380dbb62a47d9c4d868a81e42fa79b)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "tk.h"
437da2899SCharles.Forsyth #include <kernel.h>
537da2899SCharles.Forsyth #include <interp.h>
637da2899SCharles.Forsyth 
737da2899SCharles.Forsyth enum
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth 	Cmask,
1037da2899SCharles.Forsyth 	Cctl,
1137da2899SCharles.Forsyth 	Ckey,
1237da2899SCharles.Forsyth 	Cbp,
1337da2899SCharles.Forsyth 	Cbr,
1437da2899SCharles.Forsyth };
1537da2899SCharles.Forsyth 
1637da2899SCharles.Forsyth struct
1737da2899SCharles.Forsyth {
1837da2899SCharles.Forsyth 	char*	event;
1937da2899SCharles.Forsyth 	int	mask;
2037da2899SCharles.Forsyth 	int	action;
2137da2899SCharles.Forsyth } etab[] =
2237da2899SCharles.Forsyth {
2337da2899SCharles.Forsyth 	"Motion",		TkMotion,	Cmask,
2437da2899SCharles.Forsyth 	"Double",		TkDouble,	Cmask,
2537da2899SCharles.Forsyth 	"Map",			TkMap,		Cmask,
2637da2899SCharles.Forsyth 	"Unmap",		TkUnmap,	Cmask,
2737da2899SCharles.Forsyth 	"Destroy",		TkDestroy, Cmask,
2837da2899SCharles.Forsyth 	"Enter",		TkEnter,	Cmask,
2937da2899SCharles.Forsyth 	"Leave",		TkLeave,	Cmask,
3037da2899SCharles.Forsyth 	"FocusIn",		TkFocusin,	Cmask,
3137da2899SCharles.Forsyth 	"FocusOut",		TkFocusout,	Cmask,
3237da2899SCharles.Forsyth 	"Configure",		TkConfigure,	Cmask,
3337da2899SCharles.Forsyth 	"Control",		0,		Cctl,
3437da2899SCharles.Forsyth 	"Key",			0,		Ckey,
3537da2899SCharles.Forsyth 	"KeyPress",		0,		Ckey,
3637da2899SCharles.Forsyth 	"Button",		0,		Cbp,
3737da2899SCharles.Forsyth 	"ButtonPress",		0,		Cbp,
3837da2899SCharles.Forsyth 	"ButtonRelease",	0,		Cbr,
3937da2899SCharles.Forsyth };
4037da2899SCharles.Forsyth 
4137da2899SCharles.Forsyth static
4237da2899SCharles.Forsyth TkOption tkcurop[] =
4337da2899SCharles.Forsyth {
4437da2899SCharles.Forsyth 	"x",		OPTdist,	O(TkCursor, p.x),	nil,
4537da2899SCharles.Forsyth 	"y",		OPTdist,	O(TkCursor, p.y),	nil,
4637da2899SCharles.Forsyth 	"bitmap",	OPTbmap,	O(TkCursor, bit),	nil,
4737da2899SCharles.Forsyth 	"image",	OPTimag,	O(TkCursor, img),	nil,
4837da2899SCharles.Forsyth 	"default",	OPTbool,	O(TkCursor, def),	nil,
4937da2899SCharles.Forsyth 	nil
5037da2899SCharles.Forsyth };
5137da2899SCharles.Forsyth 
5237da2899SCharles.Forsyth static
5337da2899SCharles.Forsyth TkOption focusopts[] = {
5437da2899SCharles.Forsyth 	"global",			OPTbool,	0,	nil,
5537da2899SCharles.Forsyth 	nil
5637da2899SCharles.Forsyth };
5737da2899SCharles.Forsyth 
5837da2899SCharles.Forsyth static char*
tkseqitem(char * buf,char * arg)5937da2899SCharles.Forsyth tkseqitem(char *buf, char *arg)
6037da2899SCharles.Forsyth {
6137da2899SCharles.Forsyth 	while(*arg && (*arg == ' ' || *arg == '-'))
6237da2899SCharles.Forsyth 		arg++;
6337da2899SCharles.Forsyth 	while(*arg && *arg != ' ' && *arg != '-' && *arg != '>')
6437da2899SCharles.Forsyth 		*buf++ = *arg++;
6537da2899SCharles.Forsyth 	*buf = '\0';
6637da2899SCharles.Forsyth 	return arg;
6737da2899SCharles.Forsyth }
6837da2899SCharles.Forsyth 
6937da2899SCharles.Forsyth static char*
tkseqkey(Rune * r,char * arg)7037da2899SCharles.Forsyth tkseqkey(Rune *r, char *arg)
7137da2899SCharles.Forsyth {
7237da2899SCharles.Forsyth 	char *narg;
7337da2899SCharles.Forsyth 
7437da2899SCharles.Forsyth 	while(*arg && (*arg == ' ' || *arg == '-'))
7537da2899SCharles.Forsyth 		arg++;
7637da2899SCharles.Forsyth 	if (*arg == '\\') {
7737da2899SCharles.Forsyth 		if (*++arg == '\0') {
7837da2899SCharles.Forsyth 			*r = 0;
7937da2899SCharles.Forsyth 			return arg;
8037da2899SCharles.Forsyth 		}
8137da2899SCharles.Forsyth 	} else if (*arg == '\0' || *arg == '>' || *arg == '-') {
8237da2899SCharles.Forsyth 		*r = 0;
8337da2899SCharles.Forsyth 		return arg;
8437da2899SCharles.Forsyth 	}
8537da2899SCharles.Forsyth 	narg = arg + chartorune(r, arg);
8637da2899SCharles.Forsyth 	return narg;
8737da2899SCharles.Forsyth }
8837da2899SCharles.Forsyth 
8937da2899SCharles.Forsyth int
tkseqparse(char * seq)9037da2899SCharles.Forsyth tkseqparse(char *seq)
9137da2899SCharles.Forsyth {
9237da2899SCharles.Forsyth 	Rune r;
9337da2899SCharles.Forsyth 	int i, event;
9437da2899SCharles.Forsyth 	char *buf;
9537da2899SCharles.Forsyth 
9637da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
9737da2899SCharles.Forsyth 	if(buf == nil)
9837da2899SCharles.Forsyth 		return -1;
9937da2899SCharles.Forsyth 
10037da2899SCharles.Forsyth 	event = 0;
10137da2899SCharles.Forsyth 
10237da2899SCharles.Forsyth 	while(*seq && *seq != '>') {
10337da2899SCharles.Forsyth 		seq = tkseqitem(buf, seq);
10437da2899SCharles.Forsyth 
10537da2899SCharles.Forsyth 		for(i = 0; i < nelem(etab); i++)
10637da2899SCharles.Forsyth 			if(strcmp(buf, etab[i].event) == 0)
10737da2899SCharles.Forsyth 				break;
10837da2899SCharles.Forsyth 
10937da2899SCharles.Forsyth 		if(i >= nelem(etab)) {
11037da2899SCharles.Forsyth 			seq = tkextnparseseq(buf, seq, &event);
11137da2899SCharles.Forsyth 			if (seq == nil) {
11237da2899SCharles.Forsyth 				free(buf);
11337da2899SCharles.Forsyth 				return -1;
11437da2899SCharles.Forsyth 			}
11537da2899SCharles.Forsyth 			continue;
11637da2899SCharles.Forsyth 		}
11737da2899SCharles.Forsyth 
11837da2899SCharles.Forsyth 
11937da2899SCharles.Forsyth 		switch(etab[i].action) {
12037da2899SCharles.Forsyth 		case Cmask:
12137da2899SCharles.Forsyth 			event |= etab[i].mask;
12237da2899SCharles.Forsyth 			break;
12337da2899SCharles.Forsyth 		case Cctl:
12437da2899SCharles.Forsyth 			seq = tkseqkey(&r, seq);
12537da2899SCharles.Forsyth 			if(r == 0) {
12637da2899SCharles.Forsyth 				free(buf);
12737da2899SCharles.Forsyth 				return -1;
12837da2899SCharles.Forsyth 			}
12937da2899SCharles.Forsyth 			if(r <= '~')
13037da2899SCharles.Forsyth 				r &= 0x1f;
13137da2899SCharles.Forsyth 			event |= TkKey|TKKEY(r);
13237da2899SCharles.Forsyth 			break;
13337da2899SCharles.Forsyth 		case Ckey:
13437da2899SCharles.Forsyth 			seq = tkseqkey(&r, seq);
13537da2899SCharles.Forsyth 			if(r != 0)
13637da2899SCharles.Forsyth 				event |= TKKEY(r);
13737da2899SCharles.Forsyth 			event |= TkKey;
13837da2899SCharles.Forsyth 			break;
13937da2899SCharles.Forsyth 		case Cbp:
14037da2899SCharles.Forsyth 			seq = tkseqitem(buf, seq);
14137da2899SCharles.Forsyth 			switch(buf[0]) {
14237da2899SCharles.Forsyth 			default:
14337da2899SCharles.Forsyth 				free(buf);
14437da2899SCharles.Forsyth 				return -1;
14537da2899SCharles.Forsyth 			case '\0':
14637da2899SCharles.Forsyth 				event |= TkEpress;
14737da2899SCharles.Forsyth 				break;
14837da2899SCharles.Forsyth 			case '1':
14937da2899SCharles.Forsyth 				event |= TkButton1P;
15037da2899SCharles.Forsyth 				break;
15137da2899SCharles.Forsyth 			case '2':
15237da2899SCharles.Forsyth 				event |= TkButton2P;
15337da2899SCharles.Forsyth 				break;
15437da2899SCharles.Forsyth 			case '3':
15537da2899SCharles.Forsyth 				event |= TkButton3P;
15637da2899SCharles.Forsyth 				break;
15737da2899SCharles.Forsyth 			case '4':
15837da2899SCharles.Forsyth 				event |= TkButton4P;
15937da2899SCharles.Forsyth 				break;
16037da2899SCharles.Forsyth 			case '5':
16137da2899SCharles.Forsyth 				event |= TkButton5P;
16237da2899SCharles.Forsyth 				break;
16337da2899SCharles.Forsyth 			case '6':
16437da2899SCharles.Forsyth 				event |= TkButton6P;
16537da2899SCharles.Forsyth 				break;
16637da2899SCharles.Forsyth 			}
16737da2899SCharles.Forsyth 			break;
16837da2899SCharles.Forsyth 		case Cbr:
16937da2899SCharles.Forsyth 			seq = tkseqitem(buf, seq);
17037da2899SCharles.Forsyth 			switch(buf[0]) {
17137da2899SCharles.Forsyth 			default:
17237da2899SCharles.Forsyth 				free(buf);
17337da2899SCharles.Forsyth 				return -1;
17437da2899SCharles.Forsyth 			case '\0':
17537da2899SCharles.Forsyth 				event |= TkErelease;
17637da2899SCharles.Forsyth 				break;
17737da2899SCharles.Forsyth 			case '1':
17837da2899SCharles.Forsyth 				event |= TkButton1R;
17937da2899SCharles.Forsyth 				break;
18037da2899SCharles.Forsyth 			case '2':
18137da2899SCharles.Forsyth 				event |= TkButton2R;
18237da2899SCharles.Forsyth 				break;
18337da2899SCharles.Forsyth 			case '3':
18437da2899SCharles.Forsyth 				event |= TkButton3R;
18537da2899SCharles.Forsyth 				break;
18637da2899SCharles.Forsyth 			case '4':
18737da2899SCharles.Forsyth 				event |= TkButton4R;
18837da2899SCharles.Forsyth 				break;
18937da2899SCharles.Forsyth 			case '5':
19037da2899SCharles.Forsyth 				event |= TkButton5R;
19137da2899SCharles.Forsyth 				break;
19237da2899SCharles.Forsyth 			case '6':
19337da2899SCharles.Forsyth 				event |= TkButton6R;
19437da2899SCharles.Forsyth 				break;
19537da2899SCharles.Forsyth 			}
19637da2899SCharles.Forsyth 			break;
19737da2899SCharles.Forsyth 		}
19837da2899SCharles.Forsyth 	}
19937da2899SCharles.Forsyth 	free(buf);
20037da2899SCharles.Forsyth 	return event;
20137da2899SCharles.Forsyth }
20237da2899SCharles.Forsyth 
20337da2899SCharles.Forsyth void
tkcmdbind(Tk * tk,int event,char * s,void * data)20437da2899SCharles.Forsyth tkcmdbind(Tk *tk, int event, char *s, void *data)
20537da2899SCharles.Forsyth {
20637da2899SCharles.Forsyth 	Point p;
20737da2899SCharles.Forsyth 	TkMouse *m;
20837da2899SCharles.Forsyth 	TkGeom *g;
20937da2899SCharles.Forsyth 	int v, len;
21037da2899SCharles.Forsyth 	char *e, *c, *ec, *cmd;
21137da2899SCharles.Forsyth 	TkTop *t;
21237da2899SCharles.Forsyth 
21337da2899SCharles.Forsyth 	if(s == nil)
21437da2899SCharles.Forsyth 		return;
21537da2899SCharles.Forsyth 	cmd = malloc(2*Tkmaxitem);
21637da2899SCharles.Forsyth 	if (cmd == nil) {
21737da2899SCharles.Forsyth 		print("tk: bind command \"%s\": %s\n",
21837da2899SCharles.Forsyth 			tk->name ? tk->name->name : "(noname)", TkNomem);
21937da2899SCharles.Forsyth 		return;
22037da2899SCharles.Forsyth 	}
22137da2899SCharles.Forsyth 
22237da2899SCharles.Forsyth 	m = (TkMouse*)data;
22337da2899SCharles.Forsyth 	c = cmd;
22437da2899SCharles.Forsyth 	ec = cmd+2*Tkmaxitem-1;
22537da2899SCharles.Forsyth 	while(*s && c < ec) {
22637da2899SCharles.Forsyth 		if(*s != '%') {
22737da2899SCharles.Forsyth 			*c++ = *s++;
22837da2899SCharles.Forsyth 			continue;
22937da2899SCharles.Forsyth 		}
23037da2899SCharles.Forsyth 		s++;
23137da2899SCharles.Forsyth 		len = ec-c;
23237da2899SCharles.Forsyth 		switch(*s++) {
23337da2899SCharles.Forsyth 		def:
23437da2899SCharles.Forsyth 		default:
23537da2899SCharles.Forsyth 			*c++ = s[-1];
23637da2899SCharles.Forsyth 			break;
23737da2899SCharles.Forsyth 		case '%':
23837da2899SCharles.Forsyth 			*c++ = '%';
23937da2899SCharles.Forsyth 			break;
24037da2899SCharles.Forsyth 		case 'b':
24137da2899SCharles.Forsyth 			v = 0;
24237da2899SCharles.Forsyth 			if (!(event & TkKey)) {
24337da2899SCharles.Forsyth 				if(event & (TkButton1P|TkButton1R))
24437da2899SCharles.Forsyth 					v = 1;
245c9ccdbd5Sforsyth 				else if(event & (TkButton2P|TkButton2R))
24637da2899SCharles.Forsyth 					v = 2;
247c9ccdbd5Sforsyth 				else if(event & (TkButton3P|TkButton3R))
24837da2899SCharles.Forsyth 					v = 3;
24937da2899SCharles.Forsyth 			}
25037da2899SCharles.Forsyth 			c += snprint(c, len, "%d", v);
25137da2899SCharles.Forsyth 			break;
25237da2899SCharles.Forsyth 		case 'h':
25337da2899SCharles.Forsyth 			if((event & TkConfigure) == 0)
25437da2899SCharles.Forsyth 				goto def;
25537da2899SCharles.Forsyth 			g = (TkGeom*)data;
25637da2899SCharles.Forsyth 			c += snprint(c, len, "%d", g->height);
25737da2899SCharles.Forsyth 			break;
25837da2899SCharles.Forsyth 		case 's':
25937da2899SCharles.Forsyth 			if((event & TkKey))
26037da2899SCharles.Forsyth 				c += snprint(c, len, "%d", TKKEY(event));
261c9ccdbd5Sforsyth 			else if((event & (TkEmouse|TkEnter)))
26237da2899SCharles.Forsyth 				c += snprint(c, len, "%d", m->b);
263c9ccdbd5Sforsyth 			else if((event & TkFocusin))
26437da2899SCharles.Forsyth 				c += snprint(c, len, "%d", (int)data);
26537da2899SCharles.Forsyth 			else
26637da2899SCharles.Forsyth 				goto def;
26737da2899SCharles.Forsyth 			break;
26837da2899SCharles.Forsyth 		case 'w':
26937da2899SCharles.Forsyth 			if((event & TkConfigure) == 0)
27037da2899SCharles.Forsyth 				goto def;
27137da2899SCharles.Forsyth 			g = (TkGeom*)data;
27237da2899SCharles.Forsyth 			c += snprint(c, len, "%d", g->width);
27337da2899SCharles.Forsyth 			break;
27437da2899SCharles.Forsyth 		case 'x':		/* Relative mouse coords */
27537da2899SCharles.Forsyth 		case 'y':
27637da2899SCharles.Forsyth 			if((event & TkKey) || (event & (TkEmouse|TkEnter)) == 0)
27737da2899SCharles.Forsyth 				goto def;
27837da2899SCharles.Forsyth 			p = tkposn(tk);
27937da2899SCharles.Forsyth 			if(s[-1] == 'x')
28037da2899SCharles.Forsyth 				v = m->x - p.x;
28137da2899SCharles.Forsyth 			else
28237da2899SCharles.Forsyth 				v = m->y - p.y;
28337da2899SCharles.Forsyth 			c += snprint(c, len, "%d", v - tk->borderwidth);
28437da2899SCharles.Forsyth 			break;
28537da2899SCharles.Forsyth 		case 'X':		/* Absolute mouse coords */
28637da2899SCharles.Forsyth 		case 'Y':
28737da2899SCharles.Forsyth 			if((event & TkKey) || (event & TkEmouse) == 0)
28837da2899SCharles.Forsyth 				goto def;
28937da2899SCharles.Forsyth 			c += snprint(c, len, "%d", s[-1] == 'X' ? m->x : m->y);
29037da2899SCharles.Forsyth 			break;
29137da2899SCharles.Forsyth 		case 'A':
29237da2899SCharles.Forsyth 			if((event & TkKey) == 0)
29337da2899SCharles.Forsyth 				goto def;
29437da2899SCharles.Forsyth 			v = TKKEY(event);
29537da2899SCharles.Forsyth 			if(v == '{' || v == '}' || v == '\\')
29637da2899SCharles.Forsyth 				c += snprint(c, len, "\\%C", v);
297c9ccdbd5Sforsyth 			else if(v != '\0')
29837da2899SCharles.Forsyth 				c += snprint(c, len, "%C", v);
29937da2899SCharles.Forsyth 			break;
30037da2899SCharles.Forsyth 		case 'K':
30137da2899SCharles.Forsyth 			if((event & TkKey) == 0)
30237da2899SCharles.Forsyth 				goto def;
30337da2899SCharles.Forsyth 			c += snprint(c, len, "%.4X", TKKEY(event));
30437da2899SCharles.Forsyth 			break;
30537da2899SCharles.Forsyth 		case 'W':
30637da2899SCharles.Forsyth 		        if (tk->name != nil)
30737da2899SCharles.Forsyth 			  c += snprint(c, len, "%s", tk->name->name);
30837da2899SCharles.Forsyth 			break;
30937da2899SCharles.Forsyth 		}
31037da2899SCharles.Forsyth 	}
31137da2899SCharles.Forsyth 	*c = '\0';
31237da2899SCharles.Forsyth 	e = nil;
31337da2899SCharles.Forsyth 	t = tk->env->top;
31437da2899SCharles.Forsyth 	t->execdepth = 0;
31537da2899SCharles.Forsyth 	if(cmd[0] == '|')
31637da2899SCharles.Forsyth 		tkexec(t, cmd+1, nil);
317c9ccdbd5Sforsyth 	else if(cmd[0] != '\0')
31837da2899SCharles.Forsyth 		e = tkexec(t, cmd, nil);
31937da2899SCharles.Forsyth 	t->execdepth = -1;
32037da2899SCharles.Forsyth 
32137da2899SCharles.Forsyth 	if(e == nil) {
32237da2899SCharles.Forsyth 		free(cmd);
32337da2899SCharles.Forsyth 		return;
32437da2899SCharles.Forsyth 	}
32537da2899SCharles.Forsyth 
32637da2899SCharles.Forsyth 	if(tk->name != nil){
32737da2899SCharles.Forsyth 		char *s;
32837da2899SCharles.Forsyth 
32937da2899SCharles.Forsyth 		if(t->errx[0] != '\0')
33037da2899SCharles.Forsyth 			s = tkerrstr(t, e);
33137da2899SCharles.Forsyth 		else
33237da2899SCharles.Forsyth 			s = e;
33337da2899SCharles.Forsyth 		print("tk: bind command \"%s\": %s: %s\n", tk->name->name, cmd, s);
33437da2899SCharles.Forsyth 		if(s != e)
33537da2899SCharles.Forsyth 			free(s);
33637da2899SCharles.Forsyth 	}
33737da2899SCharles.Forsyth 	free(cmd);
33837da2899SCharles.Forsyth }
33937da2899SCharles.Forsyth 
34037da2899SCharles.Forsyth char*
tkbind(TkTop * t,char * arg,char ** ret)34137da2899SCharles.Forsyth tkbind(TkTop *t, char *arg, char **ret)
34237da2899SCharles.Forsyth {
34337da2899SCharles.Forsyth 	Rune r;
34437da2899SCharles.Forsyth 	Tk *tk;
34537da2899SCharles.Forsyth 	TkAction **ap;
34637da2899SCharles.Forsyth 	int i, mode, event;
34737da2899SCharles.Forsyth 	char *cmd, *tag, *seq;
34837da2899SCharles.Forsyth 	char *e;
34937da2899SCharles.Forsyth 
35037da2899SCharles.Forsyth 	USED(ret);
35137da2899SCharles.Forsyth 
35237da2899SCharles.Forsyth 	tag = mallocz(Tkmaxitem, 0);
35337da2899SCharles.Forsyth 	if(tag == nil)
35437da2899SCharles.Forsyth 		return TkNomem;
35537da2899SCharles.Forsyth 	seq = mallocz(Tkmaxitem, 0);
35637da2899SCharles.Forsyth 	if(seq == nil) {
35737da2899SCharles.Forsyth 		free(tag);
35837da2899SCharles.Forsyth 		return TkNomem;
35937da2899SCharles.Forsyth 	}
36037da2899SCharles.Forsyth 
36137da2899SCharles.Forsyth 	arg = tkword(t, arg, tag, tag+Tkmaxitem, nil);
36237da2899SCharles.Forsyth 	if(tag[0] == '\0') {
36337da2899SCharles.Forsyth 		e = TkBadtg;
36437da2899SCharles.Forsyth 		goto err;
36537da2899SCharles.Forsyth 	}
36637da2899SCharles.Forsyth 
36737da2899SCharles.Forsyth 	arg = tkword(t, arg, seq, seq+Tkmaxitem, nil);
36837da2899SCharles.Forsyth 	if(seq[0] == '<') {
36937da2899SCharles.Forsyth 		event = tkseqparse(seq+1);
37037da2899SCharles.Forsyth 		if(event == -1) {
37137da2899SCharles.Forsyth 			e = TkBadsq;
37237da2899SCharles.Forsyth 			goto err;
37337da2899SCharles.Forsyth 		}
37437da2899SCharles.Forsyth 	}
37537da2899SCharles.Forsyth 	else {
37637da2899SCharles.Forsyth 		chartorune(&r, seq);
37737da2899SCharles.Forsyth 		event = TkKey | r;
37837da2899SCharles.Forsyth 	}
37937da2899SCharles.Forsyth 	if(event == 0) {
38037da2899SCharles.Forsyth 		e = TkBadsq;
38137da2899SCharles.Forsyth 		goto err;
38237da2899SCharles.Forsyth 	}
38337da2899SCharles.Forsyth 
38437da2899SCharles.Forsyth 	arg = tkskip(arg, " \t");
38537da2899SCharles.Forsyth 
38637da2899SCharles.Forsyth 	mode = TkArepl;
38737da2899SCharles.Forsyth 	if(*arg == '+') {
38837da2899SCharles.Forsyth 		mode = TkAadd;
38937da2899SCharles.Forsyth 		arg++;
39037da2899SCharles.Forsyth 	}
39137da2899SCharles.Forsyth 	else if(*arg == '-'){
39237da2899SCharles.Forsyth 		mode = TkAsub;
39337da2899SCharles.Forsyth 		arg++;
39437da2899SCharles.Forsyth 	}
39537da2899SCharles.Forsyth 
39637da2899SCharles.Forsyth 	if(*arg == '{') {
39737da2899SCharles.Forsyth 		cmd = tkskip(arg+1, " \t");
39837da2899SCharles.Forsyth 		if(*cmd == '}') {
39937da2899SCharles.Forsyth 			tk = tklook(t, tag, 0);
40037da2899SCharles.Forsyth 			if(tk == nil) {
40137da2899SCharles.Forsyth 				for(i = 0; ; i++) {
40237da2899SCharles.Forsyth 					if(i >= TKwidgets) {
40337da2899SCharles.Forsyth 						e = TkBadwp;
40437da2899SCharles.Forsyth 						tkerr(t, tag);
40537da2899SCharles.Forsyth 						goto err;
40637da2899SCharles.Forsyth 					}
40737da2899SCharles.Forsyth 					if(strcmp(tag, tkmethod[i]->name) == 0) {
40837da2899SCharles.Forsyth 						ap = &(t->binds[i]);
40937da2899SCharles.Forsyth 						break;
41037da2899SCharles.Forsyth 					}
41137da2899SCharles.Forsyth 				}
41237da2899SCharles.Forsyth 			}
41337da2899SCharles.Forsyth 			else
41437da2899SCharles.Forsyth 				ap = &tk->binds;
41537da2899SCharles.Forsyth 			tkcancel(ap, event);
41637da2899SCharles.Forsyth 		}
41737da2899SCharles.Forsyth 	}
41837da2899SCharles.Forsyth 
41937da2899SCharles.Forsyth 	tkword(t, arg, seq, seq+Tkmaxitem, nil);
42037da2899SCharles.Forsyth 	if(tag[0] == '.') {
42137da2899SCharles.Forsyth 		tk = tklook(t, tag, 0);
42237da2899SCharles.Forsyth 		if(tk == nil) {
42337da2899SCharles.Forsyth 			e = TkBadwp;
42437da2899SCharles.Forsyth 			tkerr(t, tag);
42537da2899SCharles.Forsyth 			goto err;
42637da2899SCharles.Forsyth 		}
42737da2899SCharles.Forsyth 
42837da2899SCharles.Forsyth 		cmd = strdup(seq);
42937da2899SCharles.Forsyth 		if(cmd == nil) {
43037da2899SCharles.Forsyth 			e = TkNomem;
43137da2899SCharles.Forsyth 			goto err;
43237da2899SCharles.Forsyth 		}
43337da2899SCharles.Forsyth 		e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
43437da2899SCharles.Forsyth 		if(e != nil)
43537da2899SCharles.Forsyth 			goto err;	/* tkaction does free(cmd) */
43637da2899SCharles.Forsyth 		free(tag);
43737da2899SCharles.Forsyth 		free(seq);
43837da2899SCharles.Forsyth 		return nil;
43937da2899SCharles.Forsyth 	}
44037da2899SCharles.Forsyth 	/* documented but doesn't work */
44137da2899SCharles.Forsyth 	if(strcmp(tag, "all") == 0) {
44237da2899SCharles.Forsyth 		for(tk = t->root; tk; tk = tk->next) {
44337da2899SCharles.Forsyth 			cmd = strdup(seq);
44437da2899SCharles.Forsyth 			if(cmd == nil) {
44537da2899SCharles.Forsyth 				e = TkNomem;
44637da2899SCharles.Forsyth 				goto err;
44737da2899SCharles.Forsyth 			}
44837da2899SCharles.Forsyth 			e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
44937da2899SCharles.Forsyth 			if(e != nil)
45037da2899SCharles.Forsyth 				goto err;
45137da2899SCharles.Forsyth 		}
45237da2899SCharles.Forsyth 		free(tag);
45337da2899SCharles.Forsyth 		free(seq);
45437da2899SCharles.Forsyth 		return nil;
45537da2899SCharles.Forsyth 	}
45637da2899SCharles.Forsyth 	/* undocumented, probably unused, and doesn't work consistently */
45737da2899SCharles.Forsyth 	for(i = 0; i < TKwidgets; i++) {
45837da2899SCharles.Forsyth 		if(strcmp(tag, tkmethod[i]->name) == 0) {
45937da2899SCharles.Forsyth 			cmd = strdup(seq);
46037da2899SCharles.Forsyth 			if(cmd == nil) {
46137da2899SCharles.Forsyth 				e = TkNomem;
46237da2899SCharles.Forsyth 				goto err;
46337da2899SCharles.Forsyth 			}
46437da2899SCharles.Forsyth 			e = tkaction(t->binds + i,event, TkDynamic, cmd, mode);
46537da2899SCharles.Forsyth 			if(e != nil)
46637da2899SCharles.Forsyth 				goto err;
46737da2899SCharles.Forsyth 			free(tag);
46837da2899SCharles.Forsyth 			free(seq);
46937da2899SCharles.Forsyth 			return nil;
47037da2899SCharles.Forsyth 		}
47137da2899SCharles.Forsyth 	}
47237da2899SCharles.Forsyth 
47337da2899SCharles.Forsyth 	e = TkBadtg;
47437da2899SCharles.Forsyth err:
47537da2899SCharles.Forsyth 	free(tag);
47637da2899SCharles.Forsyth 	free(seq);
47737da2899SCharles.Forsyth 
47837da2899SCharles.Forsyth 	return e;
47937da2899SCharles.Forsyth }
48037da2899SCharles.Forsyth 
48137da2899SCharles.Forsyth char*
tksend(TkTop * t,char * arg,char ** ret)48237da2899SCharles.Forsyth tksend(TkTop *t, char *arg, char **ret)
48337da2899SCharles.Forsyth {
48437da2899SCharles.Forsyth 
48537da2899SCharles.Forsyth 	TkVar *v;
48637da2899SCharles.Forsyth 	char *var;
48737da2899SCharles.Forsyth 
48837da2899SCharles.Forsyth 	USED(ret);
48937da2899SCharles.Forsyth 
49037da2899SCharles.Forsyth 	var = mallocz(Tkmaxitem, 0);
49137da2899SCharles.Forsyth 	if(var == nil)
49237da2899SCharles.Forsyth 		return TkNomem;
49337da2899SCharles.Forsyth 
49437da2899SCharles.Forsyth 	arg = tkword(t, arg, var, var+Tkmaxitem, nil);
49537da2899SCharles.Forsyth 	v = tkmkvar(t, var, 0);
49637da2899SCharles.Forsyth 	free(var);
49737da2899SCharles.Forsyth 	if(v == nil)
49837da2899SCharles.Forsyth 		return TkBadvr;
49937da2899SCharles.Forsyth 	if(v->type != TkVchan)
50037da2899SCharles.Forsyth 		return TkNotvt;
50137da2899SCharles.Forsyth 
50237da2899SCharles.Forsyth 	arg = tkskip(arg, " \t");
50337da2899SCharles.Forsyth 	if(tktolimbo(v->value, arg) == 0)
50437da2899SCharles.Forsyth 		return TkMovfw;
50537da2899SCharles.Forsyth 
50637da2899SCharles.Forsyth 	return nil;
50737da2899SCharles.Forsyth }
50837da2899SCharles.Forsyth 
50937da2899SCharles.Forsyth static Tk*
tknextfocus(TkTop * t,int d)51037da2899SCharles.Forsyth tknextfocus(TkTop *t, int d)
51137da2899SCharles.Forsyth {
51237da2899SCharles.Forsyth 	int i, n, j, k;
51337da2899SCharles.Forsyth 	Tk *oldfocus;
51437da2899SCharles.Forsyth 
51537da2899SCharles.Forsyth 	if (t->focusorder == nil)
51637da2899SCharles.Forsyth 		tkbuildfocusorder(t);
51737da2899SCharles.Forsyth 
51837da2899SCharles.Forsyth 	oldfocus = t->ctxt->tkkeygrab;
51937da2899SCharles.Forsyth 	n = t->nfocus;
52037da2899SCharles.Forsyth 	if (n == 0)
52137da2899SCharles.Forsyth 		return oldfocus;
52237da2899SCharles.Forsyth 	for (i = 0; i < n; i++)
52337da2899SCharles.Forsyth 		if (t->focusorder[i] == oldfocus)
52437da2899SCharles.Forsyth 			break;
52537da2899SCharles.Forsyth 	if (i == n) {
52637da2899SCharles.Forsyth 		for (i = 0; i < n; i++)
52737da2899SCharles.Forsyth 			if ((t->focusorder[i]->flag & Tkdisabled) == 0)
52837da2899SCharles.Forsyth 				return t->focusorder[i];
52937da2899SCharles.Forsyth 		return oldfocus;
53037da2899SCharles.Forsyth 	}
53137da2899SCharles.Forsyth 	for (j = 1; j < n; j++) {
53237da2899SCharles.Forsyth 		k = (i + d * j + n) % n;
53337da2899SCharles.Forsyth 		if ((t->focusorder[k]->flag & Tkdisabled) == 0)
53437da2899SCharles.Forsyth 			return t->focusorder[k];
53537da2899SCharles.Forsyth 	}
53637da2899SCharles.Forsyth 	return oldfocus;
53737da2899SCharles.Forsyth }
53837da2899SCharles.Forsyth 
53937da2899SCharles.Forsyth /* our dirty little secret */
54037da2899SCharles.Forsyth static void
focusdirty(Tk * tk)54137da2899SCharles.Forsyth focusdirty(Tk *tk)
54237da2899SCharles.Forsyth {
54337da2899SCharles.Forsyth 	if(tk->highlightwidth > 0){
54437da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
54537da2899SCharles.Forsyth 		tkdirty(tk);
54637da2899SCharles.Forsyth 	}
54737da2899SCharles.Forsyth }
54837da2899SCharles.Forsyth 
54937da2899SCharles.Forsyth void
tksetkeyfocus(TkTop * top,Tk * new,int dir)55037da2899SCharles.Forsyth tksetkeyfocus(TkTop *top, Tk *new, int dir)
55137da2899SCharles.Forsyth {
55237da2899SCharles.Forsyth 	TkCtxt *c;
55337da2899SCharles.Forsyth 	Tk *old;
55437da2899SCharles.Forsyth 
55537da2899SCharles.Forsyth 	c = top->ctxt;
55637da2899SCharles.Forsyth 	old = c->tkkeygrab;
55737da2899SCharles.Forsyth 
55837da2899SCharles.Forsyth 	if(old == new)
55937da2899SCharles.Forsyth 		return;
56037da2899SCharles.Forsyth 	c->tkkeygrab = new;
56137da2899SCharles.Forsyth 	if(top->focused == 0)
56237da2899SCharles.Forsyth 		return;
56337da2899SCharles.Forsyth 	if(old != nil && old != top->root){
56437da2899SCharles.Forsyth 		tkdeliver(old, TkFocusout, nil);
56537da2899SCharles.Forsyth 		focusdirty(old);
56637da2899SCharles.Forsyth 	}
56737da2899SCharles.Forsyth 	if(new != nil && new != top->root){
56837da2899SCharles.Forsyth 		tkdeliver(new, TkFocusin, (void*)dir);
56937da2899SCharles.Forsyth 		focusdirty(new);
57037da2899SCharles.Forsyth 	}
57137da2899SCharles.Forsyth }
57237da2899SCharles.Forsyth 
57337da2899SCharles.Forsyth void
tksetglobalfocus(TkTop * top,int in)57437da2899SCharles.Forsyth tksetglobalfocus(TkTop *top, int in)
57537da2899SCharles.Forsyth {
57637da2899SCharles.Forsyth 	Tk *tk;
57737da2899SCharles.Forsyth 	in = (in != 0);
57837da2899SCharles.Forsyth 	if (in != top->focused){
57937da2899SCharles.Forsyth 		top->focused = in;
58037da2899SCharles.Forsyth 		tk = top->ctxt->tkkeygrab;
58137da2899SCharles.Forsyth 		if(in){
58237da2899SCharles.Forsyth 			tkdeliver(top->root, TkFocusin, (void*)0);
58337da2899SCharles.Forsyth 			if(tk != nil && tk != top->root){
58437da2899SCharles.Forsyth 				tkdeliver(tk, TkFocusin, (void*)0);
58537da2899SCharles.Forsyth 				focusdirty(tk);
58637da2899SCharles.Forsyth 			}
58737da2899SCharles.Forsyth 		}else{
58837da2899SCharles.Forsyth 			if(tk != nil && tk != top->root){
58937da2899SCharles.Forsyth 				tkdeliver(tk, TkFocusout, nil);
59037da2899SCharles.Forsyth 				focusdirty(tk);
59137da2899SCharles.Forsyth 			}
59237da2899SCharles.Forsyth 			tkdeliver(top->root, TkFocusout, nil);
59337da2899SCharles.Forsyth 		}
59437da2899SCharles.Forsyth 	}
59537da2899SCharles.Forsyth }
59637da2899SCharles.Forsyth 
59737da2899SCharles.Forsyth char*
tkfocus(TkTop * top,char * arg,char ** ret)59837da2899SCharles.Forsyth tkfocus(TkTop *top, char *arg, char **ret)
59937da2899SCharles.Forsyth {
60037da2899SCharles.Forsyth 	Tk *tk;
60137da2899SCharles.Forsyth 	char *wp, *e;
60237da2899SCharles.Forsyth 	int dir, global;
60337da2899SCharles.Forsyth 	TkOptab tko[2];
60437da2899SCharles.Forsyth 	TkName *names;
60537da2899SCharles.Forsyth 
60637da2899SCharles.Forsyth 	tko[0].ptr = &global;
60737da2899SCharles.Forsyth 	tko[0].optab = focusopts;
60837da2899SCharles.Forsyth 	tko[1].ptr = nil;
60937da2899SCharles.Forsyth 
61037da2899SCharles.Forsyth 	global = 0;
61137da2899SCharles.Forsyth 
61237da2899SCharles.Forsyth 	names = nil;
61337da2899SCharles.Forsyth 	e = tkparse(top, arg, tko, &names);
61437da2899SCharles.Forsyth 	if (e != nil)
61537da2899SCharles.Forsyth 		return e;
61637da2899SCharles.Forsyth 
61737da2899SCharles.Forsyth 	if(names == nil){
61837da2899SCharles.Forsyth 		if(global)
61937da2899SCharles.Forsyth 			return tkvalue(ret, "%d", top->focused);
62037da2899SCharles.Forsyth 		tk = top->ctxt->tkkeygrab;
62137da2899SCharles.Forsyth 		if (tk != nil && tk->name != nil)
62237da2899SCharles.Forsyth 			return tkvalue(ret, "%s", tk->name->name);
62337da2899SCharles.Forsyth 		return nil;
62437da2899SCharles.Forsyth 	}
62537da2899SCharles.Forsyth 
62637da2899SCharles.Forsyth 	if(global){
62737da2899SCharles.Forsyth 		tksetglobalfocus(top, atoi(names->name));
62837da2899SCharles.Forsyth 		return nil;
62937da2899SCharles.Forsyth 	}
63037da2899SCharles.Forsyth 
63137da2899SCharles.Forsyth 	wp = mallocz(Tkmaxitem, 0);
63237da2899SCharles.Forsyth 	if(wp == nil)
63337da2899SCharles.Forsyth 		return TkNomem;
63437da2899SCharles.Forsyth 
63537da2899SCharles.Forsyth 	tkword(top, arg, wp, wp+Tkmaxitem, nil);
63637da2899SCharles.Forsyth 	if (!strcmp(wp, "next")) {
63737da2899SCharles.Forsyth 		tk = tknextfocus(top, 1);		/* can only return nil if c->tkkeygrab is already nil */
63837da2899SCharles.Forsyth 		dir = +1;
63937da2899SCharles.Forsyth 	} else if (!strcmp(wp, "previous")) {
64037da2899SCharles.Forsyth 		tk = tknextfocus(top, -1);
64137da2899SCharles.Forsyth 		dir = -1;
64237da2899SCharles.Forsyth 	} else if(*wp == '\0') {
64337da2899SCharles.Forsyth 		tk = nil;
64437da2899SCharles.Forsyth 		dir = 0;
64537da2899SCharles.Forsyth 	} else {
64637da2899SCharles.Forsyth 		tk = tklook(top, wp, 0);
64737da2899SCharles.Forsyth 		if(tk == nil){
64837da2899SCharles.Forsyth 			tkerr(top, wp);
64937da2899SCharles.Forsyth 			free(wp);
65037da2899SCharles.Forsyth 			return TkBadwp;
65137da2899SCharles.Forsyth 		}
65237da2899SCharles.Forsyth 		dir = 0;
65337da2899SCharles.Forsyth 	}
65437da2899SCharles.Forsyth 	free(wp);
65537da2899SCharles.Forsyth 
65637da2899SCharles.Forsyth 	tksetkeyfocus(top, tk, dir);
65737da2899SCharles.Forsyth 	return nil;
65837da2899SCharles.Forsyth }
65937da2899SCharles.Forsyth 
66037da2899SCharles.Forsyth char*
tkraise(TkTop * t,char * arg,char ** ret)66137da2899SCharles.Forsyth tkraise(TkTop *t, char *arg, char **ret)
66237da2899SCharles.Forsyth {
66337da2899SCharles.Forsyth 	Tk *tk;
66437da2899SCharles.Forsyth 	char *wp;
66537da2899SCharles.Forsyth 
66637da2899SCharles.Forsyth 	USED(ret);
66737da2899SCharles.Forsyth 
66837da2899SCharles.Forsyth 	wp = mallocz(Tkmaxitem, 0);
66937da2899SCharles.Forsyth 	if(wp == nil)
67037da2899SCharles.Forsyth 		return TkNomem;
67137da2899SCharles.Forsyth 	tkword(t, arg, wp, wp+Tkmaxitem, nil);
67237da2899SCharles.Forsyth 	tk = tklook(t, wp, 0);
67337da2899SCharles.Forsyth 	if(tk == nil){
67437da2899SCharles.Forsyth 		tkerr(t, wp);
67537da2899SCharles.Forsyth 		free(wp);
67637da2899SCharles.Forsyth 		return TkBadwp;
67737da2899SCharles.Forsyth 	}
67837da2899SCharles.Forsyth 	free(wp);
67937da2899SCharles.Forsyth 
68037da2899SCharles.Forsyth 	if((tk->flag & Tkwindow) == 0)
68137da2899SCharles.Forsyth 		return TkNotwm;
68237da2899SCharles.Forsyth 
68337da2899SCharles.Forsyth 	tkwreq(tk->env->top, "raise %s", tk->name->name);
68437da2899SCharles.Forsyth 	return nil;
68537da2899SCharles.Forsyth }
68637da2899SCharles.Forsyth 
68737da2899SCharles.Forsyth char*
tklower(TkTop * t,char * arg,char ** ret)68837da2899SCharles.Forsyth tklower(TkTop *t, char *arg, char **ret)
68937da2899SCharles.Forsyth {
69037da2899SCharles.Forsyth 	Tk *tk;
69137da2899SCharles.Forsyth 	char *wp;
69237da2899SCharles.Forsyth 
69337da2899SCharles.Forsyth 	USED(ret);
69437da2899SCharles.Forsyth 	wp = mallocz(Tkmaxitem, 0);
69537da2899SCharles.Forsyth 	if(wp == nil)
69637da2899SCharles.Forsyth 		return TkNomem;
69737da2899SCharles.Forsyth 	tkword(t, arg, wp, wp+Tkmaxitem, nil);
69837da2899SCharles.Forsyth 	tk = tklook(t, wp, 0);
69937da2899SCharles.Forsyth 	if(tk == nil){
70037da2899SCharles.Forsyth 		tkerr(t, wp);
70137da2899SCharles.Forsyth 		free(wp);
70237da2899SCharles.Forsyth 		return TkBadwp;
70337da2899SCharles.Forsyth 	}
70437da2899SCharles.Forsyth 	free(wp);
70537da2899SCharles.Forsyth 
70637da2899SCharles.Forsyth 	if((tk->flag & Tkwindow) == 0)
70737da2899SCharles.Forsyth 		return TkNotwm;
70837da2899SCharles.Forsyth 
70937da2899SCharles.Forsyth 	tkwreq(tk->env->top, "lower %s", tk->name->name);
71037da2899SCharles.Forsyth 	return nil;
71137da2899SCharles.Forsyth }
71237da2899SCharles.Forsyth 
71337da2899SCharles.Forsyth char*
tkgrab(TkTop * t,char * arg,char ** ret)71437da2899SCharles.Forsyth tkgrab(TkTop *t, char *arg, char **ret)
71537da2899SCharles.Forsyth {
71637da2899SCharles.Forsyth 	Tk *tk;
71737da2899SCharles.Forsyth 	TkCtxt *c;
71837da2899SCharles.Forsyth 	char *r, *buf, *wp;
71937da2899SCharles.Forsyth 
72037da2899SCharles.Forsyth 	USED(ret);
72137da2899SCharles.Forsyth 
72237da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
72337da2899SCharles.Forsyth 	if(buf == nil)
72437da2899SCharles.Forsyth 		return TkNomem;
72537da2899SCharles.Forsyth 
72637da2899SCharles.Forsyth 	wp = mallocz(Tkmaxitem, 0);
72737da2899SCharles.Forsyth 	if(wp == nil) {
72837da2899SCharles.Forsyth 		free(buf);
72937da2899SCharles.Forsyth 		return TkNomem;
73037da2899SCharles.Forsyth 	}
73137da2899SCharles.Forsyth 	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
73237da2899SCharles.Forsyth 
73337da2899SCharles.Forsyth 	tkword(t, arg, wp, wp+Tkmaxitem, nil);
73437da2899SCharles.Forsyth 	tk = tklook(t, wp, 0);
73537da2899SCharles.Forsyth 	if(tk == nil) {
73637da2899SCharles.Forsyth 		free(buf);
73737da2899SCharles.Forsyth 		tkerr(t, wp);
73837da2899SCharles.Forsyth 		free(wp);
73937da2899SCharles.Forsyth 		return TkBadwp;
74037da2899SCharles.Forsyth 	}
74137da2899SCharles.Forsyth 	free(wp);
74237da2899SCharles.Forsyth 
74337da2899SCharles.Forsyth 	c = t->ctxt;
74437da2899SCharles.Forsyth 	if(strcmp(buf, "release") == 0) {
74537da2899SCharles.Forsyth 		free(buf);
74637da2899SCharles.Forsyth 		if(c->mgrab == tk)
74737da2899SCharles.Forsyth 			tksetmgrab(t, nil);
74837da2899SCharles.Forsyth 		return nil;
74937da2899SCharles.Forsyth 	}
75037da2899SCharles.Forsyth 	if(strcmp(buf, "set") == 0) {
75137da2899SCharles.Forsyth 		free(buf);
75237da2899SCharles.Forsyth 		return tksetmgrab(t, tk);
75337da2899SCharles.Forsyth 	}
75437da2899SCharles.Forsyth 	if(strcmp(buf, "ifunset") == 0) {
75537da2899SCharles.Forsyth 		free(buf);
75637da2899SCharles.Forsyth 		if(c->mgrab == nil)
75737da2899SCharles.Forsyth 			return tksetmgrab(t, tk);
75837da2899SCharles.Forsyth 		return nil;
75937da2899SCharles.Forsyth 	}
76037da2899SCharles.Forsyth 	if(strcmp(buf, "status") == 0) {
76137da2899SCharles.Forsyth 		free(buf);
76237da2899SCharles.Forsyth 		r = "none";
76337da2899SCharles.Forsyth 		if ((c->mgrab != nil) && (c->mgrab->name != nil))
76437da2899SCharles.Forsyth 			r = c->mgrab->name->name;
76537da2899SCharles.Forsyth 		return tkvalue(ret, "%s", r);
76637da2899SCharles.Forsyth 	}
76737da2899SCharles.Forsyth 	free(buf);
76837da2899SCharles.Forsyth 	return TkBadcm;
76937da2899SCharles.Forsyth }
77037da2899SCharles.Forsyth 
77137da2899SCharles.Forsyth char*
tkputs(TkTop * t,char * arg,char ** ret)77237da2899SCharles.Forsyth tkputs(TkTop *t, char *arg, char **ret)
77337da2899SCharles.Forsyth {
77437da2899SCharles.Forsyth 	char *buf;
77537da2899SCharles.Forsyth 
77637da2899SCharles.Forsyth 	USED(ret);
77737da2899SCharles.Forsyth 
77837da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
77937da2899SCharles.Forsyth 	if(buf == nil)
78037da2899SCharles.Forsyth 		return TkNomem;
78137da2899SCharles.Forsyth 	tkword(t, arg, buf, buf+Tkmaxitem, nil);
78237da2899SCharles.Forsyth 	print("%s\n", buf);
78337da2899SCharles.Forsyth 	free(buf);
78437da2899SCharles.Forsyth 	return nil;
78537da2899SCharles.Forsyth }
78637da2899SCharles.Forsyth 
78737da2899SCharles.Forsyth char*
tkdestroy(TkTop * t,char * arg,char ** ret)78837da2899SCharles.Forsyth tkdestroy(TkTop *t, char *arg, char **ret)
78937da2899SCharles.Forsyth {
79037da2899SCharles.Forsyth 	int found, len, isroot;
79137da2899SCharles.Forsyth 	Tk *tk, **l, *next, *slave;
79237da2899SCharles.Forsyth 	char *n, *e, *buf;
79337da2899SCharles.Forsyth 
79437da2899SCharles.Forsyth 	USED(ret);
79537da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
79637da2899SCharles.Forsyth 	if(buf == nil)
79737da2899SCharles.Forsyth 		return TkNomem;
79837da2899SCharles.Forsyth 	e = nil;
79937da2899SCharles.Forsyth 	for(;;) {
80037da2899SCharles.Forsyth 		arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
80137da2899SCharles.Forsyth 		if(buf[0] == '\0')
80237da2899SCharles.Forsyth 			break;
80337da2899SCharles.Forsyth 
80437da2899SCharles.Forsyth 		len = strlen(buf);
80537da2899SCharles.Forsyth 		found = 0;
80637da2899SCharles.Forsyth 		isroot = (strcmp(buf, ".") == 0);
80737da2899SCharles.Forsyth 		for(tk = t->root; tk; tk = tk->siblings) {
80837da2899SCharles.Forsyth 		        if (tk->name != nil) {
80937da2899SCharles.Forsyth 				n = tk->name->name;
81037da2899SCharles.Forsyth 				if(strcmp(buf, n) == 0) {
81137da2899SCharles.Forsyth 					tk->flag |= Tkdestroy;
81237da2899SCharles.Forsyth 					found = 1;
81337da2899SCharles.Forsyth 				} else if(isroot || (strncmp(buf, n, len) == 0 && n[len] == '.'))
81437da2899SCharles.Forsyth 					tk->flag |= Tkdestroy;
81537da2899SCharles.Forsyth 			}
81637da2899SCharles.Forsyth 		}
81737da2899SCharles.Forsyth 		if(!found) {
81837da2899SCharles.Forsyth 			e = TkBadwp;
81937da2899SCharles.Forsyth 			tkerr(t, buf);
82037da2899SCharles.Forsyth 			break;
82137da2899SCharles.Forsyth 		}
82237da2899SCharles.Forsyth 	}
82337da2899SCharles.Forsyth 	free(buf);
82437da2899SCharles.Forsyth 
82537da2899SCharles.Forsyth 	for(tk = t->root; tk; tk = tk->siblings) {
82637da2899SCharles.Forsyth 		if((tk->flag & Tkdestroy) == 0)
82737da2899SCharles.Forsyth 			continue;
82837da2899SCharles.Forsyth 		if(tk->flag & Tkwindow) {
82937da2899SCharles.Forsyth 			tkunmap(tk);
830*5849851aSforsyth 			if(tk->name != nil &&
831*5849851aSforsyth 			   strcmp(tk->name->name, ".") == 0)
83237da2899SCharles.Forsyth 				tk->flag &= ~Tkdestroy;
83337da2899SCharles.Forsyth 			else
83437da2899SCharles.Forsyth 				tkdeliver(tk, TkDestroy, nil);
83537da2899SCharles.Forsyth 		} else
83637da2899SCharles.Forsyth 			tkdeliver(tk, TkDestroy, nil);
837*5849851aSforsyth if(0)print("tkdestroy %q\n", tkname(tk));
83837da2899SCharles.Forsyth 		if(tk->destroyed != nil)
83937da2899SCharles.Forsyth 			tk->destroyed(tk);
84037da2899SCharles.Forsyth 		tkpackqit(tk->master);
84137da2899SCharles.Forsyth 		tkdelpack(tk);
84237da2899SCharles.Forsyth 		for (slave = tk->slave; slave != nil; slave = next) {
84337da2899SCharles.Forsyth 			next = slave->next;
84437da2899SCharles.Forsyth 			slave->master = nil;
84537da2899SCharles.Forsyth 			slave->next = nil;
84637da2899SCharles.Forsyth 		}
84737da2899SCharles.Forsyth 		tk->slave = nil;
84837da2899SCharles.Forsyth 		if(tk->parent != nil && tk->geom != nil)		/* XXX this appears to be bogus */
84937da2899SCharles.Forsyth 			tk->geom(tk, 0, 0, 0, 0);
85037da2899SCharles.Forsyth 		if(tk->grid){
85137da2899SCharles.Forsyth 			tkfreegrid(tk->grid);
85237da2899SCharles.Forsyth 			tk->grid = nil;
85337da2899SCharles.Forsyth 		}
85437da2899SCharles.Forsyth 	}
85537da2899SCharles.Forsyth 	tkrunpack(t);
85637da2899SCharles.Forsyth 
85737da2899SCharles.Forsyth 	l = &t->windows;
85837da2899SCharles.Forsyth 	for(tk = t->windows; tk; tk = next) {
85937da2899SCharles.Forsyth 		next = TKobj(TkWin, tk)->next;
86037da2899SCharles.Forsyth 		if(tk->flag & Tkdestroy) {
86137da2899SCharles.Forsyth 			*l = next;
86237da2899SCharles.Forsyth 			continue;
86337da2899SCharles.Forsyth 		}
86437da2899SCharles.Forsyth 		l = &TKobj(TkWin, tk)->next;
86537da2899SCharles.Forsyth 	}
86637da2899SCharles.Forsyth 	l = &t->root;
86737da2899SCharles.Forsyth 	for(tk = t->root; tk; tk = next) {
86837da2899SCharles.Forsyth 		next = tk->siblings;
86937da2899SCharles.Forsyth 		if(tk->flag & Tkdestroy) {
87037da2899SCharles.Forsyth 			*l = next;
87137da2899SCharles.Forsyth 			tkfreeobj(tk);
87237da2899SCharles.Forsyth 			continue;
87337da2899SCharles.Forsyth 		}
87437da2899SCharles.Forsyth 		l = &tk->siblings;
87537da2899SCharles.Forsyth 	}
87637da2899SCharles.Forsyth 
87737da2899SCharles.Forsyth 	return e;
87837da2899SCharles.Forsyth }
87937da2899SCharles.Forsyth 
88037da2899SCharles.Forsyth char*
tkupdatecmd(TkTop * t,char * arg,char ** ret)88137da2899SCharles.Forsyth tkupdatecmd(TkTop *t, char *arg, char **ret)
88237da2899SCharles.Forsyth {
88337da2899SCharles.Forsyth 	Tk *tk;
88437da2899SCharles.Forsyth 	int x, y;
88537da2899SCharles.Forsyth 	Rectangle *dr;
88637da2899SCharles.Forsyth 	char buf[Tkmaxitem];
88737da2899SCharles.Forsyth 
88837da2899SCharles.Forsyth 	USED(ret);
88937da2899SCharles.Forsyth 
89037da2899SCharles.Forsyth 	tkword(t, arg, buf, buf+sizeof(buf), nil);
89137da2899SCharles.Forsyth 	if(strcmp(buf, "-onscreen") == 0){
89237da2899SCharles.Forsyth 		tk = t->root;
89337da2899SCharles.Forsyth 		dr = &t->screenr;
89437da2899SCharles.Forsyth 		x = tk->act.x;
89537da2899SCharles.Forsyth 		if(x+tk->act.width > dr->max.x)
89637da2899SCharles.Forsyth 			x = dr->max.x - tk->act.width;
89737da2899SCharles.Forsyth 		if(x < 0)
89837da2899SCharles.Forsyth 			x = 0;
89937da2899SCharles.Forsyth 		y = tk->act.y;
90037da2899SCharles.Forsyth 		if(y+tk->act.height > dr->max.y)
90137da2899SCharles.Forsyth 			y = dr->max.y - tk->act.height;
90237da2899SCharles.Forsyth 		if(y < 0)
90337da2899SCharles.Forsyth 			y = 0;
90437da2899SCharles.Forsyth 		tkmovewin(tk, Pt(x, y));
90537da2899SCharles.Forsyth 	}else if(strcmp(buf, "-disable") == 0){
90637da2899SCharles.Forsyth 		t->noupdate = 1;
90737da2899SCharles.Forsyth 	}else if(strcmp(buf, "-enable") == 0){
90837da2899SCharles.Forsyth 		t->noupdate = 0;
90937da2899SCharles.Forsyth 	}
91037da2899SCharles.Forsyth 	return tkupdate(t);
91137da2899SCharles.Forsyth }
91237da2899SCharles.Forsyth 
91337da2899SCharles.Forsyth char*
tkwinfo(TkTop * t,char * arg,char ** ret)91437da2899SCharles.Forsyth tkwinfo(TkTop *t, char *arg, char **ret)
91537da2899SCharles.Forsyth {
91637da2899SCharles.Forsyth 	Tk *tk;
91737da2899SCharles.Forsyth 	char *cmd, *arg1;
91837da2899SCharles.Forsyth 
91937da2899SCharles.Forsyth 	cmd = mallocz(Tkmaxitem, 0);
92037da2899SCharles.Forsyth 	if(cmd == nil)
92137da2899SCharles.Forsyth 		return TkNomem;
92237da2899SCharles.Forsyth 
92337da2899SCharles.Forsyth 	arg = tkword(t, arg, cmd, cmd+Tkmaxitem, nil);
92437da2899SCharles.Forsyth 	if(strcmp(cmd, "class") == 0) {
92537da2899SCharles.Forsyth 		arg1 = mallocz(Tkmaxitem, 0);
92637da2899SCharles.Forsyth 		if(arg1 == nil) {
92737da2899SCharles.Forsyth 			free(cmd);
92837da2899SCharles.Forsyth 			return TkNomem;
92937da2899SCharles.Forsyth 		}
93037da2899SCharles.Forsyth 		tkword(t, arg, arg1, arg1+Tkmaxitem, nil);
93137da2899SCharles.Forsyth 		tk = tklook(t, arg1, 0);
93237da2899SCharles.Forsyth 		if(tk == nil){
93337da2899SCharles.Forsyth 			tkerr(t, arg1);
93437da2899SCharles.Forsyth 			free(arg1);
93537da2899SCharles.Forsyth 			free(cmd);
93637da2899SCharles.Forsyth 			return TkBadwp;
93737da2899SCharles.Forsyth 		}
93837da2899SCharles.Forsyth 		free(arg1);
93937da2899SCharles.Forsyth 		free(cmd);
94037da2899SCharles.Forsyth 		return tkvalue(ret, "%s", tkmethod[tk->type]->name);
94137da2899SCharles.Forsyth 	}
94237da2899SCharles.Forsyth 	free(cmd);
94337da2899SCharles.Forsyth 	return TkBadvl;
94437da2899SCharles.Forsyth }
94537da2899SCharles.Forsyth 
94637da2899SCharles.Forsyth char*
tkcursorcmd(TkTop * t,char * arg,char ** ret)94737da2899SCharles.Forsyth tkcursorcmd(TkTop *t, char *arg, char **ret)
94837da2899SCharles.Forsyth {
94937da2899SCharles.Forsyth 	char *e;
95037da2899SCharles.Forsyth 	int locked;
95137da2899SCharles.Forsyth 	Display *d;
95237da2899SCharles.Forsyth 	TkCursor c;
95337da2899SCharles.Forsyth 	TkOptab tko[3];
95437da2899SCharles.Forsyth 	enum {Notset = 0x80000000};
95537da2899SCharles.Forsyth 
95637da2899SCharles.Forsyth 	c.def = 0;
95737da2899SCharles.Forsyth 	c.p.x = Notset;
95837da2899SCharles.Forsyth 	c.p.y = Notset;
95937da2899SCharles.Forsyth 	c.bit = nil;
96037da2899SCharles.Forsyth 	c.img = nil;
96137da2899SCharles.Forsyth 
96237da2899SCharles.Forsyth 	USED(ret);
96337da2899SCharles.Forsyth 
96437da2899SCharles.Forsyth 	c.def = 0;
96537da2899SCharles.Forsyth 	tko[0].ptr = &c;
96637da2899SCharles.Forsyth 	tko[0].optab = tkcurop;
96737da2899SCharles.Forsyth 	tko[1].ptr = nil;
96837da2899SCharles.Forsyth 	e = tkparse(t, arg, tko, nil);
96937da2899SCharles.Forsyth 	if(e != nil)
97037da2899SCharles.Forsyth 		return e;
97137da2899SCharles.Forsyth 
97237da2899SCharles.Forsyth 	d = t->display;
97337da2899SCharles.Forsyth 	locked = lockdisplay(d);
97437da2899SCharles.Forsyth 	if(c.def)
97537da2899SCharles.Forsyth 		tkcursorswitch(t, nil, nil);
97637da2899SCharles.Forsyth 	if(c.img != nil || c.bit != nil){
97737da2899SCharles.Forsyth 		e = tkcursorswitch(t, c.bit, c.img);
97837da2899SCharles.Forsyth 		tkimgput(c.img);
97937da2899SCharles.Forsyth 		freeimage(c.bit);
98037da2899SCharles.Forsyth 	}
98137da2899SCharles.Forsyth 	if(e == nil){
98237da2899SCharles.Forsyth 		if(c.p.x != Notset && c.p.y != Notset)
98337da2899SCharles.Forsyth 			tkcursorset(t, c.p);
98437da2899SCharles.Forsyth 	}
98537da2899SCharles.Forsyth 	if(locked)
98637da2899SCharles.Forsyth 		unlockdisplay(d);
98737da2899SCharles.Forsyth 	return e;
98837da2899SCharles.Forsyth }
98937da2899SCharles.Forsyth 
99037da2899SCharles.Forsyth char *
tkbindings(TkTop * t,Tk * tk,TkEbind * b,int blen)99137da2899SCharles.Forsyth tkbindings(TkTop *t, Tk *tk, TkEbind *b, int blen)
99237da2899SCharles.Forsyth {
99337da2899SCharles.Forsyth 	TkAction *a, **ap;
99437da2899SCharles.Forsyth 	char *cmd, *e;
99537da2899SCharles.Forsyth 	int i;
99637da2899SCharles.Forsyth 
99737da2899SCharles.Forsyth 	e = nil;
99837da2899SCharles.Forsyth 	for(i = 0; e == nil && i < blen; i++)	/* default bindings */ {
99937da2899SCharles.Forsyth 		int how = TkArepl;
100037da2899SCharles.Forsyth 		char *cmd = b[i].cmd;
100137da2899SCharles.Forsyth 		if(cmd[0] == '+') {
100237da2899SCharles.Forsyth 			how = TkAadd;
100337da2899SCharles.Forsyth 			cmd++;
100437da2899SCharles.Forsyth 		}
100537da2899SCharles.Forsyth 		else if(cmd[0] == '-'){
100637da2899SCharles.Forsyth 			how = TkAsub;
100737da2899SCharles.Forsyth 			cmd++;
100837da2899SCharles.Forsyth 		}
100937da2899SCharles.Forsyth 		e = tkaction(&tk->binds, b[i].event, TkStatic, cmd, how);
101037da2899SCharles.Forsyth 	}
101137da2899SCharles.Forsyth 
101237da2899SCharles.Forsyth 	if(e != nil)
101337da2899SCharles.Forsyth 		return e;
101437da2899SCharles.Forsyth 
101537da2899SCharles.Forsyth 	ap = &tk->binds;
101637da2899SCharles.Forsyth 	for(a = t->binds[tk->type]; a; a = a->link) {	/* user "defaults" */
101737da2899SCharles.Forsyth 		cmd = strdup(a->arg);
101837da2899SCharles.Forsyth 		if(cmd == nil)
101937da2899SCharles.Forsyth 			return TkNomem;
102037da2899SCharles.Forsyth 
102137da2899SCharles.Forsyth 		e = tkaction(ap, a->event, TkDynamic, cmd,
102237da2899SCharles.Forsyth 						(a->type >> 8) & 0xff);
102337da2899SCharles.Forsyth 		if(e != nil)
102437da2899SCharles.Forsyth 			return e;
102537da2899SCharles.Forsyth 		ap = &(*ap)->link;
102637da2899SCharles.Forsyth 	}
102737da2899SCharles.Forsyth 	return nil;
102837da2899SCharles.Forsyth }
1029