#include "lib9.h"#include <kernel.h>#include "draw.h"#include "tk.h" #define O(t, e) ((long)(&((t*)0)->e)) char* tkimgbmcreate(TkTop*, char*, int, char**);char* tkimgbmdel(TkImg*);void tkimgbmfree(TkImg*); static Rectangle huger = { -1000000, -1000000, 1000000, 1000000 }; typedef struct TkImgtype TkImgtype;struct TkImgtype{ char* type; char* (*create)(TkTop*, char*, int, char**); char* (*delete)(TkImg*); void (*destroy)(TkImg*);} tkimgopts[] = { "bitmap", tkimgbmcreate, tkimgbmdel, tkimgbmfree, nil,}; typedef struct Imgargs Imgargs;struct Imgargs { Image* fgimg; Image* maskimg;}; TkImg*tkname2img(TkTop *t, char *name){ TkImg *tki; for(tki = t->imgs; tki; tki = tki->link) if((tki->name != nil) && strcmp(tki->name->name, name) == 0) return tki; return nil;} TkOptionbitopt[] ={ "file", OPTbmap, O(Imgargs, fgimg), nil, "maskfile", OPTbmap, O(Imgargs, maskimg), nil, nil}; voidtksizeimage(Tk *tk, TkImg *tki){ int dx, dy, repack; dx = 0; dy = 0; if(tki->img != nil) { dx = Dx(tki->img->r); dy = Dy(tki->img->r); } repack = 0; if(tki->ref > 1 && (tki->w != dx || tki->h != dy)) repack = 1; tki->w = dx; tki->h = dy; if(repack) { tkpackqit(tk); tkrunpack(tk->env->top); }} char*tkimgbmcreate(TkTop *t, char *arg, int type, char **ret){ TkName *names; TkImg *tki, *f; TkOptab tko[2]; char buf[32]; static int id; char *e = nil; Imgargs iargs; Rectangle r; Display *d; int chan; int locked; d = t->display; locked = 0; tki = malloc(sizeof(TkImg)); if(tki == nil) return TkNomem; tki->env = tkdefaultenv(t); if(tki->env == nil) goto err; tki->type = type; tki->ref = 1; tki->top = t; iargs.fgimg = nil; iargs.maskimg = nil; tko[0].ptr = &iargs; tko[0].optab = bitopt; tko[1].ptr = nil; names = nil; e = tkparse(t, arg, tko, &names); if(e != nil) goto err; if (iargs.fgimg == nil && iargs.maskimg != nil) { locked = lockdisplay(d); r = Rect(0, 0, Dx(iargs.maskimg->r), Dy(iargs.maskimg->r)); tki->img = allocimage(d, r, CHAN2(CAlpha, 8, CGrey, 8), 0, DTransparent); if (tki->img != nil) draw(tki->img, r, nil, iargs.maskimg, iargs.maskimg->r.min); freeimage(iargs.maskimg); } else if (iargs.fgimg != nil && iargs.maskimg != nil) { locked = lockdisplay(d); r = Rect(0, 0, Dx(iargs.fgimg->r), Dy(iargs.fgimg->r)); if (tkchanhastype(iargs.fgimg->chan, CGrey)) chan = CHAN2(CAlpha, 8, CGrey, 8); else chan = RGBA32; tki->img = allocimage(d, r, chan, 0, DTransparent); if (tki->img != nil) draw(tki->img, r, iargs.fgimg, iargs.maskimg, iargs.fgimg->r.min); freeimage(iargs.fgimg); freeimage(iargs.maskimg); } else { tki->img = iargs.fgimg; } if (locked) unlockdisplay(d); if(names == nil) { sprint(buf, "image%d", id++); tki->name = tkmkname(buf); if(tki->name == nil) goto err; } else { /* XXX should mark as dirty any widgets using the named * image - some notification scheme needs putting in place */ tki->name = names; tkfreename(names->link); names->link = nil; } tksizeimage(t->root, tki); if (tki->name != nil) { f = tkname2img(t, tki->name->name); if(f != nil) tkimgopts[f->type].delete(f); } tki->link = t->imgs; t->imgs = tki; if (tki->name != nil) { e = tkvalue(ret, "%s", tki->name->name); if(e == nil) return nil; }err: tkputenv(tki->env); if(tki->img != nil) { locked = lockdisplay(d); freeimage(tki->img); if (locked) unlockdisplay(d); } tkfreename(tki->name); free(tki); return e != nil ? e : TkNomem;} char*tkimgbmdel(TkImg *tki){ TkImg **l, *f; l = &tki->top->imgs; for(f = *l; f; f = f->link) { if(f == tki) { *l = tki->link; tkimgput(tki); return nil; } l = &f->link; } return TkBadvl;} voidtkimgbmfree(TkImg *tki){ int locked; Display *d; d = tki->top->display; locked = lockdisplay(d); freeimage(tki->img); if(locked) unlockdisplay(d); free(tki->cursor); tkfreename(tki->name); tkputenv(tki->env); free(tki);} char*tkimage(TkTop *t, char *arg, char **ret){ int i; TkImg *tkim; char *fmt, *e, *buf, *cmd; /* Note - could actually allocate buf and cmd in one buffer - DBK */ buf = mallocz(Tkmaxitem, 0); if(buf == nil) return TkNomem; cmd = mallocz(Tkminitem, 0); if(cmd == nil) { free(buf); return TkNomem; } arg = tkword(t, arg, cmd, cmd+Tkminitem, nil); if(strcmp(cmd, "create") == 0) { arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); for(i = 0; tkimgopts[i].type != nil; i++) if(strcmp(buf, tkimgopts[i].type) == 0) { e = tkimgopts[i].create(t, arg, i, ret); goto ret; } e = TkBadvl; goto ret; } if(strcmp(cmd, "names") == 0) { fmt = "%s"; for(tkim = t->imgs; tkim; tkim = tkim->link) { if (tkim->name != nil) { e = tkvalue(ret, fmt, tkim->name->name); if(e != nil) goto ret; } fmt = " %s"; } e = nil; goto ret; } arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); tkim = tkname2img(t, buf); if(tkim == nil) { e = TkBadvl; goto ret; } if(strcmp(cmd, "height") == 0) { e = tkvalue(ret, "%d", tkim->h); goto ret; } if(strcmp(cmd, "width") == 0) { e = tkvalue(ret, "%d", tkim->w); goto ret; } if(strcmp(cmd, "type") == 0) { e = tkvalue(ret, "%s", tkimgopts[tkim->type].type); goto ret; } if(strcmp(cmd, "delete") == 0) { for (;;) { e = tkimgopts[tkim->type].delete(tkim); if (e != nil) break; arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); if (buf[0] == '\0') break; tkim = tkname2img(t, buf); if (tkim == nil) { e = TkBadvl; break; } } goto ret; } e = TkBadcm;ret: free(cmd); free(buf); return e;} voidtkimgput(TkImg *tki){ if(tki == nil) return; if(--tki->ref > 0) return; tkimgopts[tki->type].destroy(tki); } TkImg*tkauximage(TkTop *t, char* s, uchar* bytes, int nbytes, int chans, Rectangle r, int repl){ TkName *name; TkCtxt *c; TkImg *tki; Display *d; Image *i; int locked; tki = tkname2img(t, s); if (tki != nil) { tki->ref++; return tki; } name = tkmkname(s); if (name == nil) return nil; tki = mallocz(sizeof(*tki), 0); if (tki == nil) goto err; tki->env = tkdefaultenv(t); if(tki->env == nil) goto err; c = t->ctxt; d = c->display; locked = lockdisplay(d); i = allocimage(d, r, chans, repl, DTransparent); if (i != nil) { if (loadimage(i, r, bytes, nbytes) != nbytes) { freeimage(i); i = nil; } if (repl) replclipr(i, 1, huger); } if (locked) unlockdisplay(d); if (i == nil) goto err; tki->top = t; tki->ref = 2; /* t->imgs ref and the ref we are returning */ tki->type = 0; /* bitmap */ tki->w = Dx(r); tki->h = Dy(r); tki->img = i; tki->name = name; tki->link = t->imgs; t->imgs = tki; return tki;err: if (tki != nil) { tkputenv(tki->env); free(tki); } tkfreename(name); return nil;}
#include "lib9.h"
#include <kernel.h>
#include "draw.h"
#include "tk.h"
#define O(t, e) ((long)(&((t*)0)->e))
char* tkimgbmcreate(TkTop*, char*, int, char**);
char* tkimgbmdel(TkImg*);
void tkimgbmfree(TkImg*);
static Rectangle huger = { -1000000, -1000000, 1000000, 1000000 };
typedef struct TkImgtype TkImgtype;
struct TkImgtype
{
char* type;
char* (*create)(TkTop*, char*, int, char**);
char* (*delete)(TkImg*);
void (*destroy)(TkImg*);
} tkimgopts[] =
{
"bitmap", tkimgbmcreate, tkimgbmdel, tkimgbmfree,
nil,
};
typedef struct Imgargs Imgargs;
struct Imgargs {
Image* fgimg;
Image* maskimg;
};
TkImg*
tkname2img(TkTop *t, char *name)
{
TkImg *tki;
for(tki = t->imgs; tki; tki = tki->link)
if((tki->name != nil) && strcmp(tki->name->name, name) == 0)
return tki;
return nil;
}
TkOption
bitopt[] =
{
"file", OPTbmap, O(Imgargs, fgimg), nil,
"maskfile", OPTbmap, O(Imgargs, maskimg), nil,
nil
};
void
tksizeimage(Tk *tk, TkImg *tki)
{
int dx, dy, repack;
dx = 0;
dy = 0;
if(tki->img != nil) {
dx = Dx(tki->img->r);
dy = Dy(tki->img->r);
}
repack = 0;
if(tki->ref > 1 && (tki->w != dx || tki->h != dy))
repack = 1;
tki->w = dx;
tki->h = dy;
if(repack) {
tkpackqit(tk);
tkrunpack(tk->env->top);
}
}
char*
tkimgbmcreate(TkTop *t, char *arg, int type, char **ret)
{
TkName *names;
TkImg *tki, *f;
TkOptab tko[2];
char buf[32];
static int id;
char *e = nil;
Imgargs iargs;
Rectangle r;
Display *d;
int chan;
int locked;
d = t->display;
locked = 0;
tki = malloc(sizeof(TkImg));
if(tki == nil)
return TkNomem;
tki->env = tkdefaultenv(t);
if(tki->env == nil)
goto err;
tki->type = type;
tki->ref = 1;
tki->top = t;
iargs.fgimg = nil;
iargs.maskimg = nil;
tko[0].ptr = &iargs;
tko[0].optab = bitopt;
tko[1].ptr = nil;
names = nil;
e = tkparse(t, arg, tko, &names);
if(e != nil)
goto err;
if (iargs.fgimg == nil && iargs.maskimg != nil) {
locked = lockdisplay(d);
r = Rect(0, 0, Dx(iargs.maskimg->r), Dy(iargs.maskimg->r));
tki->img = allocimage(d, r, CHAN2(CAlpha, 8, CGrey, 8), 0, DTransparent);
if (tki->img != nil)
draw(tki->img, r, nil, iargs.maskimg, iargs.maskimg->r.min);
freeimage(iargs.maskimg);
} else if (iargs.fgimg != nil && iargs.maskimg != nil) {
locked = lockdisplay(d);
r = Rect(0, 0, Dx(iargs.fgimg->r), Dy(iargs.fgimg->r));
if (tkchanhastype(iargs.fgimg->chan, CGrey))
chan = CHAN2(CAlpha, 8, CGrey, 8);
else
chan = RGBA32;
tki->img = allocimage(d, r, chan, 0, DTransparent);
if (tki->img != nil)
draw(tki->img, r, iargs.fgimg, iargs.maskimg, iargs.fgimg->r.min);
freeimage(iargs.fgimg);
freeimage(iargs.maskimg);
} else {
tki->img = iargs.fgimg;
}
if (locked)
unlockdisplay(d);
if(names == nil) {
sprint(buf, "image%d", id++);
tki->name = tkmkname(buf);
if(tki->name == nil)
goto err;
}
else {
/* XXX should mark as dirty any widgets using the named
* image - some notification scheme needs putting in place
*/
tki->name = names;
tkfreename(names->link);
names->link = nil;
}
tksizeimage(t->root, tki);
if (tki->name != nil) {
f = tkname2img(t, tki->name->name);
if(f != nil)
tkimgopts[f->type].delete(f);
}
tki->link = t->imgs;
t->imgs = tki;
if (tki->name != nil) {
e = tkvalue(ret, "%s", tki->name->name);
if(e == nil)
return nil;
}
err:
tkputenv(tki->env);
if(tki->img != nil) {
locked = lockdisplay(d);
freeimage(tki->img);
if (locked)
unlockdisplay(d);
}
tkfreename(tki->name);
free(tki);
return e != nil ? e : TkNomem;
}
char*
tkimgbmdel(TkImg *tki)
{
TkImg **l, *f;
l = &tki->top->imgs;
for(f = *l; f; f = f->link) {
if(f == tki) {
*l = tki->link;
tkimgput(tki);
return nil;
}
l = &f->link;
}
return TkBadvl;
}
void
tkimgbmfree(TkImg *tki)
{
int locked;
Display *d;
d = tki->top->display;
locked = lockdisplay(d);
freeimage(tki->img);
if(locked)
unlockdisplay(d);
free(tki->cursor);
tkfreename(tki->name);
tkputenv(tki->env);
free(tki);
}
char*
tkimage(TkTop *t, char *arg, char **ret)
{
int i;
TkImg *tkim;
char *fmt, *e, *buf, *cmd;
/* Note - could actually allocate buf and cmd in one buffer - DBK */
buf = mallocz(Tkmaxitem, 0);
if(buf == nil)
return TkNomem;
cmd = mallocz(Tkminitem, 0);
if(cmd == nil) {
free(buf);
return TkNomem;
}
arg = tkword(t, arg, cmd, cmd+Tkminitem, nil);
if(strcmp(cmd, "create") == 0) {
arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
for(i = 0; tkimgopts[i].type != nil; i++)
if(strcmp(buf, tkimgopts[i].type) == 0) {
e = tkimgopts[i].create(t, arg, i, ret);
goto ret;
}
e = TkBadvl;
goto ret;
}
if(strcmp(cmd, "names") == 0) {
fmt = "%s";
for(tkim = t->imgs; tkim; tkim = tkim->link) {
if (tkim->name != nil) {
e = tkvalue(ret, fmt, tkim->name->name);
if(e != nil)
goto ret;
}
fmt = " %s";
}
e = nil;
goto ret;
}
arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
tkim = tkname2img(t, buf);
if(tkim == nil) {
e = TkBadvl;
goto ret;
}
if(strcmp(cmd, "height") == 0) {
e = tkvalue(ret, "%d", tkim->h);
goto ret;
}
if(strcmp(cmd, "width") == 0) {
e = tkvalue(ret, "%d", tkim->w);
goto ret;
}
if(strcmp(cmd, "type") == 0) {
e = tkvalue(ret, "%s", tkimgopts[tkim->type].type);
goto ret;
}
if(strcmp(cmd, "delete") == 0) {
for (;;) {
e = tkimgopts[tkim->type].delete(tkim);
if (e != nil)
break;
arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
if (buf[0] == '\0')
break;
tkim = tkname2img(t, buf);
if (tkim == nil) {
e = TkBadvl;
break;
}
}
goto ret;
}
e = TkBadcm;
ret:
free(cmd);
free(buf);
return e;
}
void
tkimgput(TkImg *tki)
{
if(tki == nil)
return;
if(--tki->ref > 0)
return;
tkimgopts[tki->type].destroy(tki);
}
TkImg*
tkauximage(TkTop *t, char* s, uchar* bytes, int nbytes, int chans, Rectangle r, int repl)
{
TkName *name;
TkCtxt *c;
TkImg *tki;
Display *d;
Image *i;
int locked;
tki = tkname2img(t, s);
if (tki != nil) {
tki->ref++;
return tki;
}
name = tkmkname(s);
if (name == nil)
return nil;
tki = mallocz(sizeof(*tki), 0);
if (tki == nil)
goto err;
tki->env = tkdefaultenv(t);
if(tki->env == nil)
goto err;
c = t->ctxt;
d = c->display;
locked = lockdisplay(d);
i = allocimage(d, r, chans, repl, DTransparent);
if (i != nil) {
if (loadimage(i, r, bytes, nbytes) != nbytes) {
freeimage(i);
i = nil;
}
if (repl)
replclipr(i, 1, huger);
}
if (locked)
unlockdisplay(d);
if (i == nil)
goto err;
tki->top = t;
tki->ref = 2; /* t->imgs ref and the ref we are returning */
tki->type = 0; /* bitmap */
tki->w = Dx(r);
tki->h = Dy(r);
tki->img = i;
tki->name = name;
tki->link = t->imgs;
t->imgs = tki;
return tki;
err:
if (tki != nil) {
tkputenv(tki->env);
free(tki);
}
tkfreename(name);
return nil;
}