xref: /plan9/sys/src/libcontrol/entry.c (revision 42dedc50a943b5d120c8c26dac13fc4664b65146)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier 
980ee5cbfSDavid du Colombier typedef struct Entry Entry;
1080ee5cbfSDavid du Colombier 
1180ee5cbfSDavid du Colombier struct Entry
1280ee5cbfSDavid du Colombier {
1380ee5cbfSDavid du Colombier 	Control;
1480ee5cbfSDavid du Colombier 	int		border;
1580ee5cbfSDavid du Colombier 	CFont	*font;
1680ee5cbfSDavid du Colombier 	CImage	*image;
1780ee5cbfSDavid du Colombier 	CImage	*textcolor;
1880ee5cbfSDavid du Colombier 	CImage	*bordercolor;
1980ee5cbfSDavid du Colombier 	Rune		*text;
2080ee5cbfSDavid du Colombier 	int		ntext;
2180ee5cbfSDavid du Colombier 	int		cursor;
2280ee5cbfSDavid du Colombier 	int		align;
2380ee5cbfSDavid du Colombier 	int		hasfocus;
2480ee5cbfSDavid du Colombier 	int		lastbut;
2580ee5cbfSDavid du Colombier };
2680ee5cbfSDavid du Colombier 
2780ee5cbfSDavid du Colombier enum{
2880ee5cbfSDavid du Colombier 	EAlign,
2980ee5cbfSDavid du Colombier 	EBorder,
3080ee5cbfSDavid du Colombier 	EBordercolor,
3180ee5cbfSDavid du Colombier 	EData,
3280ee5cbfSDavid du Colombier 	EFocus,
3380ee5cbfSDavid du Colombier 	EFont,
3480ee5cbfSDavid du Colombier 	EFormat,
359a747e4fSDavid du Colombier 	EHide,
3680ee5cbfSDavid du Colombier 	EImage,
3780ee5cbfSDavid du Colombier 	ERect,
389a747e4fSDavid du Colombier 	EReveal,
3980ee5cbfSDavid du Colombier 	EShow,
409a747e4fSDavid du Colombier 	ESize,
4180ee5cbfSDavid du Colombier 	ETextcolor,
4280ee5cbfSDavid du Colombier 	EValue,
4380ee5cbfSDavid du Colombier };
4480ee5cbfSDavid du Colombier 
4580ee5cbfSDavid du Colombier static char *cmds[] = {
4680ee5cbfSDavid du Colombier 	[EAlign] =			"align",
4780ee5cbfSDavid du Colombier 	[EBorder] =		"border",
4880ee5cbfSDavid du Colombier 	[EBordercolor] =	"bordercolor",
4980ee5cbfSDavid du Colombier 	[EData] = 			"data",
5080ee5cbfSDavid du Colombier 	[EFocus] = 		"focus",
5180ee5cbfSDavid du Colombier 	[EFont] =			"font",
5280ee5cbfSDavid du Colombier 	[EFormat] = 		"format",
539a747e4fSDavid du Colombier 	[EHide] =			"hide",
5480ee5cbfSDavid du Colombier 	[EImage] =		"image",
5580ee5cbfSDavid du Colombier 	[ERect] =			"rect",
569a747e4fSDavid du Colombier 	[EReveal] =		"reveal",
5780ee5cbfSDavid du Colombier 	[EShow] =			"show",
589a747e4fSDavid du Colombier 	[ESize] =			"size",
5980ee5cbfSDavid du Colombier 	[ETextcolor] =		"textcolor",
6080ee5cbfSDavid du Colombier 	[EValue] =			"value",
6180ee5cbfSDavid du Colombier 	nil
6280ee5cbfSDavid du Colombier };
6380ee5cbfSDavid du Colombier 
6480ee5cbfSDavid du Colombier static void
entryfree(Control * c)659a747e4fSDavid du Colombier entryfree(Control *c)
6680ee5cbfSDavid du Colombier {
6780ee5cbfSDavid du Colombier 	Entry *e;
6880ee5cbfSDavid du Colombier 
699a747e4fSDavid du Colombier 	e = (Entry *)c;
7080ee5cbfSDavid du Colombier 	_putctlfont(e->font);
7180ee5cbfSDavid du Colombier 	_putctlimage(e->image);
7280ee5cbfSDavid du Colombier 	_putctlimage(e->textcolor);
7380ee5cbfSDavid du Colombier 	_putctlimage(e->bordercolor);
7480ee5cbfSDavid du Colombier 	free(e->text);
7580ee5cbfSDavid du Colombier }
7680ee5cbfSDavid du Colombier 
7780ee5cbfSDavid du Colombier static Point
entrypoint(Entry * e,int c)7880ee5cbfSDavid du Colombier entrypoint(Entry *e, int c)
7980ee5cbfSDavid du Colombier {
8080ee5cbfSDavid du Colombier 	Point p;
8180ee5cbfSDavid du Colombier 	Rectangle r;
8280ee5cbfSDavid du Colombier 
8380ee5cbfSDavid du Colombier 	r = e->rect;
8480ee5cbfSDavid du Colombier 	if(e->border > 0)
8580ee5cbfSDavid du Colombier 		r = insetrect(r, e->border);
8680ee5cbfSDavid du Colombier 	p = _ctlalignpoint(r,
8780ee5cbfSDavid du Colombier 		runestringnwidth(e->font->font, e->text, e->ntext),
8880ee5cbfSDavid du Colombier 		e->font->font->height, e->align);
8980ee5cbfSDavid du Colombier 	if(c > e->ntext)
9080ee5cbfSDavid du Colombier 		c = e->ntext;
9180ee5cbfSDavid du Colombier 	p.x += runestringnwidth(e->font->font, e->text, c);
9280ee5cbfSDavid du Colombier 	return p;
9380ee5cbfSDavid du Colombier }
9480ee5cbfSDavid du Colombier 
9580ee5cbfSDavid du Colombier static void
entryshow(Entry * e)9680ee5cbfSDavid du Colombier entryshow(Entry *e)
9780ee5cbfSDavid du Colombier {
9880ee5cbfSDavid du Colombier 	Rectangle r, dr;
9980ee5cbfSDavid du Colombier 	Point p;
10080ee5cbfSDavid du Colombier 
1019a747e4fSDavid du Colombier 	if (e->hidden)
1029a747e4fSDavid du Colombier 		return;
10380ee5cbfSDavid du Colombier 	r = e->rect;
10480ee5cbfSDavid du Colombier 	draw(e->screen, r, e->image->image, nil, e->image->image->r.min);
10580ee5cbfSDavid du Colombier 	if(e->border > 0){
10680ee5cbfSDavid du Colombier 		border(e->screen, r, e->border, e->bordercolor->image, e->bordercolor->image->r.min);
10780ee5cbfSDavid du Colombier 		dr = insetrect(r, e->border);
10880ee5cbfSDavid du Colombier 	}else
10980ee5cbfSDavid du Colombier 		dr = r;
11080ee5cbfSDavid du Colombier 	p = entrypoint(e, 0);
11180ee5cbfSDavid du Colombier 	_string(e->screen, p, e->textcolor->image,
11280ee5cbfSDavid du Colombier 		ZP, e->font->font, nil, e->text, e->ntext,
113ac57dd0bSDavid du Colombier 		dr, nil, ZP, SoverD);
11480ee5cbfSDavid du Colombier 	if(e->hasfocus){
11580ee5cbfSDavid du Colombier 		p = entrypoint(e, e->cursor);
11680ee5cbfSDavid du Colombier 		r.min = p;
11780ee5cbfSDavid du Colombier 		r.max.x = p.x+1;
11880ee5cbfSDavid du Colombier 		r.max.y = p.y+e->font->font->height;
11980ee5cbfSDavid du Colombier 		if(rectclip(&r, dr))
12080ee5cbfSDavid du Colombier 			draw(e->screen, r, e->textcolor->image, nil, ZP);
12180ee5cbfSDavid du Colombier 	}
12280ee5cbfSDavid du Colombier 	flushimage(display, 1);
12380ee5cbfSDavid du Colombier }
12480ee5cbfSDavid du Colombier 
12580ee5cbfSDavid du Colombier static void
entrysetpoint(Entry * e,Point cp)1269a747e4fSDavid du Colombier entrysetpoint(Entry *e, Point cp)
1279a747e4fSDavid du Colombier {
1289a747e4fSDavid du Colombier 	Point p;
1299a747e4fSDavid du Colombier 	int i;
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier 	if(!ptinrect(cp, insetrect(e->rect, e->border)))
1329a747e4fSDavid du Colombier 		return;
1339a747e4fSDavid du Colombier 	p = entrypoint(e, 0);
1349a747e4fSDavid du Colombier 	for(i=0; i<e->ntext; i++){
1359a747e4fSDavid du Colombier 		p.x += runestringnwidth(e->font->font, e->text+i, 1);
1369a747e4fSDavid du Colombier 		if(p.x > cp.x)
1379a747e4fSDavid du Colombier 			break;
1389a747e4fSDavid du Colombier 	}
1399a747e4fSDavid du Colombier 	e->cursor = i;
1409a747e4fSDavid du Colombier 	entryshow(e);
1419a747e4fSDavid du Colombier }
1429a747e4fSDavid du Colombier 
1439a747e4fSDavid du Colombier static void
entrymouse(Control * c,Mouse * m)1449a747e4fSDavid du Colombier entrymouse(Control *c, Mouse *m)
1459a747e4fSDavid du Colombier {
1469a747e4fSDavid du Colombier 	Entry *e;
1479a747e4fSDavid du Colombier 
1489a747e4fSDavid du Colombier 	e = (Entry*)c;
1499a747e4fSDavid du Colombier 	if(m->buttons==1 && e->lastbut==0)
1509a747e4fSDavid du Colombier 		entrysetpoint(e, m->xy);
1519a747e4fSDavid du Colombier 	e->lastbut = m->buttons;
1529a747e4fSDavid du Colombier }
1539a747e4fSDavid du Colombier 
1549a747e4fSDavid du Colombier static void
entryctl(Control * c,CParse * cp)1559a747e4fSDavid du Colombier entryctl(Control *c, CParse *cp)
15680ee5cbfSDavid du Colombier {
15780ee5cbfSDavid du Colombier 	int cmd;
15880ee5cbfSDavid du Colombier 	Rectangle r;
15980ee5cbfSDavid du Colombier 	Entry *e;
16080ee5cbfSDavid du Colombier 	Rune *rp;
16180ee5cbfSDavid du Colombier 
16280ee5cbfSDavid du Colombier 	e = (Entry*)c;
1639a747e4fSDavid du Colombier 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
16480ee5cbfSDavid du Colombier 	switch(cmd){
16580ee5cbfSDavid du Colombier 	default:
1669a747e4fSDavid du Colombier 		ctlerror("%q: unrecognized message '%s'", e->name, cp->str);
16780ee5cbfSDavid du Colombier 		break;
16880ee5cbfSDavid du Colombier 	case EAlign:
1699a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
1709a747e4fSDavid du Colombier 		e->align = _ctlalignment(cp->args[1]);
17180ee5cbfSDavid du Colombier 		break;
17280ee5cbfSDavid du Colombier 	case EBorder:
1739a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
1749a747e4fSDavid du Colombier 		if(cp->iargs[1] < 0)
1759a747e4fSDavid du Colombier 			ctlerror("%q: bad border: %c", e->name, cp->str);
1769a747e4fSDavid du Colombier 		e->border = cp->iargs[1];
17780ee5cbfSDavid du Colombier 		break;
17880ee5cbfSDavid du Colombier 	case EBordercolor:
1799a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
1809a747e4fSDavid du Colombier 		_setctlimage(e, &e->bordercolor, cp->args[1]);
18180ee5cbfSDavid du Colombier 		break;
18280ee5cbfSDavid du Colombier 	case EData:
1839a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 1);
1849a747e4fSDavid du Colombier 		chanprint(e->data, "%S", e->text);
18580ee5cbfSDavid du Colombier 		break;
18680ee5cbfSDavid du Colombier 	case EFocus:
1879a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
1889a747e4fSDavid du Colombier 		e->hasfocus = cp->iargs[1];
18980ee5cbfSDavid du Colombier 		e->lastbut = 0;
19080ee5cbfSDavid du Colombier 		entryshow(e);
19180ee5cbfSDavid du Colombier 		break;
19280ee5cbfSDavid du Colombier 	case EFont:
1939a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
1949a747e4fSDavid du Colombier 		_setctlfont(e, &e->font, cp->args[1]);
19580ee5cbfSDavid du Colombier 		break;
19680ee5cbfSDavid du Colombier 	case EFormat:
1979a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
1989a747e4fSDavid du Colombier 		e->format = ctlstrdup(cp->args[1]);
1999a747e4fSDavid du Colombier 		break;
2009a747e4fSDavid du Colombier 	case EHide:
2019a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 1);
2029a747e4fSDavid du Colombier 		e->hidden = 1;
20380ee5cbfSDavid du Colombier 		break;
20480ee5cbfSDavid du Colombier 	case EImage:
2059a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
2069a747e4fSDavid du Colombier 		_setctlimage(e, &e->image, cp->args[1]);
20780ee5cbfSDavid du Colombier 		break;
20880ee5cbfSDavid du Colombier 	case ERect:
2099a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 5);
2109a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
2119a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
2129a747e4fSDavid du Colombier 		r.max.x = cp->iargs[3];
2139a747e4fSDavid du Colombier 		r.max.y = cp->iargs[4];
21480ee5cbfSDavid du Colombier 		if(Dx(r)<=0 || Dy(r)<=0)
2159a747e4fSDavid du Colombier 			ctlerror("%q: bad rectangle: %s", e->name, cp->str);
21680ee5cbfSDavid du Colombier 		e->rect = r;
21780ee5cbfSDavid du Colombier 		break;
2189a747e4fSDavid du Colombier 	case EReveal:
2199a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 1);
2209a747e4fSDavid du Colombier 		e->hidden = 0;
22180ee5cbfSDavid du Colombier 		entryshow(e);
22280ee5cbfSDavid du Colombier 		break;
2239a747e4fSDavid du Colombier 	case EShow:
2249a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 1);
2259a747e4fSDavid du Colombier 		entryshow(e);
2269a747e4fSDavid du Colombier 		break;
2279a747e4fSDavid du Colombier 	case ESize:
2289a747e4fSDavid du Colombier 		if (cp->nargs == 3)
2299a747e4fSDavid du Colombier 			r.max = Pt(0x7fffffff, 0x7fffffff);
2309a747e4fSDavid du Colombier 		else{
2319a747e4fSDavid du Colombier 			_ctlargcount(e, cp, 5);
2329a747e4fSDavid du Colombier 			r.max.x = cp->iargs[3];
2339a747e4fSDavid du Colombier 			r.max.y = cp->iargs[4];
2349a747e4fSDavid du Colombier 		}
2359a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
2369a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
2379a747e4fSDavid du Colombier 		if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
2389a747e4fSDavid du Colombier 			ctlerror("%q: bad sizes: %s", e->name, cp->str);
2399a747e4fSDavid du Colombier 		e->size.min = r.min;
2409a747e4fSDavid du Colombier 		e->size.max = r.max;
24180ee5cbfSDavid du Colombier 		break;
24280ee5cbfSDavid du Colombier 	case ETextcolor:
2439a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
2449a747e4fSDavid du Colombier 		_setctlimage(e, &e->textcolor, cp->args[1]);
24580ee5cbfSDavid du Colombier 		break;
24680ee5cbfSDavid du Colombier 	case EValue:
2479a747e4fSDavid du Colombier 		_ctlargcount(e, cp, 2);
2489a747e4fSDavid du Colombier 		rp = _ctlrunestr(cp->args[1]);
24980ee5cbfSDavid du Colombier 		if(runestrcmp(rp, e->text) != 0){
25080ee5cbfSDavid du Colombier 			free(e->text);
25180ee5cbfSDavid du Colombier 			e->text = rp;
25280ee5cbfSDavid du Colombier 			e->ntext = runestrlen(e->text);
2539a747e4fSDavid du Colombier 			e->cursor = e->ntext;
25480ee5cbfSDavid du Colombier 			entryshow(e);
25580ee5cbfSDavid du Colombier 		}else
25680ee5cbfSDavid du Colombier 			free(rp);
25780ee5cbfSDavid du Colombier 		break;
25880ee5cbfSDavid du Colombier 	}
25980ee5cbfSDavid du Colombier }
26080ee5cbfSDavid du Colombier 
26180ee5cbfSDavid du Colombier static void
entrykey(Entry * e,Rune r)26280ee5cbfSDavid du Colombier entrykey(Entry *e, Rune r)
26380ee5cbfSDavid du Colombier {
26480ee5cbfSDavid du Colombier 	Rune *s;
26580ee5cbfSDavid du Colombier 	int n;
26680ee5cbfSDavid du Colombier 	char *p;
26780ee5cbfSDavid du Colombier 
26880ee5cbfSDavid du Colombier 	switch(r){
26980ee5cbfSDavid du Colombier 	default:
27080ee5cbfSDavid du Colombier 		e->text = ctlrealloc(e->text, (e->ntext+1+1)*sizeof(Rune));
27180ee5cbfSDavid du Colombier 		memmove(e->text+e->cursor+1, e->text+e->cursor,
27280ee5cbfSDavid du Colombier 			(e->ntext+1-e->cursor)*sizeof(Rune));
27380ee5cbfSDavid du Colombier 		e->text[e->cursor++] = r;
27480ee5cbfSDavid du Colombier 		e->ntext++;
27580ee5cbfSDavid du Colombier 		break;
27680ee5cbfSDavid du Colombier 	case L'\n':	/* newline: return value */
27780ee5cbfSDavid du Colombier 		p = _ctlstrrune(e->text);
2789a747e4fSDavid du Colombier 		chanprint(e->event, e->format, e->name, p);
27980ee5cbfSDavid du Colombier 		free(p);
28080ee5cbfSDavid du Colombier 		return;
28180ee5cbfSDavid du Colombier 	case L'\b':
28280ee5cbfSDavid du Colombier 		if(e->cursor > 0){
28380ee5cbfSDavid du Colombier 			memmove(e->text+e->cursor-1, e->text+e->cursor,
28480ee5cbfSDavid du Colombier 				(e->ntext+1-e->cursor)*sizeof(Rune));
28580ee5cbfSDavid du Colombier 			e->cursor--;
28680ee5cbfSDavid du Colombier 			e->ntext--;
28780ee5cbfSDavid du Colombier 		}
28880ee5cbfSDavid du Colombier 		break;
289*42dedc50SDavid du Colombier 	case Kright:
290*42dedc50SDavid du Colombier 		if(e->cursor < e->ntext)
291*42dedc50SDavid du Colombier 			e->cursor++;
292*42dedc50SDavid du Colombier 		break;
293*42dedc50SDavid du Colombier 	case Kleft:
294*42dedc50SDavid du Colombier 		if(e->cursor > 0)
295*42dedc50SDavid du Colombier 			e->cursor--;
296*42dedc50SDavid du Colombier 		break;
297*42dedc50SDavid du Colombier 	case 0x01:	/* control A: beginning of line */
298*42dedc50SDavid du Colombier 		e->cursor = 0;
299*42dedc50SDavid du Colombier 		break;
300*42dedc50SDavid du Colombier 	case 0x05:	/* control E: end of line */
301*42dedc50SDavid du Colombier 		e->cursor = e->ntext;
302*42dedc50SDavid du Colombier 		break;
30380ee5cbfSDavid du Colombier 	case 0x15:	/* control U: kill line */
30480ee5cbfSDavid du Colombier 		e->cursor = 0;
30580ee5cbfSDavid du Colombier 		e->ntext = 0;
30680ee5cbfSDavid du Colombier 		break;
30780ee5cbfSDavid du Colombier 	case 0x16:	/* control V: paste (append snarf buffer) */
30880ee5cbfSDavid du Colombier 		s = _ctlgetsnarf();
30980ee5cbfSDavid du Colombier 		if(s != nil){
31080ee5cbfSDavid du Colombier 			n = runestrlen(s);
31180ee5cbfSDavid du Colombier 			e->text = ctlrealloc(e->text, (e->ntext+n+1)*sizeof(Rune));
31280ee5cbfSDavid du Colombier 			memmove(e->text+e->cursor+n, e->text+e->cursor,
31380ee5cbfSDavid du Colombier 				(e->ntext+1-e->cursor)*sizeof(Rune));
31480ee5cbfSDavid du Colombier 			memmove(e->text+e->cursor, s, n*sizeof(Rune));
31580ee5cbfSDavid du Colombier 			e->cursor += n;
31680ee5cbfSDavid du Colombier 			e->ntext += n;
31780ee5cbfSDavid du Colombier 		}
31880ee5cbfSDavid du Colombier 		break;
31980ee5cbfSDavid du Colombier 	}
32080ee5cbfSDavid du Colombier 	e->text[e->ntext] = L'\0';
32180ee5cbfSDavid du Colombier }
3229a747e4fSDavid du Colombier 
3239a747e4fSDavid du Colombier static void
entrykeys(Control * c,Rune * rp)3249a747e4fSDavid du Colombier entrykeys(Control *c, Rune *rp)
3259a747e4fSDavid du Colombier {
3269a747e4fSDavid du Colombier 	Entry *e;
3279a747e4fSDavid du Colombier 	int i;
3289a747e4fSDavid du Colombier 
3299a747e4fSDavid du Colombier 	e = (Entry *)c;
3309a747e4fSDavid du Colombier 	for(i=0; rp[i]!=L'\0'; i++)
3319a747e4fSDavid du Colombier 		entrykey(e, rp[i]);
3329a747e4fSDavid du Colombier 	entryshow(e);
3339a747e4fSDavid du Colombier }
3349a747e4fSDavid du Colombier 
3359a747e4fSDavid du Colombier Control*
createentry(Controlset * cs,char * name)3369a747e4fSDavid du Colombier createentry(Controlset *cs, char *name)
3379a747e4fSDavid du Colombier {
3389a747e4fSDavid du Colombier 	Entry *e;
3399a747e4fSDavid du Colombier 
3409a747e4fSDavid du Colombier 	e = (Entry*) _createctl(cs, "entry", sizeof(Entry), name);
3419a747e4fSDavid du Colombier 	e->text = ctlmalloc(sizeof(Rune));
3429a747e4fSDavid du Colombier 	e->ntext = 0;
3439a747e4fSDavid du Colombier 	e->image = _getctlimage("white");
3449a747e4fSDavid du Colombier 	e->textcolor = _getctlimage("black");
3459a747e4fSDavid du Colombier 	e->bordercolor = _getctlimage("black");
3469a747e4fSDavid du Colombier 	e->font = _getctlfont("font");
3479a747e4fSDavid du Colombier 	e->format = ctlstrdup("%q: value %q");
3489a747e4fSDavid du Colombier 	e->border = 0;
3499a747e4fSDavid du Colombier 	e->ctl = entryctl;
3509a747e4fSDavid du Colombier 	e->mouse = entrymouse;
3519a747e4fSDavid du Colombier 	e->key = entrykeys;
3529a747e4fSDavid du Colombier 	e->exit = entryfree;
3539a747e4fSDavid du Colombier 	return (Control *)e;
3549a747e4fSDavid du Colombier }
355