#include #include #include #include #include #include #include #include <9p.h> #include #include "gui.h" #include "cook.h" typedef struct Icache Icache; struct Icache { Icache* next; Ref; Image* i; uchar* idata; int isize; long sum; }; static void xinit(Panel*); static void xterm(Panel*); static int xctl(Panel* p, char* ctl); static long xattrs(Panel* p, char* buf, long sz); static long xread(Panel* p, void* buf, long cnt, vlong off); static long xwrite(Panel* p, void* buf, long cnt, vlong off); static void xmouse(Panel* p, Cmouse* m, Channel* mc); static long xwriteall(Panel* p, void* buf, long cnt); static void xdraw(Panel* p, int ); Pops imageops = { .pref = "image:", .init = xinit, .term = xterm, .ctl = genctl, .attrs= xattrs, .read = xread, .write= xwrite, .draw = xdraw, .mouse = xmouse, .keyboard = genkeyboard, .writeall = xwriteall, }; Pops pageops = { .pref = "page:", .init = xinit, .term = xterm, .ctl = genctl, .attrs= xattrs, .read = xread, .write= xwrite, .draw = xdraw, .mouse = xmouse, .keyboard = genkeyboard, .writeall = xwriteall, }; static QLock imglck; static Icache* images; static Icache* ialloc(uchar* data, int isize) { long sum; int i; Icache* ic; static char*fname; Image* img; int fd; sum = 0; for (i = 0; i < isize; i++) sum += data[i]; qlock(&imglck); for (ic = images; ic != nil; ic = ic->next){ if (ic->sum == sum && ic->isize == isize && ic->ref > 0) if (memcmp(ic->idata, data, isize) == 0){ incref(ic); qunlock(&imglck); return ic; } } /* We use readimage(). This works for all images despite * changes in the image format and avoids repeating readimage here. */ if (fname == nil) fname = smprint("/tmp/omero.%d.img", getpid()); fd = create(fname, ORDWR|ORCLOSE, 0644); if (fd < 0){ edprint("image: %r\n"); qunlock(&imglck); return 0; } write(fd, data, isize); seek(fd, 0, 0); img = readimage(display, fd, 0); close(fd); if (img == nil) ic = nil; else { ic = emalloc9p(sizeof(*ic)); ic->ref = 1; ic->idata = emalloc9p(isize); memmove(ic->idata, data, isize); ic->isize = isize; ic->sum = sum; ic->next = images; ic->i = img; images = ic; } qunlock(&imglck); return ic; } static void iclose(Icache* ic) { Icache** icp; if (ic != nil && decref(ic) == 0){ qlock(&imglck); for (icp = &images; *icp != nil && *icp != ic; icp = &((*icp)->next)) ; assert(*icp == ic); *icp = ic->next; qunlock(&imglck); free(ic->idata); freeimage(ic->i); free(ic); } } static void xinit(Panel* p) { p->minsz = Pt(48,48); p->flags |= Pedit; if (!strncmp(p->name, "page:", 5)) p->wants = Pt(1,1); p->irect = Rect(0, 0, p->minsz.x, p->minsz.y); } static void xterm(Panel* p) { iclose(p->ic); p->ic = nil; } static void xdraw(Panel* p, int ) { Point pt; Icache* ic; if (hidden(p->file) || Dx(p->rect) <= 0 || Dy(p->rect) <= 0) return; if (ic = p->ic){ if (p->wants.x) pt = Pt(p->hoff,p->voff); else pt = ZP; pt = addpt(ic->i->r.min, pt); if (p->wants.x) draw(screen, p->rect, cols[BACK], nil, ZP); draw(screen, p->rect, ic->i, cols[BACK], pt); } else draw(screen, p->rect, cols[BACK], nil, ZP); if (p->flags&Ptag) drawtag(p, 0); } static long xread(Panel* p, void* buf, long cnt, vlong off) { if (p->ic != nil) return genreadbuf(buf, cnt, off, p->ic->idata, p->ic->isize); else return genreadbuf(buf, cnt, off, "", 0); } static long xwrite(Panel* , void* , long , vlong ) { // We have writeall. No write should reach us. fprint(2, "xwrite called for image\n"); abort(); return -1; } static long xwriteall(Panel* p, void* buf, long cnt) { Rectangle old; Icache* ic; if (cnt <= 0){ edprint("bad count to xwriteall\n"); return -1; } p->dfile->length = cnt; ic = p->ic; p->ic = ialloc(buf, cnt); if (p->ic == nil){ p->ic = ic; return -1; } if (ic && ic->i) old = ic->i->r; else old = Rect(0, 0, 48, 48); iclose(ic); p->voff = 0; if (!p->wants.x){ p->minsz.x = Dx(p->ic->i->r); p->minsz.y = Dy(p->ic->i->r); } if (!p->ic || !p->ic->i || eqrect(old, p->ic->i->r)){ xdraw(p, 0); flushimage(display, 1); } else { p->flags |= Predraw; resize(); } return cnt; } static long xattrs(Panel* p, char* str, long l) { char size[40]; seprint(size, size+sizeof(size), "size %11d %11d\n", Dx(p->rect), Dy(p->rect)); return sprintattrs(p, str, l, size); } static void ijump(Panel* p, Point pt) { int dy, dx; int diy, dix; if (pt.x < 0) pt.x = 0; if (pt.y < 0) pt.y = 0; dy = Dy(p->rect); diy= Dy(p->ic->i->r); dx = Dx(p->rect); dix= Dx(p->ic->i->r); p->voff = pt.y * diy / dy; p->hoff = pt.x * dix / dx; if (p->voff < 0) p->voff = 0; if (diy <= dy) p->voff = 0; else if (p->voff > diy - dy) p->voff = diy - dy ; if (p->hoff < 0) p->hoff = 0; if (dix <= dx) p->hoff = 0; else if (p->hoff > dix - dx) p->hoff = dix - dx; } static void xmouse(Panel* p, Cmouse* m, Channel* mc) { Point xy; if (!p->wants.x){ genmouse(p, m, mc); return; } if (m->buttons == 4){ recv(mc, m); if (!m->buttons){ event(p, "look %11d %s", strlen(p->name), p->name); return; } while(m->buttons & 4){ xy = subpt(m->xy, p->rect.min); ijump(p, xy); xdraw(p, 0); flushimage(display, 1); recv(mc, m); } while(m->buttons) recv(mc, m); } else if (m->buttons == 2){ if (cookclick(m, mc)) event(p, "exec %11d %s", strlen(p->name), p->name); } }