xref: /inferno-os/libtk/image.c (revision 0db9190e73bd2b1391b1108a354b8cf089ab5374)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include <kernel.h>
337da2899SCharles.Forsyth #include "draw.h"
437da2899SCharles.Forsyth #include "tk.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
737da2899SCharles.Forsyth 
837da2899SCharles.Forsyth char*	tkimgbmcreate(TkTop*, char*, int, char**);
937da2899SCharles.Forsyth char*	tkimgbmdel(TkImg*);
1037da2899SCharles.Forsyth void	tkimgbmfree(TkImg*);
1137da2899SCharles.Forsyth 
1237da2899SCharles.Forsyth static Rectangle huger = { -1000000, -1000000, 1000000, 1000000 };
1337da2899SCharles.Forsyth 
1437da2899SCharles.Forsyth typedef struct TkImgtype TkImgtype;
1537da2899SCharles.Forsyth struct TkImgtype
1637da2899SCharles.Forsyth {
1737da2899SCharles.Forsyth 	char*	type;
1837da2899SCharles.Forsyth 	char*	(*create)(TkTop*, char*, int, char**);
1937da2899SCharles.Forsyth 	char*	(*delete)(TkImg*);
2037da2899SCharles.Forsyth 	void	(*destroy)(TkImg*);
2137da2899SCharles.Forsyth } tkimgopts[] =
2237da2899SCharles.Forsyth {
2337da2899SCharles.Forsyth 	"bitmap",	tkimgbmcreate,		tkimgbmdel, 	tkimgbmfree,
2437da2899SCharles.Forsyth 	nil,
2537da2899SCharles.Forsyth };
2637da2899SCharles.Forsyth 
2737da2899SCharles.Forsyth typedef struct Imgargs Imgargs;
2837da2899SCharles.Forsyth struct Imgargs {
2937da2899SCharles.Forsyth 	Image*	fgimg;
3037da2899SCharles.Forsyth 	Image*	maskimg;
3137da2899SCharles.Forsyth };
3237da2899SCharles.Forsyth 
3337da2899SCharles.Forsyth TkImg*
tkname2img(TkTop * t,char * name)3437da2899SCharles.Forsyth tkname2img(TkTop *t, char *name)
3537da2899SCharles.Forsyth {
3637da2899SCharles.Forsyth 	TkImg *tki;
3737da2899SCharles.Forsyth 
3837da2899SCharles.Forsyth 	for(tki = t->imgs; tki; tki = tki->link)
3937da2899SCharles.Forsyth 		if((tki->name != nil) && strcmp(tki->name->name, name) == 0)
4037da2899SCharles.Forsyth 			return tki;
4137da2899SCharles.Forsyth 
4237da2899SCharles.Forsyth 	return nil;
4337da2899SCharles.Forsyth }
4437da2899SCharles.Forsyth 
4537da2899SCharles.Forsyth TkOption
4637da2899SCharles.Forsyth bitopt[] =
4737da2899SCharles.Forsyth {
4837da2899SCharles.Forsyth 	"file",		OPTbmap,	O(Imgargs, fgimg),	nil,
4937da2899SCharles.Forsyth 	"maskfile",	OPTbmap,	O(Imgargs, maskimg),	nil,
5037da2899SCharles.Forsyth 	nil
5137da2899SCharles.Forsyth };
5237da2899SCharles.Forsyth 
5337da2899SCharles.Forsyth void
tksizeimage(Tk * tk,TkImg * tki)5437da2899SCharles.Forsyth tksizeimage(Tk *tk, TkImg *tki)
5537da2899SCharles.Forsyth {
5637da2899SCharles.Forsyth 	int dx, dy, repack;
5737da2899SCharles.Forsyth 
5837da2899SCharles.Forsyth 	dx = 0;
5937da2899SCharles.Forsyth 	dy = 0;
6037da2899SCharles.Forsyth 	if(tki->img != nil) {
6137da2899SCharles.Forsyth 		dx = Dx(tki->img->r);
6237da2899SCharles.Forsyth 		dy = Dy(tki->img->r);
6337da2899SCharles.Forsyth 	}
6437da2899SCharles.Forsyth 	repack = 0;
6537da2899SCharles.Forsyth 	if(tki->ref > 1 && (tki->w != dx || tki->h != dy))
6637da2899SCharles.Forsyth 		repack = 1;
6737da2899SCharles.Forsyth 	tki->w = dx;
6837da2899SCharles.Forsyth 	tki->h = dy;
6937da2899SCharles.Forsyth 
7037da2899SCharles.Forsyth 	if(repack) {
7137da2899SCharles.Forsyth 		tkpackqit(tk);
7237da2899SCharles.Forsyth 		tkrunpack(tk->env->top);
7337da2899SCharles.Forsyth 	}
7437da2899SCharles.Forsyth }
7537da2899SCharles.Forsyth 
7637da2899SCharles.Forsyth char*
tkimgbmcreate(TkTop * t,char * arg,int type,char ** ret)7737da2899SCharles.Forsyth tkimgbmcreate(TkTop *t, char *arg, int type, char **ret)
7837da2899SCharles.Forsyth {
7937da2899SCharles.Forsyth 	TkName *names;
8037da2899SCharles.Forsyth 	TkImg *tki, *f;
8137da2899SCharles.Forsyth 	TkOptab tko[2];
8237da2899SCharles.Forsyth 	char buf[32];
8337da2899SCharles.Forsyth 	static int id;
8437da2899SCharles.Forsyth 	char *e = nil;
8537da2899SCharles.Forsyth 	Imgargs iargs;
8637da2899SCharles.Forsyth 	Rectangle r;
8737da2899SCharles.Forsyth 	Display *d;
8837da2899SCharles.Forsyth 	int chan;
8937da2899SCharles.Forsyth 	int locked;
9037da2899SCharles.Forsyth 
9137da2899SCharles.Forsyth 	d = t->display;
9237da2899SCharles.Forsyth 	locked = 0;
9337da2899SCharles.Forsyth 
9437da2899SCharles.Forsyth 	tki = malloc(sizeof(TkImg));
9537da2899SCharles.Forsyth 	if(tki == nil)
9637da2899SCharles.Forsyth 		return TkNomem;
9737da2899SCharles.Forsyth 
9837da2899SCharles.Forsyth 	tki->env = tkdefaultenv(t);
9937da2899SCharles.Forsyth 	if(tki->env == nil)
10037da2899SCharles.Forsyth 		goto err;
10137da2899SCharles.Forsyth 	tki->type = type;
10237da2899SCharles.Forsyth 	tki->ref = 1;
10337da2899SCharles.Forsyth 	tki->top = t;
10437da2899SCharles.Forsyth 
10537da2899SCharles.Forsyth 	iargs.fgimg = nil;
10637da2899SCharles.Forsyth 	iargs.maskimg = nil;
10737da2899SCharles.Forsyth 
10837da2899SCharles.Forsyth 	tko[0].ptr = &iargs;
10937da2899SCharles.Forsyth 	tko[0].optab = bitopt;
11037da2899SCharles.Forsyth 	tko[1].ptr = nil;
11137da2899SCharles.Forsyth 
11237da2899SCharles.Forsyth 	names = nil;
11337da2899SCharles.Forsyth 	e = tkparse(t, arg, tko, &names);
11437da2899SCharles.Forsyth 	if(e != nil)
11537da2899SCharles.Forsyth 		goto err;
11637da2899SCharles.Forsyth 
11737da2899SCharles.Forsyth 	if (iargs.fgimg == nil && iargs.maskimg != nil) {
11837da2899SCharles.Forsyth 		locked = lockdisplay(d);
11937da2899SCharles.Forsyth 		r = Rect(0, 0, Dx(iargs.maskimg->r), Dy(iargs.maskimg->r));
12037da2899SCharles.Forsyth 		tki->img = allocimage(d, r, CHAN2(CAlpha, 8, CGrey, 8), 0, DTransparent);
12137da2899SCharles.Forsyth 		if (tki->img != nil)
12237da2899SCharles.Forsyth 			draw(tki->img, r, nil, iargs.maskimg, iargs.maskimg->r.min);
12337da2899SCharles.Forsyth 		freeimage(iargs.maskimg);
12437da2899SCharles.Forsyth 
12537da2899SCharles.Forsyth 	} else if (iargs.fgimg != nil && iargs.maskimg != nil) {
12637da2899SCharles.Forsyth 		locked = lockdisplay(d);
12737da2899SCharles.Forsyth 		r = Rect(0, 0, Dx(iargs.fgimg->r), Dy(iargs.fgimg->r));
12837da2899SCharles.Forsyth 		if (tkchanhastype(iargs.fgimg->chan, CGrey))
12937da2899SCharles.Forsyth 			chan = CHAN2(CAlpha, 8, CGrey, 8);
13037da2899SCharles.Forsyth 		else
13137da2899SCharles.Forsyth 			chan = RGBA32;
13237da2899SCharles.Forsyth 		tki->img = allocimage(d, r, chan, 0, DTransparent);
13337da2899SCharles.Forsyth 		if (tki->img != nil)
13437da2899SCharles.Forsyth 			draw(tki->img, r, iargs.fgimg, iargs.maskimg, iargs.fgimg->r.min);
13537da2899SCharles.Forsyth 		freeimage(iargs.fgimg);
13637da2899SCharles.Forsyth 		freeimage(iargs.maskimg);
13737da2899SCharles.Forsyth 	} else {
13837da2899SCharles.Forsyth 		tki->img = iargs.fgimg;
13937da2899SCharles.Forsyth 	}
14037da2899SCharles.Forsyth 	if (locked)
14137da2899SCharles.Forsyth 		unlockdisplay(d);
14237da2899SCharles.Forsyth 
14337da2899SCharles.Forsyth 	if(names == nil) {
14437da2899SCharles.Forsyth 		sprint(buf, "image%d", id++);
14537da2899SCharles.Forsyth 		tki->name = tkmkname(buf);
14637da2899SCharles.Forsyth 		if(tki->name == nil)
14737da2899SCharles.Forsyth 			goto err;
14837da2899SCharles.Forsyth 	}
14937da2899SCharles.Forsyth 	else {
15037da2899SCharles.Forsyth 		/* XXX should mark as dirty any widgets using the named
15137da2899SCharles.Forsyth 		 * image - some notification scheme needs putting in place
15237da2899SCharles.Forsyth 		 */
15337da2899SCharles.Forsyth 		tki->name = names;
15437da2899SCharles.Forsyth 		tkfreename(names->link);
15537da2899SCharles.Forsyth 		names->link = nil;
15637da2899SCharles.Forsyth 	}
15737da2899SCharles.Forsyth 
15837da2899SCharles.Forsyth 	tksizeimage(t->root, tki);
15937da2899SCharles.Forsyth 
16037da2899SCharles.Forsyth 	if (tki->name != nil) {
16137da2899SCharles.Forsyth 		f = tkname2img(t, tki->name->name);
16237da2899SCharles.Forsyth 		if(f != nil)
16337da2899SCharles.Forsyth 			tkimgopts[f->type].delete(f);
16437da2899SCharles.Forsyth 	}
16537da2899SCharles.Forsyth 
16637da2899SCharles.Forsyth 	tki->link = t->imgs;
16737da2899SCharles.Forsyth 	t->imgs = tki;
16837da2899SCharles.Forsyth 
16937da2899SCharles.Forsyth 	if (tki->name != nil) {
17037da2899SCharles.Forsyth 		e = tkvalue(ret, "%s", tki->name->name);
17137da2899SCharles.Forsyth 		if(e == nil)
17237da2899SCharles.Forsyth 			return nil;
17337da2899SCharles.Forsyth 	}
17437da2899SCharles.Forsyth err:
17537da2899SCharles.Forsyth 	tkputenv(tki->env);
17637da2899SCharles.Forsyth 	if(tki->img != nil) {
17737da2899SCharles.Forsyth 		locked = lockdisplay(d);
17837da2899SCharles.Forsyth 		freeimage(tki->img);
17937da2899SCharles.Forsyth 		if (locked)
18037da2899SCharles.Forsyth 			unlockdisplay(d);
18137da2899SCharles.Forsyth 	}
18237da2899SCharles.Forsyth 	tkfreename(tki->name);
18337da2899SCharles.Forsyth 	free(tki);
18437da2899SCharles.Forsyth 	return e != nil ? e : TkNomem;
18537da2899SCharles.Forsyth }
18637da2899SCharles.Forsyth 
18737da2899SCharles.Forsyth char*
tkimgbmdel(TkImg * tki)18837da2899SCharles.Forsyth tkimgbmdel(TkImg *tki)
18937da2899SCharles.Forsyth {
19037da2899SCharles.Forsyth 	TkImg **l, *f;
19137da2899SCharles.Forsyth 
19237da2899SCharles.Forsyth 	l = &tki->top->imgs;
19337da2899SCharles.Forsyth 	for(f = *l; f; f = f->link) {
19437da2899SCharles.Forsyth 		if(f == tki) {
19537da2899SCharles.Forsyth 			*l = tki->link;
19637da2899SCharles.Forsyth 			tkimgput(tki);
19737da2899SCharles.Forsyth 			return nil;
19837da2899SCharles.Forsyth 		}
19937da2899SCharles.Forsyth 		l = &f->link;
20037da2899SCharles.Forsyth 	}
20137da2899SCharles.Forsyth 	return TkBadvl;
20237da2899SCharles.Forsyth }
20337da2899SCharles.Forsyth 
20437da2899SCharles.Forsyth void
tkimgbmfree(TkImg * tki)20537da2899SCharles.Forsyth tkimgbmfree(TkImg *tki)
20637da2899SCharles.Forsyth {
20737da2899SCharles.Forsyth 	int locked;
20837da2899SCharles.Forsyth 	Display *d;
20937da2899SCharles.Forsyth 
21037da2899SCharles.Forsyth 	d = tki->top->display;
21137da2899SCharles.Forsyth 	locked = lockdisplay(d);
21237da2899SCharles.Forsyth 	freeimage(tki->img);
21337da2899SCharles.Forsyth 	if(locked)
21437da2899SCharles.Forsyth 		unlockdisplay(d);
21537da2899SCharles.Forsyth 
21637da2899SCharles.Forsyth 	free(tki->cursor);
21737da2899SCharles.Forsyth 	tkfreename(tki->name);
21837da2899SCharles.Forsyth 	tkputenv(tki->env);
21937da2899SCharles.Forsyth 
22037da2899SCharles.Forsyth 	free(tki);
22137da2899SCharles.Forsyth }
22237da2899SCharles.Forsyth 
22337da2899SCharles.Forsyth char*
tkimage(TkTop * t,char * arg,char ** ret)22437da2899SCharles.Forsyth tkimage(TkTop *t, char *arg, char **ret)
22537da2899SCharles.Forsyth {
22637da2899SCharles.Forsyth 	int i;
22737da2899SCharles.Forsyth 	TkImg *tkim;
22837da2899SCharles.Forsyth 	char *fmt, *e, *buf, *cmd;
22937da2899SCharles.Forsyth 
23037da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
23137da2899SCharles.Forsyth 	if(buf == nil)
23237da2899SCharles.Forsyth 		return TkNomem;
23337da2899SCharles.Forsyth 	cmd = mallocz(Tkminitem, 0);
23437da2899SCharles.Forsyth 	if(cmd == nil) {
23537da2899SCharles.Forsyth 		free(buf);
23637da2899SCharles.Forsyth 		return TkNomem;
23737da2899SCharles.Forsyth 	}
23837da2899SCharles.Forsyth 
23937da2899SCharles.Forsyth 	arg = tkword(t, arg, cmd, cmd+Tkminitem, nil);
24037da2899SCharles.Forsyth 	if(strcmp(cmd, "create") == 0) {
24137da2899SCharles.Forsyth 		arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
24237da2899SCharles.Forsyth 		for(i = 0; tkimgopts[i].type != nil; i++)
24337da2899SCharles.Forsyth 			if(strcmp(buf, tkimgopts[i].type) == 0) {
24437da2899SCharles.Forsyth 				e = tkimgopts[i].create(t, arg, i, ret);
24537da2899SCharles.Forsyth 				goto ret;
24637da2899SCharles.Forsyth 			}
24737da2899SCharles.Forsyth 		e = TkBadvl;
24837da2899SCharles.Forsyth 		goto ret;
24937da2899SCharles.Forsyth 	}
25037da2899SCharles.Forsyth 	if(strcmp(cmd, "names") == 0) {
25137da2899SCharles.Forsyth 		fmt = "%s";
25237da2899SCharles.Forsyth 		for(tkim = t->imgs; tkim; tkim = tkim->link) {
25337da2899SCharles.Forsyth 		        if (tkim->name != nil) {
25437da2899SCharles.Forsyth 				e = tkvalue(ret, fmt, tkim->name->name);
25537da2899SCharles.Forsyth 				if(e != nil)
25637da2899SCharles.Forsyth 					goto ret;
25737da2899SCharles.Forsyth 			}
25837da2899SCharles.Forsyth 			fmt = " %s";
25937da2899SCharles.Forsyth 		}
26037da2899SCharles.Forsyth 		e = nil;
26137da2899SCharles.Forsyth 		goto ret;
26237da2899SCharles.Forsyth 	}
26337da2899SCharles.Forsyth 
26437da2899SCharles.Forsyth 	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
26537da2899SCharles.Forsyth 	tkim = tkname2img(t, buf);
26637da2899SCharles.Forsyth 	if(tkim == nil) {
26737da2899SCharles.Forsyth 		e = TkBadvl;
26837da2899SCharles.Forsyth 		goto ret;
26937da2899SCharles.Forsyth 	}
27037da2899SCharles.Forsyth 
27137da2899SCharles.Forsyth 	if(strcmp(cmd, "height") == 0) {
27237da2899SCharles.Forsyth 		e = tkvalue(ret, "%d", tkim->h);
27337da2899SCharles.Forsyth 		goto ret;
27437da2899SCharles.Forsyth 	}
27537da2899SCharles.Forsyth 	if(strcmp(cmd, "width") == 0) {
27637da2899SCharles.Forsyth 		e = tkvalue(ret, "%d", tkim->w);
27737da2899SCharles.Forsyth 		goto ret;
27837da2899SCharles.Forsyth 	}
27937da2899SCharles.Forsyth 	if(strcmp(cmd, "type") == 0) {
28037da2899SCharles.Forsyth 		e = tkvalue(ret, "%s", tkimgopts[tkim->type].type);
28137da2899SCharles.Forsyth 		goto ret;
28237da2899SCharles.Forsyth 	}
28337da2899SCharles.Forsyth 	if(strcmp(cmd, "delete") == 0) {
28437da2899SCharles.Forsyth 		for (;;) {
28537da2899SCharles.Forsyth 			e = tkimgopts[tkim->type].delete(tkim);
28637da2899SCharles.Forsyth 			if (e != nil)
28737da2899SCharles.Forsyth 				break;
28837da2899SCharles.Forsyth 			arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
28937da2899SCharles.Forsyth 			if (buf[0] == '\0')
29037da2899SCharles.Forsyth 				 break;
29137da2899SCharles.Forsyth 			tkim = tkname2img(t, buf);
29237da2899SCharles.Forsyth 			if (tkim == nil) {
29337da2899SCharles.Forsyth 				e = TkBadvl;
29437da2899SCharles.Forsyth 				break;
29537da2899SCharles.Forsyth 			}
29637da2899SCharles.Forsyth 		}
29737da2899SCharles.Forsyth 		goto ret;
29837da2899SCharles.Forsyth 	}
29937da2899SCharles.Forsyth 
30037da2899SCharles.Forsyth 	e = TkBadcm;
30137da2899SCharles.Forsyth ret:
30237da2899SCharles.Forsyth 	free(cmd);
30337da2899SCharles.Forsyth 	free(buf);
30437da2899SCharles.Forsyth 	return e;
30537da2899SCharles.Forsyth }
30637da2899SCharles.Forsyth 
30737da2899SCharles.Forsyth void
tkimgput(TkImg * tki)30837da2899SCharles.Forsyth tkimgput(TkImg *tki)
30937da2899SCharles.Forsyth {
31037da2899SCharles.Forsyth 	if(tki == nil)
31137da2899SCharles.Forsyth 		return;
31237da2899SCharles.Forsyth 
31337da2899SCharles.Forsyth 	if(--tki->ref > 0)
31437da2899SCharles.Forsyth 		return;
31537da2899SCharles.Forsyth 
31637da2899SCharles.Forsyth 	tkimgopts[tki->type].destroy(tki);
31737da2899SCharles.Forsyth }
31837da2899SCharles.Forsyth 
31937da2899SCharles.Forsyth TkImg*
tkauximage(TkTop * t,char * s,TkMemimage * m,int repl)320*0db9190eSforsyth tkauximage(TkTop *t, char* s, TkMemimage *m, int repl)
32137da2899SCharles.Forsyth {
32237da2899SCharles.Forsyth 	TkName *name;
32337da2899SCharles.Forsyth 	TkCtxt *c;
32437da2899SCharles.Forsyth 	TkImg *tki;
32537da2899SCharles.Forsyth 	Display *d;
32637da2899SCharles.Forsyth 	Image *i;
327*0db9190eSforsyth 	int locked, nbytes;
32837da2899SCharles.Forsyth 
32937da2899SCharles.Forsyth 	tki = tkname2img(t, s);
33037da2899SCharles.Forsyth 	if (tki != nil) {
33137da2899SCharles.Forsyth 		tki->ref++;
33237da2899SCharles.Forsyth 		return tki;
33337da2899SCharles.Forsyth 	}
33437da2899SCharles.Forsyth 
33537da2899SCharles.Forsyth 	name = tkmkname(s);
33637da2899SCharles.Forsyth 	if (name == nil)
33737da2899SCharles.Forsyth 		return nil;
338*0db9190eSforsyth 	tki = mallocz(sizeof(*tki), 1);
33937da2899SCharles.Forsyth 	if (tki == nil)
34037da2899SCharles.Forsyth 		goto err;
34137da2899SCharles.Forsyth 	tki->env = tkdefaultenv(t);
34237da2899SCharles.Forsyth 	if(tki->env == nil)
34337da2899SCharles.Forsyth 		goto err;
34437da2899SCharles.Forsyth 
34537da2899SCharles.Forsyth 	c = t->ctxt;
34637da2899SCharles.Forsyth 	d = c->display;
34737da2899SCharles.Forsyth 
348*0db9190eSforsyth 	nbytes = bytesperline(m->r, chantodepth(m->chans))*Dy(m->r);
34937da2899SCharles.Forsyth 	locked = lockdisplay(d);
350*0db9190eSforsyth 	i = allocimage(d, m->r, m->chans, repl, DTransparent);
35137da2899SCharles.Forsyth 	if (i != nil) {
352*0db9190eSforsyth 		if (loadimage(i, m->r, m->data, nbytes) != nbytes) {
35337da2899SCharles.Forsyth 			freeimage(i);
35437da2899SCharles.Forsyth 			i = nil;
35537da2899SCharles.Forsyth 		}
35637da2899SCharles.Forsyth 		if (repl)
357*0db9190eSforsyth 			replclipr(i, 1, huger);	/* TO DO: doesn't allocimage do this? */
35837da2899SCharles.Forsyth 	}
35937da2899SCharles.Forsyth 	if (locked)
36037da2899SCharles.Forsyth 		unlockdisplay(d);
36137da2899SCharles.Forsyth 	if (i == nil)
36237da2899SCharles.Forsyth 		goto err;
36337da2899SCharles.Forsyth 	tki->top = t;
36437da2899SCharles.Forsyth 	tki->ref = 2;	/* t->imgs ref and the ref we are returning */
36537da2899SCharles.Forsyth 	tki->type = 0;	/* bitmap */
366*0db9190eSforsyth 	tki->w = Dx(m->r);
367*0db9190eSforsyth 	tki->h = Dy(m->r);
36837da2899SCharles.Forsyth 	tki->img = i;
36937da2899SCharles.Forsyth 	tki->name = name;
37037da2899SCharles.Forsyth 	tki->link = t->imgs;
37137da2899SCharles.Forsyth 	t->imgs = tki;
37237da2899SCharles.Forsyth 	return tki;
37337da2899SCharles.Forsyth err:
37437da2899SCharles.Forsyth 	if (tki != nil) {
37537da2899SCharles.Forsyth 		tkputenv(tki->env);
37637da2899SCharles.Forsyth 		free(tki);
37737da2899SCharles.Forsyth 	}
37837da2899SCharles.Forsyth 	tkfreename(name);
37937da2899SCharles.Forsyth 	return nil;
38037da2899SCharles.Forsyth }
381