Commit Diff


commit - 6c4c5c5b959ec8a2e85510bdf85339582f638f36
commit + 05a4d855f167ae2d0d2c0ba0e386d933172b71ea
blob - a09de6689b2fdbbfe8bafef92e8889acb6123aee
blob + befccc32b975c549bda6627a4a2355012d6133a4
--- src/cmd/mkfile
+++ src/cmd/mkfile
@@ -4,7 +4,7 @@ TARG=`ls *.[cy] *.lx | egrep -v "\.tab\.c$|^x\." | sed
 
 <$PLAN9/src/mkmany
 
-BUGGERED='CVS|faces|factotum|lp|ip|mailfs|page|scat|upas|vncv|mnihongo|mpm|index|u9fs|secstore'
+BUGGERED='CVS|faces|factotum|lp|ip|mailfs|scat|upas|vncv|mnihongo|mpm|index|u9fs|secstore'
 DIRS=lex `ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"|egrep -v '^lex$'`
 
 <$PLAN9/src/mkdirs
blob - 319cfb68f62fdea12f42676ebe57bd7a5d1beafd
blob + 415db0384e2ff80873e5f4c6adc26cdeb50d87f7
--- src/cmd/page/filter.c
+++ src/cmd/page/filter.c
@@ -1,9 +1,9 @@
 #include <u.h>
 #include <libc.h>
 #include <draw.h>
-#include <cursor.h>
-#include <event.h>
+#include <thread.h>
 #include <bio.h>
+#include <cursor.h>
 #include "page.h"
 
 Document*
@@ -24,7 +24,7 @@ initfilt(Biobuf *b, int argc, char **argv, uchar *buf,
 	if(docopy){
 		if(pipe(p) < 0){
 			fprint(2, "pipe fails: %r\n");
-			exits("Epipe");
+			threadexits("Epipe");
 		}
 	}else{
 		p[0] = open("/dev/null", ORDWR);
@@ -35,27 +35,29 @@ initfilt(Biobuf *b, int argc, char **argv, uchar *buf,
 	switch(fork()){
 	case -1:
 		fprint(2, "fork fails: %r\n");
-		exits("Efork");
+		threadexits("Efork");
 	default:
-		close(p[1]);
+		close(p[0]);
 		if(docopy){
-			write(p[0], buf, nbuf);
+			write(p[1], buf, nbuf);
 			if(b)
 				while((n = Bread(b, xbuf, sizeof xbuf)) > 0)
-					write(p[0], xbuf, n);
+					write(p[1], xbuf, n);
 			else
 				while((n = read(stdinfd, xbuf, sizeof xbuf)) > 0)
-					write(p[0], xbuf, n);
+					write(p[1], xbuf, n);
 		}
-		close(p[0]);
+		close(p[1]);
 		waitpid();
 		break;
 	case 0:
-		close(p[0]);
-		dup(p[1], 0);
+		close(p[1]);
+		dup(p[0], 0);
 		dup(ofd, 1);
 		/* stderr shines through */
-		execl("/bin/rc", "rc", "-c", cmd, nil);
+		if(chatty)
+			fprint(2, "Execing '%s'\n", cmd);
+		execlp("rc", "rc", "-c", cmd, nil);
 		break;
 	}
 
@@ -81,7 +83,7 @@ initdvi(Biobuf *b, int argc, char **argv, uchar *buf, 
 	 */
 	if(b == nil){	/* standard input; spool to disk (ouch) */
 		fd = spooltodisk(buf, nbuf, &name);
-		sprint(fdbuf, "/fd/%d", fd);
+		sprint(fdbuf, "/dev/fd/%d", fd);
 		b = Bopen(fdbuf, OREAD);
 		if(b == nil){
 			fprint(2, "cannot open disk spool file\n");
blob - 9ce6f74c937fad14f88e4ac7ff44ebff141d0340
blob + e8b40d038c31804c24e0526f25cc48506f06cd7c
--- src/cmd/page/gfx.c
+++ src/cmd/page/gfx.c
@@ -5,14 +5,13 @@
 #include <u.h>
 #include <libc.h>
 #include <draw.h>
-#include <cursor.h>
-#include <event.h>
+#include <thread.h>
 #include <bio.h>
+#include <cursor.h>
 #include "page.h"
 
 typedef struct Convert	Convert;
 typedef struct GfxInfo	GfxInfo;
-typedef struct Graphic	Graphic;
 
 struct Convert {
 	char *name;
@@ -24,29 +23,6 @@ struct GfxInfo {
 	Graphic *g;
 };
 
-struct Graphic {
-	int type;
-	char *name;
-	uchar *buf;	/* if stdin */
-	int nbuf;
-};
-
-enum {
-	Ipic,
-	Itiff,
-	Ijpeg,
-	Igif,
-	Iinferno,
-	Ifax,
-	Icvt2pic,
-	Iplan9bm,
-	Iccittg4,
-	Ippm,
-	Ipng,
-	Iyuv,
-	Ibmp
-};
-
 /*
  * N.B. These commands need to read stdin if %a is replaced
  * with an empty string.
@@ -65,15 +41,14 @@ Convert cvt[] = {
 [Iccittg4]	{ "ccitt-g4",	"cat %a|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" },
 [Ipng]		{ "png",	"png -9 %a", "png -t9 %a" },
 [Iyuv]		{ "yuv",	"yuv -9 %a", "yuv -t9 %a"  },
-[Ibmp]		{ "bmp",	"bmp -9 %a", "bmp -t9 %a"  }
+[Ibmp]		{ "bmp",	"bmp -9 %a", "bmp -t9 %a"  },
 };
 
-static Image*	convert(Graphic*);
 static Image*	gfxdrawpage(Document *d, int page);
 static char*	gfxpagename(Document*, int);
-static int	spawnrc(char*, uchar*, int);
-static void	waitrc(void);
-static int	spawnpost(int);
+static int	spawnrc(char*, Graphic*);
+//static void	waitrc(void);
+//static int	spawnpost(int);
 static int	addpage(Document*, char*);
 static int	rmpage(Document*, int);
 static int	genaddpage(Document*, char*, uchar*, int);
@@ -202,12 +177,12 @@ genaddpage(Document *doc, char *name, uchar *buf, int 
 	else
 		g->type = Icvt2pic;
 
-	if(name)
+	if(name){
 		g->name = estrdup(name);
-	else{
+		g->fd = -1;
+	}else{
 		g->name = estrdup("stdin");	/* so it can be freed */
-		g->buf = buf;
-		g->nbuf = nbuf;
+		g->fd = stdinpipe(buf, nbuf);
 	}
 
 	if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name);
@@ -244,7 +219,7 @@ rmpage(Document *doc, int n)
 }
 
 
-static Image*
+Image*
 convert(Graphic *g)
 {
 	int fd;
@@ -253,25 +228,24 @@ convert(Graphic *g)
 	char *name, buf[1000];
 	Image *im;
 	int rcspawned = 0;
-	Waitmsg *w;
 
 	c = cvt[g->type];
 	if(c.cmd == nil) {
 		if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
-		if(g->buf == nil){	/* not stdin */
+		if(g->fd < 0){	/* not stdin */
 			fd = open(g->name, OREAD);
 			if(fd < 0) {
 				fprint(2, "cannot open file: %r\n");
 				wexits("open");
 			}
 		}else
-			fd = stdinpipe(g->buf, g->nbuf);	
+			fd = g->fd;
 	} else {
 		cmd = c.cmd;
 		if(truecolor && c.truecmd)
 			cmd = c.truecmd;
 
-		if(g->buf != nil)	/* is stdin */
+		if(g->fd >= 0)	/* is pipe */
 			name = "";
 		else
 			name = g->name;
@@ -281,7 +255,7 @@ convert(Graphic *g)
 		}
 		snprint(buf, sizeof buf, cmd, name);
 		if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name);
-		fd = spawnrc(buf, g->buf, g->nbuf);
+		fd = spawnrc(buf, g);
 		rcspawned++;
 		if(fd < 0) {
 			fprint(2, "cannot spawn converter: %r\n");
@@ -293,43 +267,31 @@ convert(Graphic *g)
 	if(im == nil) {
 		fprint(2, "warning: couldn't read image: %r\n");
 	}
-	close(fd);
 
-	/* for some reason rx doesn't work well with wait */
-	/* for some reason 3to1 exits on success with a non-null status of |3to1 */
-	if(rcspawned && g->type != Iccittg4) {
-		if((w=wait())!=nil && w->msg[0] && !strstr(w->msg, "3to1"))
-			fprint(2, "slave wait error: %s\n", w->msg);
-		free(w);
-	}
+	close(fd);
 	return im;
 }
 
 static int
-spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf)
+spawnrc(char *cmd, Graphic *g)
 {
 	int pfd[2];
-	int pid;
+	int fd[3];
 
 	if(chatty) fprint(2, "spawning(%s)...", cmd);
 
 	if(pipe(pfd) < 0)
 		return -1;
-	if((pid = fork()) < 0)
+
+	if(g->fd > 0)
+		fd[0] = dup(g->fd, -1);
+	else
+		fd[0] = open("/dev/null", OREAD);
+	fd[1] = pfd[1];
+	fd[2] = dup(2, -1);
+
+	if(threadspawnl(fd, "rc", "rc", "-c", cmd, nil) == -1)
 		return -1;
 
-	if(pid == 0) {
-		close(pfd[1]);
-		if(stdinbuf)
-			dup(stdinpipe(stdinbuf, nstdinbuf), 0);
-		else
-			dup(open("/dev/null", OREAD), 0);
-		dup(pfd[0], 1);
-		/*dup(pfd[0], 2); */
-		execl("/bin/rc", "rc", "-c", cmd, nil);
-		wexits("exec");
-	}
-	close(pfd[0]);
-	return pfd[1];
+	return pfd[0];
 }
-
blob - fd7337ec81d64f42f4c1ad3ebbc1574ab0d3aab0
blob + 8c0e1b59f6ec29847f7c7bdb404029c5064ebf9f
--- src/cmd/page/gs.c
+++ src/cmd/page/gs.c
@@ -7,9 +7,9 @@
 #include <u.h>
 #include <libc.h>
 #include <draw.h>
-#include <cursor.h>
-#include <event.h>
+#include <thread.h>
 #include <bio.h>
+#include <cursor.h>
 #include "page.h"
 
 static int gspid;	/* globals for atexit */
@@ -37,87 +37,41 @@ killgs(void)
 	postnote(PNPROC, gspid, "die yankee pig dog");
 }
 
-int
-spawnwriter(GSInfo *g, Biobuf *b)
+void
+spawnreader(void *cp)
 {
-	char buf[4096];
-	int n;
-	int fd;
+	int n, fd, pfd[2];
+	char buf[1024];
 
-	switch(fork()){
-	case -1:	return -1;
-	case 0:	break;
-	default:	return 0;
-	}
+	recv(cp, &fd);
 
-	Bseek(b, 0, 0);
-	fd = g->gsfd;
-	while((n = Bread(b, buf, sizeof buf)) > 0)
-		write(fd, buf, n);
-	fprint(fd, "(/fd/3) (w) file dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring flushfile\n");
-	_exits(0);
-	return -1;
-}
+	if(pipe(pfd)<0)
+		wexits("pipe failed");
 
-int
-spawnreader(int fd)
-{
-	int n, pfd[2];
-	char buf[1024];
+	send(cp, &pfd[1]);
 
-	if(pipe(pfd)<0)
-		return -1;
-	switch(fork()){
-	case -1:
-		return -1;
-	case 0:
-		break;
-	default:
-		close(pfd[0]);
-		return pfd[1];
+	while((n=read(pfd[0], buf, sizeof buf)) > 0) {
+		write(1, buf, n);
+		write(fd, buf, n);
 	}
 
-	close(pfd[1]);
-	switch(fork()){
-	case -1:
-		wexits("fork failed");
-	case 0:
-		while((n=read(fd, buf, sizeof buf)) > 0) {
-			write(1, buf, n);
-			write(pfd[0], buf, n);
-		}
-		break;
-	default:
-		while((n=read(pfd[0], buf, sizeof buf)) > 0) {
-			write(1, buf, n);
-			write(fd, buf, n);
-		}
-		break;
-	}
-	postnote(PNGROUP, getpid(), "i'm die-ing");
-	_exits(0);
-	return -1;
+	close(pfd[0]);
+	threadexits(0);
 }
 
 void
-spawnmonitor(int fd)
+spawnmonitor(void *cp)
 {
 	char buf[4096];
 	char *xbuf;
+	int fd;
 	int n;
 	int out;
 	int first;
 
-	switch(rfork(RFFDG|RFNOTEG|RFPROC)){
-	case -1:
-	default:
-		return;
+	recv(cp, &fd);
 
-	case 0:
-		break;
-	}
-
-	out = open("/dev/cons", OWRITE);
+	out = open("/dev/tty", OWRITE);
 	if(out < 0)
 		out = 2;
 
@@ -131,17 +85,19 @@ spawnmonitor(int fd)
 		write(out, xbuf, n);
 		alarm(500);
 	}
-	_exits(0);
+	threadexits(0);
 }
 
 int 
 spawngs(GSInfo *g, char *safer)
 {
+	Channel *cp;
 	char *args[16];
 	char tb[32], gb[32];
 	int i, nargs;
 	int devnull;
-	int stdinout[2];
+	int stdinp[2];
+	int stdoutp[2];
 	int dataout[2];
 	int errout[2];
 
@@ -153,15 +109,15 @@ spawngs(GSInfo *g, char *safer)
 	 * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout.
 	 * gs data output is written to fd 3, which is dataout.
 	 */
-	if(pipe(stdinout) < 0 || pipe(dataout)<0 || pipe(errout)<0)
+	if(pipe(stdinp)<0 || pipe(stdoutp)<0 || pipe(dataout)<0 || pipe(errout)<0)
 		return -1;
 
 	nargs = 0;
 	args[nargs++] = "gs";
 	args[nargs++] = "-dNOPAUSE";
-	args[nargs++] = safer;
-	args[nargs++] = "-sDEVICE=plan9";
-	args[nargs++] = "-sOutputFile=/fd/3";
+	args[nargs++] = "-dDELAYSAFER";
+	args[nargs++] = "-sDEVICE=bmp16m";
+	args[nargs++] = "-sOutputFile=/dev/fd/3";
 	args[nargs++] = "-dQUIET";
 	args[nargs++] = "-r100";
 	sprint(tb, "-dTextAlphaBits=%d", textbits);
@@ -175,9 +131,10 @@ spawngs(GSInfo *g, char *safer)
 
 	gspid = fork();
 	if(gspid == 0) {
-		close(stdinout[1]);
-		close(dataout[1]);
-		close(errout[1]);
+		close(stdinp[1]);
+		close(stdoutp[0]);
+		close(dataout[0]);
+		close(errout[0]);
 
 		/*
 		 * Horrible problem: we want to dup fd's 0-4 below,
@@ -189,36 +146,49 @@ spawngs(GSInfo *g, char *safer)
 		while((devnull = open("/dev/null", ORDWR)) < 5)
 			;
 
-		stdinout[0] = dup(stdinout[0], -1);
-		errout[0] = dup(errout[0], -1);
-		dataout[0] = dup(dataout[0], -1);
+		stdinp[0] = dup(stdinp[0], -1);
+		stdoutp[1] = dup(stdoutp[1], -1);
+		errout[1] = dup(errout[1], -1);
+		dataout[1] = dup(dataout[1], -1);
 
-		dup(stdinout[0], 0);
-		dup(errout[0], 1);
-		dup(devnull, 2);	/* never anything useful */
-		dup(dataout[0], 3);
-		dup(stdinout[0], 4);
+		dup(stdinp[0], 0);
+		dup(errout[1], 1);
+		dup(errout[1], devnull);	/* never anything useful */
+		dup(dataout[1], 3);
+		dup(stdoutp[1], 4);
 		for(i=5; i<20; i++)
 			close(i);
-		exec("/bin/gs", args);
+		execvp("gs", args);
 		wexits("exec");
 	}
-	close(stdinout[0]);
-	close(errout[0]);
-	close(dataout[0]);
+	close(stdinp[0]);
+	close(stdoutp[1]);
+	close(errout[1]);
+	close(dataout[1]);
 	atexit(killgs);
 
-	if(teegs)
-		stdinout[1] = spawnreader(stdinout[1]);
+	cp = chancreate(sizeof(int), 0);
+	if(teegs) {
+		proccreate(spawnreader, cp, mainstacksize);
+		send(cp, &stdoutp[0]);
+		recv(cp, &stdoutp[0]);
+	}
 
-	gsfd = g->gsfd = stdinout[1];
-	g->gsdfd = dataout[1];
+	gsfd = g->gsfd = stdinp[1];
 	g->gspid = gspid;
+	g->g.fd = dataout[0];
+	g->g.name = "gs pipe";
+	g->g.type = Ibmp;
 
-	spawnmonitor(errout[1]);
-	Binit(&g->gsrd, g->gsfd, OREAD);
+	proccreate(spawnmonitor, cp, mainstacksize);
+	send(cp, &errout[0]);
+	chanfree(cp);
 
-	gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n");
+	Binit(&g->gsrd, stdoutp[0], OREAD);
+
+	gscmd(g, "/PAGEOUT (/dev/fd/4) (w) file def\n");
+	if(!strcmp(safer, "-dSAFER"))
+		gscmd(g, ".setsafe\n");
 	gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
 	waitgs(g);
 
@@ -269,11 +239,14 @@ setdim(GSInfo *gs, Rectangle bbox, int ppi, int landsc
 	if(!Dx(bbox))
 		bbox = Rect(0, 0, 612, 792);	/* 8½×11 */
 
-	if(landscape)
-		pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
-	else
+	switch(landscape){
+	case 0:
 		pbox = bbox;
-
+		break;
+	default:
+		pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x);
+		break;
+	}
 	gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
 	gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
 	gscmd(gs, "currentdevice putdeviceprops pop\n");
@@ -305,10 +278,10 @@ waitgs(GSInfo *gs)
 	uchar buf[1024];
 	int n;
 
-/*	gscmd(gs, "(\\n**bstack\\n) print flush\n"); */
-/*	gscmd(gs, "stack flush\n"); */
-/*	gscmd(gs, "(**estack\\n) print flush\n"); */
-	gscmd(gs, "(\\n/*GO.SYSIN DD\\n) PAGE==\n"); */
+//	gscmd(gs, "(\\n**bstack\\n) print flush\n");
+//	gscmd(gs, "stack flush\n");
+//	gscmd(gs, "(**estack\\n) print flush\n");
+	gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n");
 
 	alarm(300*1000);
 	for(;;) {
blob - 0c4163ad001791e7c0c595976ad14d494efba6ee
blob + bcd02a8d2d57461d16e1cbc424fc2daf2d295b4c
--- src/cmd/page/mkfile
+++ src/cmd/page/mkfile
@@ -14,8 +14,18 @@ OFILES=\
 	util.$O\
 	view.$O\
 
+LIB=$PLAN9/lib/libdraw.a
+
+UPDATE=\
+	mkfile\
+	${OFILES:%.$O=%.c}\
+	pdfprolog.ps\
+	$HFILES\
+
 <$PLAN9/src/mkone
 
+BIN=$PLAN9/bin
+
 pdfprolog.c: pdfprolog.ps
 	cat pdfprolog.ps | sed 's/.*/"&\\n"/g' >pdfprolog.c
 
blob - 9f6816e23f6b7c9e18521d8f422ca0550aec3c67
blob + 96563c3d1663fb7ff179681f39344fa4df6c8533
--- src/cmd/page/nrotate.c
+++ src/cmd/page/nrotate.c
@@ -15,15 +15,15 @@
 #include <libc.h>
 #include <bio.h>
 #include <draw.h>
+#include <thread.h>
 #include <cursor.h>
-#include <event.h>
 #include "page.h"
 
 int ndraw = 0;
 
 enum {
 	Xaxis,
-	Yaxis
+	Yaxis,
 };
 
 static void reverse(Image*, Image*, int);
@@ -229,7 +229,7 @@ swapadjacent(Image *img, Image *tmp, int axis, int img
 	/*
 	 * r0 is the lower rectangle, while r1 is the upper one.
 	 */
-	draw(tmp, tmp->r, img, nil
+	draw(tmp, tmp->r, img, nil, 
 }
 
 void
blob - 4c76e03316c0139b1aba8da82a50ec685504238b
blob + 52c6eee3599bb5e6a246a68912d29b4cc12f9b22
--- src/cmd/page/page.c
+++ src/cmd/page/page.c
@@ -1,9 +1,10 @@
 #include <u.h>
 #include <libc.h>
 #include <draw.h>
-#include <cursor.h>
-#include <event.h>
+#include <thread.h>
+#include <thread.h>
 #include <bio.h>
+#include <cursor.h>
 #include "page.h"
 
 int resizing;
@@ -16,11 +17,46 @@ int ppi = 100;
 int teegs = 0;
 int truetoboundingbox;
 int textbits=4, gfxbits=4;
-int wctlfd = -1;
 int stdinfd;
 int truecolor;
 int imagemode;
+int notewatcher;
+int notegp;
 
+int
+watcher(void *v, char *x)
+{
+	USED(v);
+	if(strcmp(x, "die") != 0)
+		postnote(PNGROUP, notegp, x);
+	threadexitsall(0);
+	return 0;
+}
+
+int
+bell(void *u, char *x)
+{
+	if(x && strcmp(x, "hangup") == 0)
+		threadexitsall(0);
+
+	if(x && strstr(x, "die") == nil)
+		fprint(2, "postnote %d: %s\n", getpid(), x);
+
+	/* alarms come from the gs monitor */
+	if(x && strstr(x, "alarm")){
+		postnote(PNGROUP, getpid(), "die (gs error)");
+		postnote(PNPROC, notewatcher, "die (gs error)");
+	}
+
+	/* function mentions u so that it's in the stack trace */
+	if((u == nil || u != x) && doabort)
+		abort();
+
+/*	fprint(2, "exiting %d\n", getpid()); */
+	wexits("note");
+	return 0;
+}
+
 static int
 afmt(Fmt *fmt)
 {
@@ -37,14 +73,15 @@ void
 usage(void)
 {
 	fprint(2, "usage: page [-biRrw] [-p ppi] file...\n");
-	exits("usage");
+	wexits("usage");
 }
 
 void
-main(int argc, char **argv)
+threadmain(int argc, char **argv)
 {
 	Document *doc;
 	Biobuf *b;
+	char *basename = argv[0];
 	enum { Ninput = 16 };
 	uchar buf[Ninput+1];
 	int readstdin;
@@ -82,7 +119,7 @@ main(int argc, char **argv)
 		truetoboundingbox = 1;
 		break;
 	case 'w':
-		mknewwindow = 1;
+		fprint(2, "%s: -w has only the effect of -R X11 systems\n", basename);
 		resizing = 1;
 		break;
 	case 'i':
@@ -92,14 +129,30 @@ main(int argc, char **argv)
 		usage();
 	}ARGEND;
 
+	notegp = getpid();
+
+	switch(notewatcher = fork()){
+	case -1:
+		sysfatal("fork\n");
+		threadexitsall(0);
+	default:
+		break;
+	case 0:
+		atnotify(watcher, 1);
+		for(;;)
+			sleep(1000);
+		/* not reached */
+	}
+
 	rfork(RFNOTEG);
+	atnotify(bell, 1);
 
 	readstdin = 0;
 	if(imagemode == 0 && argc == 0){
 		readstdin = 1;
 		stdinfd = dup(0, -1);
 		close(0);
-		open("/dev/cons", OREAD);
+		open("/dev/tty", OREAD);
 	}
 
 	quotefmtinstall();
@@ -107,8 +160,9 @@ main(int argc, char **argv)
 
 	fmtinstall('R', Rfmt);
 	fmtinstall('P', Pfmt);
+	/*
 	if(mknewwindow)
-		newwin();
+		newwin(); */
 
 	if(readstdin){
 		b = nil;
@@ -179,5 +233,9 @@ main(int argc, char **argv)
 void
 wexits(char *s)
 {
-	exits(s);
+	if(s && *s && strcmp(s, "note") != 0 && mknewwindow)
+		sleep(10*1000);
+	postnote(PNPROC, notewatcher, "die");
+	postnote(PNGROUP, getpid(), "die");
+	threadexitsall(s);
 }
blob - be54e3867f9c0d88b66cd3e01472f903ec3ae5e0
blob + 7e6c526eb1b4d54353876983c54b5f7846a3d36e
--- src/cmd/page/page.h
+++ src/cmd/page/page.h
@@ -1,3 +1,5 @@
+#undef pipe
+
 typedef struct Document Document;
 
 struct Document {
@@ -12,6 +14,31 @@ struct Document {
 	void *extra;
 };
 
+typedef struct Graphic	Graphic;
+
+struct Graphic {
+	int type;
+	int fd;
+	char *name;
+};
+
+enum {
+	Ipic,
+	Itiff,
+	Ijpeg,
+	Igif,
+	Iinferno,
+	Ifax,
+	Icvt2pic,
+	Iplan9bm,
+	Iccittg4,
+	Ippm,
+	Ipng,
+	Iyuv,
+	Ibmp,
+};
+
+
 void *emalloc(int);
 void *erealloc(void*, int);
 char *estrdup(char*);
@@ -48,10 +75,10 @@ Image *resample(Image*, Image*);
 /* ghostscript interface shared by ps, pdf */
 typedef struct GSInfo	GSInfo;
 struct GSInfo {
+	Graphic g;
 	int gsfd;
 	Biobuf gsrd;
 	int gspid;
-	int gsdfd;
 	int ppi;
 };
 void	waitgs(GSInfo*);
@@ -70,6 +97,7 @@ void	wexits(char*);
 Image*	xallocimage(Display*, Rectangle, ulong, int, ulong);
 int	bell(void*, char*);
 int	opentemp(char *template);
+Image*	convert(Graphic *g);
 
 extern int stdinfd;
 extern int truecolor;
blob - d723ad8c56800289a78fa0fd45ec93eb39beb98b
blob + 77c888522e45175291de991236f3d27d51423c91
--- src/cmd/page/pdf.c
+++ src/cmd/page/pdf.c
@@ -8,7 +8,7 @@
 #include <libc.h>
 #include <draw.h>
 #include <cursor.h>
-#include <event.h>
+#include <thread.h>
 #include <bio.h>
 #include "page.h"
 
@@ -66,7 +66,7 @@ initpdf(Biobuf *b, int argc, char **argv, uchar *buf, 
 	fprint(2, "reading through pdf...\n");
 	if(b == nil){	/* standard input; spool to disk (ouch) */
 		fd = spooltodisk(buf, nbuf, &fn);
-		sprint(fdbuf, "/fd/%d", fd);
+		sprint(fdbuf, "/dev/fd/%d", fd);
 		b = Bopen(fdbuf, OREAD);
 		if(b == nil){
 			fprint(2, "cannot open disk spool file\n");
@@ -122,7 +122,7 @@ initpdf(Biobuf *b, int argc, char **argv, uchar *buf, 
 	pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
 	for(i=0; i<npage; i++) {
 		gscmd(&pdf->gs, "%d pdfgetpage\n", i+1);
-		pdf->pagebbox[i] = pdfbbox(pdf);
+		pdf->pagebbox[i] = pdfbbox(&pdf->gs);
 		if(Dx(pdf->pagebbox[i]) <= 0)
 			pdf->pagebbox[i] = bbox;
 	}
@@ -136,7 +136,7 @@ pdfdrawpage(Document *doc, int page)
 	Image *im;
 
 	gscmd(&pdf->gs, "%d DoPDFPage\n", page+1);
-	im = readimage(display, pdf->gs.gsdfd, 0);
+	im = convert(&pdf->gs.g);
 	if(im == nil) {
 		fprint(2, "fatal: readimage error %r\n");
 		wexits("readimage");
blob - 8493e6d2ad7e09b69d6fef6eb583031b12399402
blob + de51c062ac92faa62e7054789c5833571fd4ea20
--- src/cmd/page/pdfprolog.c
+++ src/cmd/page/pdfprolog.c
@@ -2,28 +2,19 @@
 "/Page# 0 def\n"
 "/PDFSave null def\n"
 "/DSCPageCount 0 def\n"
-"/DoPDFPage {dup /Page# exch store pdfgetpage mypdfshowpage } def\n"
+"/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def\n"
 "\n"
 "/pdfshowpage_mysetpage {	% <pagedict> pdfshowpage_mysetpage <pagedict>\n"
 "  dup /CropBox pget {\n"
 "      boxrect\n"
 "      2 array astore /PageSize exch 4 2 roll\n"
-"      neg exch neg exch 2 array astore /PageOffset exch\n"
+"      4 index /Rotate pget {\n"
+"        dup 0 lt {360 add} if 90 idiv {exch neg} repeat\n"
+"      } if\n"
+"      exch neg exch 2 array astore /PageOffset exch\n"
 "      << 5 1 roll >> setpagedevice\n"
 "  } if\n"
 "} bind def\n"
 "\n"
-"/mypdfshowpage		% <pagedict> pdfshowpage -\n"
-" { dup /Page exch store\n"
-"   pdfshowpage_init \n"
-"   pdfshowpage_setpage \n"
-"   pdfshowpage_mysetpage\n"
-"   save /PDFSave exch store\n"
-"   (before exec) VMDEBUG\n"
-"     pdfshowpage_finish\n"
-"   (after exec) VMDEBUG\n"
-"   PDFSave restore\n"
-" } bind def\n"
-"\n"
 "GS_PDF_ProcSet begin\n"
 "pdfdict begin\n"
blob - c4c31c923a94314567f8e1f1ea977858bbcbd3ce
blob + 681e0587a709e20412700a85bd7378e79d161536
--- src/cmd/page/pdfprolog.ps
+++ src/cmd/page/pdfprolog.ps
@@ -2,28 +2,19 @@
 /Page# 0 def
 /PDFSave null def
 /DSCPageCount 0 def
-/DoPDFPage {dup /Page# exch store pdfgetpage mypdfshowpage } def
+/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def
 
 /pdfshowpage_mysetpage {	% <pagedict> pdfshowpage_mysetpage <pagedict>
   dup /CropBox pget {
       boxrect
       2 array astore /PageSize exch 4 2 roll
-      neg exch neg exch 2 array astore /PageOffset exch
+      4 index /Rotate pget {
+        dup 0 lt {360 add} if 90 idiv {exch neg} repeat
+      } if
+      exch neg exch 2 array astore /PageOffset exch
       << 5 1 roll >> setpagedevice
   } if
 } bind def
 
-/mypdfshowpage		% <pagedict> pdfshowpage -
- { dup /Page exch store
-   pdfshowpage_init 
-   pdfshowpage_setpage 
-   pdfshowpage_mysetpage
-   save /PDFSave exch store
-   (before exec) VMDEBUG
-     pdfshowpage_finish
-   (after exec) VMDEBUG
-   PDFSave restore
- } bind def
-
 GS_PDF_ProcSet begin
 pdfdict begin
blob - cc6f3c513f9c5054cfafafa7c621685bdeec54d6
blob + 4b678dc383958f71bbab5d5d63878639ccb93fd5
--- src/cmd/page/ps.c
+++ src/cmd/page/ps.c
@@ -8,7 +8,7 @@
 #include <libc.h>
 #include <draw.h>
 #include <cursor.h>
-#include <event.h>
+#include <thread.h>
 #include <bio.h>
 #include <ctype.h>
 #include "page.h"
@@ -158,7 +158,7 @@ initps(Biobuf *b, int argc, char **argv, uchar *buf, i
 	fprint(2, "reading through postscript...\n");
 	if(b == nil){	/* standard input; spool to disk (ouch) */
 		fd = spooltodisk(buf, nbuf, nil);
-		sprint(fdbuf, "/fd/%d", fd);
+		sprint(fdbuf, "/dev/fd/%d", fd);
 		b = Bopen(fdbuf, OREAD);
 		if(b == nil){
 			fprint(2, "cannot open disk spool file\n");
@@ -367,7 +367,7 @@ Keepreading:
 
 	if(dumb) {
 		fprint(ps->gs.gsfd, "(%s) run\n", argv[0]);
-		fprint(ps->gs.gsfd, "(/fd/3) (w) file dup (THIS IS NOT A PLAN9 BITMAP 01234567890123456789012345678901234567890123456789\\n) writestring flushfile\n");
+		fprint(ps->gs.gsfd, "(/dev/fd/3) (w) file dup (THIS IS NOT A PLAN9 BITMAP 01234567890123456789012345678901234567890123456789\\n) writestring flushfile\n");
 	}
 
 	ps->bbox = bbox;
@@ -417,7 +417,7 @@ psdrawpage(Document *d, int page)
 	Image *im;
 
 	if(ps->clueless)
-		return readimage(display, ps->gs.gsdfd, 0);
+		return convert(&ps->gs.g);
 
 	waitgs(&ps->gs);
 
@@ -433,7 +433,7 @@ psdrawpage(Document *d, int page)
 	 * so send one to avoid deadlock.
 	 */
 	write(ps->gs.gsfd, "\n", 1);
-	im = readimage(display, ps->gs.gsdfd, 0);
+	im = convert(&ps->gs.g);
 	if(im == nil) {
 		fprint(2, "fatal: readimage error %r\n");
 		wexits("readimage");
blob - fc13059bf22d7933eaa170e00c30621ad3814cac
blob + 4808734813f2d0331008b816be7f3ab29271a210
--- src/cmd/page/rotate.c
+++ src/cmd/page/rotate.c
@@ -15,14 +15,14 @@
 #include <libc.h>
 #include <bio.h>
 #include <draw.h>
+#include <thread.h>
 #include <cursor.h>
-#include <event.h>
 #include "page.h"
 
 int ndraw = 0;
 enum {
 	Xaxis = 0,
-	Yaxis = 1
+	Yaxis = 1,
 };
 
 Image *mtmp;
@@ -55,7 +55,6 @@ moveup(Image *im, Image *tmp, int a, int b, int c, int
 	drawop(tmp, tmp->r, im, nil, im->r.min, S);
 
 	switch(axis){
-	default:
 	case Xaxis:
 		range = Rect(a, im->r.min.y,  c, im->r.max.y);
 		dr0 = range;
@@ -67,6 +66,7 @@ moveup(Image *im, Image *tmp, int a, int b, int c, int
 		p1 = Pt(a, im->r.min.y);
 		break;
 	case Yaxis:
+	default:
 		range = Rect(im->r.min.x, a,  im->r.max.x, c);
 		dr0 = range;
 		dr0.max.y = dr0.min.y+(c-b);
@@ -90,7 +90,6 @@ interlace(Image *im, Image *tmp, int axis, int n, Imag
 	r0 = im->r;
 	r1 = im->r;
 	switch(axis) {
-	default:
 	case Xaxis:
 		r0.max.x = n;
 		r1.min.x = n;
@@ -98,6 +97,7 @@ interlace(Image *im, Image *tmp, int axis, int n, Imag
 		p1 = (Point){-gran, 0};
 		break;
 	case Yaxis:
+	default:
 		r0.max.y = n;
 		r1.min.y = n;
 		p0 = (Point){0, gran};
@@ -132,12 +132,12 @@ interlace(Image *im, Image *tmp, int axis, int n, Imag
 int
 nextmask(Image *mask, int axis, int maskdim)
 {
-	Point delta;
+	Point o;
 
-	delta = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim);
+	o = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim);
 	drawop(mtmp, mtmp->r, mask, nil, mask->r.min, S);
-	gendrawop(mask, mask->r, mtmp, delta, mtmp, divpt(delta,-2), S);
-/*	writefile("mask", mask, maskdim/2); */
+	gendrawop(mask, mask->r, mtmp, o, mtmp, divpt(o,-2), S);
+//	writefile("mask", mask, maskdim/2);
 	return maskdim/2;
 }
 
@@ -153,13 +153,13 @@ shuffle(Image *im, Image *tmp, int axis, int n, Image 
 	nn = n - left;
 
 	interlace(im, tmp, axis, nn, mask, gran);
-/*	writefile("interlace", im, gran); */
+//	writefile("interlace", im, gran);
 	
 	gran = nextmask(mask, axis, gran);
 	shuffle(im, tmp, axis, n, mask, gran, nn);
-/*	writefile("shuffle", im, gran); */
+//	writefile("shuffle", im, gran);
 	moveup(im, tmp, lastnn, nn, n, axis);
-/*	writefile("move", im, gran); */
+//	writefile("move", im, gran);
 }
 
 void
@@ -198,7 +198,7 @@ rot180(Image *im)
 	}
 	rmask.max.x = gran;
 	drawop(mask, rmask, display->opaque, nil, ZP, S);
-/*	writefile("mask", mask, gran); */
+//	writefile("mask", mask, gran);
 	shuffle(im, tmp, Xaxis, Dx(im->r), mask, gran, 0);
 	freeimage(mask);
 	freeimage(mtmp);
@@ -309,11 +309,11 @@ i0(double x)
 }
 
 double
-kaiser(double x, double tau, double alpha)
+kaiser(double x, double t, double a)
 {
-	if(fabs(x) > tau)
+	if(fabs(x) > t)
 		return 0.;
-	return i0(alpha*sqrt(1-(x*x/(tau*tau))))/i0(alpha);
+	return i0(a*sqrt(1-(x*x/(t*t))))/i0(a);
 }
 
 
blob - 2669df84689bd26ec905b8a622fe639be18af716
blob + 1f6fdeffddae8ed83822daf6aa8b50b7833e9b34
--- src/cmd/page/util.c
+++ src/cmd/page/util.c
@@ -1,9 +1,9 @@
 #include <u.h>
 #include <libc.h>
 #include <draw.h>
-#include <cursor.h>
-#include <event.h>
+#include <thread.h>
 #include <bio.h>
+#include <cursor.h>
 #include "page.h"
 
 void*
@@ -41,30 +41,6 @@ estrdup(char *s)
 	return t;
 }
 
-int
-opentemp(char *template)
-{
-	int fd, i;
-	char *p;
-
-	p = estrdup(template);
-	fd = -1;
-	for(i=0; i<10; i++){
-		mktemp(p);
-		if(access(p, 0) < 0 && (fd=create(p, ORDWR|ORCLOSE, 0400)) >= 0)
-			break;
-		strcpy(p, template);
-	}
-	if(fd < 0){
-		fprint(2, "couldn't make temporary file\n");
-		wexits("Ecreat");
-	}
-	strcpy(template, p);
-	free(p);
-
-	return fd;
-}
-
 /*
  * spool standard input to /tmp.
  * we've already read the initial in bytes into ibuf.
@@ -96,37 +72,54 @@ spooltodisk(uchar *ibuf, int in, char **name)
 	return fd;
 }
 
+typedef struct StdinArg StdinArg;
+
+struct StdinArg {
+	Channel *cp;
+	uchar	*ibuf;
+	int	in;
+};
+
 /*
  * spool standard input into a pipe.
  * we've already ready the first in bytes into ibuf
  */
-int
-stdinpipe(uchar *ibuf, int in)
+static void
+_stdinpipe(void *a)
 {
 	uchar buf[8192];
-	int n;
+	StdinArg *arg;
 	int p[2];
+	int n;
+
+	arg = a;
+
 	if(pipe(p) < 0){
 		fprint(2, "pipe fails: %r\n");	
 		wexits("pipe");
 	}
 
-	switch(rfork(RFPROC|RFFDG)){
-	case -1:
-		fprint(2, "fork fails: %r\n");
-		wexits("fork");
-	default:
-		close(p[1]);
-		return p[0];
-	case 0:
-		break;
-	}
+	send(arg->cp, &p[0]);
 
-	close(p[0]);
-	write(p[1], ibuf, in);
+	write(p[1], arg->ibuf, arg->in);
 	while((n = read(stdinfd, buf, sizeof buf)) > 0)
 		write(p[1], buf, n);
+	
+	close(p[1]);
+	threadexits(0);
+}
 
-	_exits(0);
-	return -1;	/* not reached */
+int
+stdinpipe(uchar *ibuf, int in) {
+	StdinArg arg;
+	int fd;
+
+	arg.ibuf = ibuf;
+	arg.in = in;
+	arg.cp = chancreate(sizeof(int), 0);
+	proccreate(_stdinpipe, &arg, mainstacksize);
+	recv(arg.cp, &fd);
+	chanfree(arg.cp);
+
+	return fd;
 }
blob - 1cdb254144026a863b5a0b3394c4108b97d8f128
blob + ab409cc7920702da8cd8f8f2f26cbbfcfba9fc3f
--- src/cmd/page/view.c
+++ src/cmd/page/view.c
@@ -4,17 +4,19 @@
 
 #include <u.h>
 #include <libc.h>
+#include <9pclient.h>
 #include <draw.h>
 #include <cursor.h>
-#include <cursor.h>
-#include <event.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <thread.h>
 #include <bio.h>
 #include <plumb.h>
 #include <ctype.h>
-#include <keyboard.h>
 #include "page.h"
 
 Document *doc;
+Mousectl *mc;
 Image *im;
 int page;
 int angle = 0;
@@ -26,6 +28,7 @@ Point ul;			/* the upper left corner of the image is a
 Point pclip(Point, Rectangle);
 Rectangle mkrange(Rectangle screenr, Rectangle imr);
 void redraw(Image*);
+void plumbproc(void*);
 
 Cursor reading={
 	{-1, -1},
@@ -56,20 +59,13 @@ enum {
 	Middle = 2,
 	Right = 4,
 
-	RMenu = 3
+	RMenu = 3,
 };
 
 void
 unhide(void)
 {
-	static int wctl = -1;
-
-	if(wctl < 0)
-		wctl = open("/dev/wctl", OWRITE);
-	if(wctl < 0)
-		return;
-
-	write(wctl, "unhide", 6);
+	USED(nil);
 }
 
 int 
@@ -126,7 +122,7 @@ showpage(int page, Menu *m)
 	else
 		m->lasthit = reverse ? doc->npage-1-page : page;
 	
-	esetcursor(&reading);
+	setcursor(mc, &reading);
 	freeimage(im);
 	if((page < 0 || page >= doc->npage) && !doc->fwdonly){
 		im = nil;
@@ -169,7 +165,7 @@ showpage(int page, Menu *m)
 		break;
 	}
 
-	esetcursor(nil);
+	setcursor(mc, nil);
 	if(showbottom){
 		ul.y = screen->r.max.y - Dy(im->r);
 		showbottom = 0;
@@ -186,7 +182,7 @@ writebitmap(void)
 	char name[64+30];
 	static char result[200];
 	char *p, *q;
-	int fd;
+	int fd = -1;
 
 	if(im == nil)
 		return "no image";
@@ -209,18 +205,18 @@ writebitmap(void)
 		snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1);
 		if(access(name, 0) >= 0) {
 			strcat(name, "XXXX");
-			mktemp(name);
+			fd = mkstemp(name);
 		}
-		if(access(name, 0) >= 0)
+		if(fd < 0)
 			return "couldn't think of a name for bitmap";
 	} else {
 		strcpy(name, "bitXXXX");
-		mktemp(name);
-		if(access(name, 0) >= 0) 
+		mkstemp(name);
+		if(fd < 0)
 			return "couldn't think of a name for bitmap";
 	}
 
-	if((fd = create(name, OWRITE, 0666)) < 0) {
+	if(fd < 0) {
 		snprint(result, sizeof result, "cannot create %s: %r", name);
 		return result;
 	}
@@ -265,7 +261,7 @@ enum{
 	Del,
 	Write,
 	Empty3,
-	Exit
+	Exit,
 };
  
 void
@@ -273,11 +269,14 @@ viewer(Document *dd)
 {
 	int i, fd, n, oldpage;
 	int nxt;
+	Channel *cp;
 	Menu menu, midmenu;
 	Mouse m;
-	Event e;
+	Keyboardctl *kc;
 	Point dxy, oxy, xy0;
+	Rune run;
 	Rectangle r;
+	int size[2];
 	Image *tmp;
 	static char *fwditems[] = { "this page", "next page", "exit", 0 };
  	static char *miditems[] = {
@@ -299,16 +298,44 @@ viewer(Document *dd)
  		0 
  	};
 	char *s;
-	enum { Eplumb = 4 };
+	enum {
+	    CMouse,
+	    CResize,
+	    CKeyboard,
+	    CPlumb,
+	    CN
+	};
+	Alt alts[CN+1];
 	Plumbmsg *pm;
 
+	cp = chancreate(sizeof pm, 0);
+	assert(cp);
+
 	doc = dd;    /* save global for menuhit */
 	ul = screen->r.min;
-	einit(Emouse|Ekeyboard);
-	if(doc->addpage != nil)
-		eplumb(Eplumb, "image");
+	mc = initmouse(nil, screen);
+	kc = initkeyboard(nil);
+	alts[CMouse].c = mc->c;
+	alts[CMouse].v = &m;
+	alts[CMouse].op = CHANRCV;
+	alts[CResize].c = mc->resizec;
+	alts[CResize].v = &size;
+	alts[CResize].op = CHANRCV;
+	alts[CKeyboard].c = kc->c;
+	alts[CKeyboard].v = &run;
+	alts[CKeyboard].op = CHANRCV;
+	alts[CPlumb].c = cp;
+	alts[CPlumb].v = &pm;
+	alts[CPlumb].op = CHANNOP;
+	alts[CN].op = CHANEND;
 
-	esetcursor(&reading);
+	/* XXX: Event */
+	if(doc->addpage != nil) {
+		alts[CPlumb].op = CHANRCV;
+		proccreate(plumbproc, cp, 16384);
+	}
+
+	setcursor(mc, &reading);
 	r.min = ZP;
 
 	/*
@@ -336,7 +363,7 @@ viewer(Document *dd)
 	midmenu.lasthit = Next;
 
 	showpage(page, &menu);
-	esetcursor(nil);
+	setcursor(mc, nil);
 
 	nxt = 0;
 	for(;;) {
@@ -345,14 +372,14 @@ viewer(Document *dd)
 		 * a fair amount.  we don't care about doc->npage anymore, and
 		 * all that can be done is select the next page.
 		 */
-		switch(eread(Emouse|Ekeyboard|Eplumb, &e)){
-		case Ekeyboard:
-			if(e.kbdc <= 0xFF && isdigit(e.kbdc)) {
-				nxt = nxt*10+e.kbdc-'0';
-				break;
-			} else if(e.kbdc != '\n')
+		switch(alt(alts)) {
+		case CKeyboard:
+			if(run <= 0xFF && isdigit(run)) {
+				nxt = nxt*10+run-'0';
+				break;
+			} else if(run != '\n')
 				nxt = 0;
-			switch(e.kbdc) {
+			switch(run) {
 			case 'r':	/* reverse page order */
 				if(doc->fwdonly)
 					break;
@@ -372,12 +399,12 @@ viewer(Document *dd)
 				}
 				break;
 			case 'w':	/* write bitmap of current screen */
-				esetcursor(&reading);
+				setcursor(mc, &reading);
 				s = writebitmap();
 				if(s)
 					string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
 						display->defaultfont, s);
-				esetcursor(nil);
+				setcursor(mc, nil);
 				flushimage(display, 1);
 				break;
 			case 'd':	/* remove image from working set */
@@ -397,9 +424,9 @@ viewer(Document *dd)
 			case 'u':
 				if(im==nil)
 					break;
-				esetcursor(&reading);
+				setcursor(mc, &reading);
 				rot180(im);
-				esetcursor(nil);
+				setcursor(mc, nil);
 				angle = (angle+180) % 360;
 				redraw(screen);
 				flushimage(display, 1);
@@ -470,15 +497,14 @@ viewer(Document *dd)
 				}
 				break;
 			default:
-				esetcursor(&query);
+				setcursor(mc, &query);
 				sleep(1000);
-				esetcursor(nil);
+				setcursor(mc, nil);
 				break;	
 			}
 			break;
 
-		case Emouse:
-			m = e.mouse;
+		case CMouse:
 			switch(m.buttons){
 			case Left:
 				oxy = m.xy;
@@ -487,7 +513,7 @@ viewer(Document *dd)
 					dxy = subpt(m.xy, oxy);
 					oxy = m.xy;	
 					translate(dxy);
-					m = emouse();
+					recv(mc->c, &m);
 				} while(m.buttons == Left);
 				if(m.buttons) {
 					dxy = subpt(xy0, oxy);
@@ -499,7 +525,7 @@ viewer(Document *dd)
 				if(doc->npage == 0)
 					break;
 
-				n = emenuhit(Middle, &m, &midmenu);
+				n = menuhit(Middle, mc, &midmenu, nil);
 				if(n == -1)
 					break;
 				switch(n){
@@ -543,7 +569,7 @@ viewer(Document *dd)
 						double delta;
 						Rectangle r;
 
-						r = egetrect(Middle, &m);
+						r = getrect(Middle, mc);
 						if((rectclip(&r, rectaddpt(im->r, ul)) == 0) ||
 							Dx(r) == 0 || Dy(r) == 0)
 							break;
@@ -553,7 +579,7 @@ viewer(Document *dd)
 						else
 							delta = (double)Dy(im->r)/(double)Dy(r);
 
-						esetcursor(&reading);
+						setcursor(mc, &reading);
 						tmp = xallocimage(display, 
 								Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)), 
 								im->chan, 0, DBlack);
@@ -564,7 +590,7 @@ viewer(Document *dd)
 						resample(im, tmp);
 						freeimage(im);
 						im = tmp;
-						esetcursor(nil);
+						setcursor(mc, nil);
 						ul = screen->r.min;
 						redraw(screen);
 						flushimage(display, 1);
@@ -580,7 +606,7 @@ viewer(Document *dd)
 							delta = (double)Dy(screen->r)/(double)Dy(im->r);
 
 						r = Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta));
-						esetcursor(&reading);
+						setcursor(mc, &reading);
 						tmp = xallocimage(display, r, im->chan, 0, DBlack);
 						if(tmp == nil) {
 							fprint(2, "out of memory during fit: %r\n");
@@ -589,16 +615,16 @@ viewer(Document *dd)
 						resample(im, tmp);
 						freeimage(im);
 						im = tmp;
-						esetcursor(nil);
+						setcursor(mc, nil);
 						ul = screen->r.min;
 						redraw(screen);
 						flushimage(display, 1);
 						break;
 					}
 				case Rot:	/* rotate 90 */
-					esetcursor(&reading);
+					setcursor(mc, &reading);
 					im = rot90(im);
-					esetcursor(nil);
+					setcursor(mc, nil);
 					angle = (angle+90) % 360;
 					redraw(screen);
 					flushimage(display, 1);
@@ -606,9 +632,9 @@ viewer(Document *dd)
 				case Upside: 	/* upside-down */
 					if(im==nil)
 						break;
-					esetcursor(&reading);
+					setcursor(mc, &reading);
 					rot180(im);
-					esetcursor(nil);
+					setcursor(mc, nil);
 					angle = (angle+180) % 360;
 					redraw(screen);
 					flushimage(display, 1);
@@ -628,12 +654,12 @@ viewer(Document *dd)
 					}
 					break;
 				case Write: /* write */
-					esetcursor(&reading);
+					setcursor(mc, &reading);
 					s = writebitmap();
 					if(s)
 						string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
 							display->defaultfont, s);
-					esetcursor(nil);
+					setcursor(mc, nil);
 					flushimage(display, 1);
 					break;
 				case Del: /* delete */
@@ -663,7 +689,7 @@ viewer(Document *dd)
 					break;
 
 				oldpage = page;
-				n = emenuhit(RMenu, &m, &menu);
+				n = menuhit(RMenu, mc, &menu, nil);
 				if(n == -1)
 					break;
 	
@@ -691,9 +717,15 @@ viewer(Document *dd)
 				break;
 			}
 			break;
-
-		case Eplumb:
-			pm = e.v;
+		case CResize:
+			r = screen->r;
+			if(getwindow(display, Refnone) < 0)
+				fprint(2,"can't reattach to window");
+			ul = addpt(ul, subpt(screen->r.min, r.min));
+			redraw(screen);
+			flushimage(display, 1);
+			break;
+		case CPlumb:
 			if(pm->ndata <= 0){
 				plumbfree(pm);
 				break;
@@ -866,18 +898,7 @@ redraw(Image *screen)
 		}
 	}
 	border(screen, r, -4000, gray, ZP);
-/*	flushimage(display, 0);	 */
-}
-
-void
-eresized(int new)
-{
-	Rectangle r;
-	r = screen->r;
-	if(new && getwindow(display, Refnone) < 0)
-		fprint(2,"can't reattach to window");
-	ul = addpt(ul, subpt(screen->r.min, r.min));
-	redraw(screen);
+//	flushimage(display, 0);	
 }
 
 /* clip p to be in r */
@@ -909,21 +930,17 @@ resize(int dx, int dy)
 	static Rectangle sr;
 	Rectangle r, or;
 
-	dx += 2*Borderwidth;
-	dy += 2*Borderwidth;
-	if(wctlfd < 0){
-		wctlfd = open("/dev/wctl", OWRITE);
-		if(wctlfd < 0)
-			return;
+	r = screen->r;
+	if(Dx(sr)*Dy(sr) == 0) {
+		sr = screenrect();
+		/* Start with the size of the first image */
+		r.max.x = r.min.x;
+		r.max.y = r.min.y;
 	}
 
-	r = insetrect(screen->r, -Borderwidth);
 	if(Dx(r) >= dx && Dy(r) >= dy)
 		return;
 
-	if(Dx(sr)*Dy(sr) == 0)
-		sr = screenrect();
-
 	or = r;
 
 	r.max.x = max(r.min.x+dx, r.max.x);
@@ -950,8 +967,7 @@ resize(int dx, int dy)
 	if(Dx(r) == Dx(or) && Dy(r) == Dy(or))
 		return;
 
-	fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n",
-		r.min.x, r.min.y, r.max.x, r.max.y);
+	drawresizewindow(r);
 }
 
 /*
@@ -966,129 +982,73 @@ xallocimage(Display *d, Rectangle r, ulong chan, int r
 	return allocimage(d, r, chan, repl, val);
 }
 
-/* all code below this line should be in the library, but is stolen from colors instead */
-static char*
-rdenv(char *name)
-{
-	char *v;
-	int fd, size;
-
-	fd = open(name, OREAD);
-	if(fd < 0)
-		return 0;
-	size = seek(fd, 0, 2);
-	v = malloc(size+1);
-	if(v == 0){
-		fprint(2, "page: can't malloc: %r\n");
-		wexits("no mem");
-	}
-	seek(fd, 0, 0);
-	read(fd, v, size);
-	v[size] = 0;
-	close(fd);
-	return v;
-}
-
 void
-newwin(void)
+plumbproc(void *c)
 {
-	char *srv, *mntsrv;
-	char spec[100];
-	int srvfd, cons, pid;
+	Channel *cp;
+	CFid *fd;
 
-	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){
-	case -1:
-		fprint(2, "page: can't fork: %r\n");
-		wexits("no fork");
-	case 0:
-		break;
-	default:
-		wexits(0);
+	cp = c;
+	fd = plumbopenfid("image", OREAD|OCEXEC);
+	if(fd == nil) {
+		fprint(2, "Cannot connect to the plumber");
+		threadexits("plumber");
 	}
-
-	srv = rdenv("/env/wsys");
-	if(srv == 0){
-		mntsrv = rdenv("/mnt/term/env/wsys");
-		if(mntsrv == 0){
-			fprint(2, "page: can't find $wsys\n");
-			wexits("srv");
-		}
-		srv = malloc(strlen(mntsrv)+10);
-		sprint(srv, "/mnt/term%s", mntsrv);
-		free(mntsrv);
-		pid  = 0;			/* can't send notes to remote processes! */
-	}else
-		pid = getpid();
-	srvfd = open(srv, ORDWR);
-	free(srv);
-	if(srvfd == -1){
-		fprint(2, "page: can't open %s: %r\n", srv);
-		wexits("no srv");
+	for(;;) {
+		send(cp, plumbrecvfid(fd));
 	}
-	sprint(spec, "new -pid %d", pid);
-	if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
-		fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
-		wexits("no mount");
-	}
-	close(srvfd);
-	unmount("/mnt/acme", "/dev");
-	bind("/mnt/wsys", "/dev", MBEFORE);
-	cons = open("/dev/cons", OREAD);
-	if(cons==-1){
-	NoCons:
-		fprint(2, "page: can't open /dev/cons: %r");
-		wexits("no cons");
-	}
-	dup(cons, 0);
-	close(cons);
-	cons = open("/dev/cons", OWRITE);
-	if(cons==-1)
-		goto NoCons;
-	dup(cons, 1);
-	dup(cons, 2);
-	close(cons);
-/*	wctlfd = open("/dev/wctl", OWRITE); */
 }
 
+/* XXX: This function is ugly and hacky. There may be a better way... or not */
 Rectangle
 screenrect(void)
 {
-	int fd;
-	char buf[12*5];
+	int fd[3], pfd[2];
+	int n, w, h;
+	char buf[64];
+	char *p, *pr;
 
-	fd = open("/dev/screen", OREAD);
-	if(fd == -1)
-		fd=open("/mnt/term/dev/screen", OREAD);
-	if(fd == -1){
-		fprint(2, "page: can't open /dev/screen: %r\n");
-		wexits("window read");
-	}
-	if(read(fd, buf, sizeof buf) != sizeof buf){
-		fprint(2, "page: can't read /dev/screen: %r\n");
-		wexits("screen read");
-	}
-	close(fd);
-	return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
+	if(pipe(pfd) < 0)
+		wexits("pipe failed");
+
+	fd[0] = open("/dev/null", OREAD);
+	fd[1] = pfd[1];
+	fd[2] = dup(2, -1);
+	if(threadspawnl(fd, "rc", "rc", "-c", "xdpyinfo | grep 'dimensions:'", nil) == -1)
+		wexits("threadspawnl failed");
+
+	if((n = read(pfd[0], buf, 63)) <= 0)
+		wexits("read xdpyinfo failed");
+	close(fd[0]);
+
+	buf[n] = '\0';
+	for(p = buf; *p; p++)
+		if(*p >= '0' && *p <= '9') break;
+	if(*p == '\0')
+		wexits("xdpyinfo parse failed");
+
+	w = strtoul(p, &pr, 10);
+	if(p == pr || *pr == '\0' || *(++pr) == '\0')
+		wexits("xdpyinfo parse failed");
+	h = strtoul(pr, &p, 10);
+	if(p == pr)
+		wexits("xdpyinfo parse failed");
+
+	return Rect(0, 0, w, h);
 }
 
 void
 zerox(void)
 {
 	int pfd[2];
+	int fd[3];
 
 	pipe(pfd);
-	switch(rfork(RFFDG|RFPROC)) {
-		case -1:
-			wexits("cannot fork in zerox: %r");
-		case 0: 
-			dup(pfd[1], 0);
-			close(pfd[0]);
-			execl("/bin/page", "page", "-w", nil);
-			wexits("cannot exec in zerox: %r\n");
-		default:
-			close(pfd[1]);
-			writeimage(pfd[0], im, 0);
-			close(pfd[0]);
-			break;
-	}
+	fd[0] = pfd[0];
+	fd[1] = dup(1, -1);
+	fd[2] = dup(2, -1);
+	threadspawnl(fd, "page", "page", "-R", nil);
+
+	writeimage(pfd[1], im, 0);
+	close(pfd[1]);
 }