ref: d209801c8cf1e45950557b9fcff09a826f6c6030
parent: e2ed803428d06da80c4c9c70acaab5e754bca3fd
author: phil9 <telephil9@gmail.com>
date: Fri Nov 19 16:18:52 EST 2021
fix image plumbing and implement showdata messages Plumb messages are received in a separate proc so we marshall them to the main thread through a dedicated channel. Image loading is then done in this main thread. In addition we now handle plumb message with a `showdata` action attribute. This is (poorly atm) done by saving the data to a temporary file which is deleted once the image is loaded. This needs to be changed to at least use ORCLOSE so that we are sure the temporary file is always deleted.
--- a/a.h
+++ b/a.h
@@ -12,4 +12,5 @@
void* erealloc(void*, ulong);
Image* eallocimage(int, int, ulong, int, ulong);
uchar* readfile(char*, int*);
+int writefile(char*, char*, int);
int fileformat(char*);
--- a/utils.c
+++ b/utils.c
@@ -67,6 +67,20 @@
}
int
+writefile(char *filename, char *data, int ndata)
+{
+ int fd;
+
+ fd = create(filename, OWRITE|OEXCL, 0600);
+ if(fd < 0)
+ return -1;
+ if(write(fd, data, ndata) != ndata)
+ return -1;
+ close(fd);
+ return 0;
+}
+
+int
fileformat(char *filename)
{
static struct {
--- a/view.c
+++ b/view.c
@@ -13,6 +13,7 @@
Emouse,
Eresize,
Ekeyboard,
+ Eplumb,
};
int mainstacksize=16384;
@@ -128,12 +129,13 @@
}
void
-plumbproc(void*)
+plumbproc(void *v)
{
Plumbmsg *m;
+ Channel *c;
int fd;
- char *a;
+ c = v;
threadsetname("plumbproc");
fd = plumbopen("image", OREAD);
if(fd < 0)
@@ -142,21 +144,47 @@
m = plumbrecv(fd);
if(m == nil)
sysfatal("plumbrecv: %r");
- a = plumblookup(m->attr, "action");
- if(a != nil && strncmp(a, "showdata", 8) == 0){
- fprint(2, "showdata: not implemented");
- }else{
- free(img);
- img = load(m->data);
- if(img == nil)
- sysfatal("load: %r");
- pos = subpt(ZP, img->r.min);
- redraw();
+ sendp(c, m);
+ }
+}
+
+/* FIXME: the whole temp file logic is bad and we risk
+ never deleting the file */
+void
+evtplumb(Plumbmsg *m)
+{
+ int rm;
+ char *a, *f;
+ Image *i;
+
+ rm = 0;
+ a = plumblookup(m->attr, "action");
+ if(a != nil && strncmp(a, "showdata", 8) == 0){
+ f = smprint("/tmp/view.%ld.%d", time(nil), getpid());
+ if(writefile(f, m->data, m->ndata) < 0){
+ fprint(2, "cannot write showdata: %r\n");
+ goto Err;
}
- plumbfree(m);
+ rm = 1;
+ }else{
+ f = strdup(m->data);
}
+ i = load(f);
+ if(i != nil){
+ freeimage(img);
+ img = i;
+ pos = subpt(ZP, img->r.min);
+ redraw();
+ }else
+ fprint(2, "cannot load plumbed image: %r"); /* XXX: visual report */
+Err:
+ plumbfree(m);
+ if(rm)
+ remove(f);
+ free(f);
}
+
void
evtresize(int new)
{
@@ -205,10 +233,13 @@
{
Mouse m;
Rune k;
+ Plumbmsg *pm;
+ Channel *plumbc;
Alt alts[] = {
{ nil, &m, CHANRCV },
{ nil, nil, CHANRCV },
{ nil, &k, CHANRCV },
+ { nil, &pm, CHANRCV },
{ nil, nil, CHANEND },
};
@@ -223,11 +254,14 @@
sysfatal("initmouse: %r");
if((kctl=initkeyboard(nil)) == nil)
sysfatal("initkeyboard: %r");
+ if((plumbc = chancreate(sizeof(Plumbmsg*), 0)) == nil)
+ sysfatal("chancreate: %r");
alts[Emouse].c = mctl->c;
alts[Eresize].c = mctl->resizec;
alts[Ekeyboard].c = kctl->c;
+ alts[Eplumb].c = plumbc;
initbg();
- proccreate(plumbproc, nil, 8192);
+ proccreate(plumbproc, plumbc, 8192);
img = load(*argv);
pos = subpt(ZP, img->r.min);
evtresize(0);
@@ -241,6 +275,9 @@
break;
case Ekeyboard:
evtkey(k);
+ break;
+ case Eplumb:
+ evtplumb(pm);
break;
}
}