shithub: view

Download patch

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;
 		}
 	}