summaryrefslogtreecommitdiff
path: root/libtk/image.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libtk/image.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libtk/image.c')
-rw-r--r--libtk/image.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/libtk/image.c b/libtk/image.c
new file mode 100644
index 00000000..3b256eb3
--- /dev/null
+++ b/libtk/image.c
@@ -0,0 +1,380 @@
+#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;
+}