Plan 9 from Bell Labs’s /usr/web/sources/contrib/nemo/sys/src/cmd/omero/image.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <thread.h>
#include <fcall.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <9p.h>
#include <frame.h>
#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);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].