URI: 
       tadd page (Kris Maglione) - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 05a4d855f167ae2d0d2c0ba0e386d933172b71ea
   DIR parent 6c4c5c5b959ec8a2e85510bdf85339582f638f36
  HTML Author: rsc <devnull@localhost>
       Date:   Mon, 26 Mar 2007 20:55:26 +0000
       
       add page (Kris Maglione)
       
       Diffstat:
         M src/cmd/mkfile                      |       2 +-
         M src/cmd/page/filter.c               |      28 +++++++++++++++-------------
         M src/cmd/page/gfx.c                  |      94 +++++++++----------------------
         M src/cmd/page/gs.c                   |     175 +++++++++++++------------------
         M src/cmd/page/mkfile                 |      10 ++++++++++
         M src/cmd/page/nrotate.c              |       6 +++---
         M src/cmd/page/page.c                 |      76 +++++++++++++++++++++++++++----
         M src/cmd/page/page.h                 |      30 +++++++++++++++++++++++++++++-
         M src/cmd/page/pdf.c                  |       8 ++++----
         M src/cmd/page/pdfprolog.c            |      19 +++++--------------
         M src/cmd/page/pdfprolog.ps           |      19 +++++--------------
         M src/cmd/page/ps.c                   |      10 +++++-----
         M src/cmd/page/rotate.c               |      30 +++++++++++++++---------------
         M src/cmd/page/util.c                 |      79 ++++++++++++++-----------------
         M src/cmd/page/view.c                 |     342 ++++++++++++++-----------------
       
       15 files changed, 448 insertions(+), 480 deletions(-)
       ---
   DIR diff --git a/src/cmd/mkfile b/src/cmd/mkfile
       t@@ -4,7 +4,7 @@ TARG=`ls *.[cy] *.lx | egrep -v "\.tab\.c$|^x\." | sed 's/\.[cy]//; s/\.lx//'`
        
        <$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
   DIR diff --git a/src/cmd/page/filter.c b/src/cmd/page/filter.c
       t@@ -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*
       t@@ -24,7 +24,7 @@ initfilt(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf, char *type, cha
                if(docopy){
                        if(pipe(p) < 0){
                                fprint(2, "pipe fails: %r\n");
       -                        exits("Epipe");
       +                        threadexits("Epipe");
                        }
                }else{
                        p[0] = open("/dev/null", ORDWR);
       t@@ -35,27 +35,29 @@ initfilt(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf, char *type, cha
                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;
                }
        
       t@@ -81,7 +83,7 @@ initdvi(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
                 */
                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");
   DIR diff --git a/src/cmd/page/gfx.c b/src/cmd/page/gfx.c
       t@@ -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;
       t@@ -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.
       t@@ -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);
       t@@ -202,12 +177,12 @@ genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
                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);
       t@@ -244,7 +219,7 @@ rmpage(Document *doc, int n)
        }
        
        
       -static Image*
       +Image*
        convert(Graphic *g)
        {
                int fd;
       t@@ -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;
       t@@ -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");
       t@@ -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];
        }
       -
   DIR diff --git a/src/cmd/page/gs.c b/src/cmd/page/gs.c
       t@@ -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 */
       t@@ -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;
       -
       -        case 0:
       -                break;
       -        }
       +        recv(cp, &fd);
        
       -        out = open("/dev/cons", OWRITE);
       +        out = open("/dev/tty", OWRITE);
                if(out < 0)
                        out = 2;
        
       t@@ -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];
        
       t@@ -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);
       t@@ -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,
       t@@ -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;
       +
       +        proccreate(spawnmonitor, cp, mainstacksize);
       +        send(cp, &errout[0]);
       +        chanfree(cp);
        
       -        spawnmonitor(errout[1]);
       -        Binit(&g->gsrd, g->gsfd, OREAD);
       +        Binit(&g->gsrd, stdoutp[0], OREAD);
        
       -        gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n");
       +        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);
        
       t@@ -269,11 +239,14 @@ setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
                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");
       t@@ -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(;;) {
   DIR diff --git a/src/cmd/page/mkfile b/src/cmd/page/mkfile
       t@@ -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
        
   DIR diff --git a/src/cmd/page/nrotate.c b/src/cmd/page/nrotate.c
       t@@ -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);
       t@@ -229,7 +229,7 @@ swapadjacent(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int mask
                /*
                 * r0 is the lower rectangle, while r1 is the upper one.
                 */
       -        draw(tmp, tmp->r, img, nil
       +        draw(tmp, tmp->r, img, nil, 
        }
        
        void
   DIR diff --git a/src/cmd/page/page.c b/src/cmd/page/page.c
       t@@ -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;
       t@@ -16,10 +17,45 @@ 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)
       t@@ -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;
       t@@ -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':
       t@@ -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();
       t@@ -107,8 +160,9 @@ main(int argc, char **argv)
        
                fmtinstall('R', Rfmt);
                fmtinstall('P', Pfmt);
       +        /*
                if(mknewwindow)
       -                newwin();
       +                newwin(); */
        
                if(readstdin){
                        b = nil;
       t@@ -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);
        }
   DIR diff --git a/src/cmd/page/page.h b/src/cmd/page/page.h
       t@@ -1,3 +1,5 @@
       +#undef pipe
       +
        typedef struct Document Document;
        
        struct Document {
       t@@ -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*);
       t@@ -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*);
       t@@ -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;
   DIR diff --git a/src/cmd/page/pdf.c b/src/cmd/page/pdf.c
       t@@ -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"
        
       t@@ -66,7 +66,7 @@ initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
                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");
       t@@ -122,7 +122,7 @@ initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
                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;
                }
       t@@ -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");
   DIR diff --git a/src/cmd/page/pdfprolog.c b/src/cmd/page/pdfprolog.c
       t@@ -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"
   DIR diff --git a/src/cmd/page/pdfprolog.ps b/src/cmd/page/pdfprolog.ps
       t@@ -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
   DIR diff --git a/src/cmd/page/ps.c b/src/cmd/page/ps.c
       t@@ -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"
       t@@ -158,7 +158,7 @@ initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
                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");
       t@@ -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;
       t@@ -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);
        
       t@@ -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");
   DIR diff --git a/src/cmd/page/rotate.c b/src/cmd/page/rotate.c
       t@@ -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;
       t@@ -55,7 +55,6 @@ moveup(Image *im, Image *tmp, int a, int b, int c, int axis)
                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;
       t@@ -67,6 +66,7 @@ moveup(Image *im, Image *tmp, int a, int b, int c, int axis)
                        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);
       t@@ -90,7 +90,6 @@ interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
                r0 = im->r;
                r1 = im->r;
                switch(axis) {
       -        default:
                case Xaxis:
                        r0.max.x = n;
                        r1.min.x = n;
       t@@ -98,6 +97,7 @@ interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
                        p1 = (Point){-gran, 0};
                        break;
                case Yaxis:
       +        default:
                        r0.max.y = n;
                        r1.min.y = n;
                        p0 = (Point){0, gran};
       t@@ -132,12 +132,12 @@ interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
        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;
        }
        
       t@@ -153,13 +153,13 @@ shuffle(Image *im, Image *tmp, int axis, int n, Image *mask, int gran,
                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
       t@@ -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);
       t@@ -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);
        }
        
        
   DIR diff --git a/src/cmd/page/util.c b/src/cmd/page/util.c
       t@@ -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*
       t@@ -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.
       t@@ -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);
       +}
       +
       +int
       +stdinpipe(uchar *ibuf, int in) {
       +        StdinArg arg;
       +        int fd;
        
       -        _exits(0);
       -        return -1;        /* not reached */
       +        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;
        }
   DIR diff --git a/src/cmd/page/view.c b/src/cmd/page/view.c
       t@@ -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;
       t@@ -26,6 +28,7 @@ Point ul;                        /* the upper left corner of the image is at this point on the screen
        Point pclip(Point, Rectangle);
        Rectangle mkrange(Rectangle screenr, Rectangle imr);
        void redraw(Image*);
       +void plumbproc(void*);
        
        Cursor reading={
                {-1, -1},
       t@@ -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 
       t@@ -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;
       t@@ -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;
       t@@ -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";
       t@@ -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;
                }
       t@@ -265,7 +261,7 @@ enum{
                Del,
                Write,
                Empty3,
       -        Exit
       +        Exit,
        };
         
        void
       t@@ -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[] = {
       t@@ -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;
       +
       +        /* XXX: Event */
       +        if(doc->addpage != nil) {
       +                alts[CPlumb].op = CHANRCV;
       +                proccreate(plumbproc, cp, 16384);
       +        }
        
       -        esetcursor(&reading);
       +        setcursor(mc, &reading);
                r.min = ZP;
        
                /*
       t@@ -336,7 +363,7 @@ viewer(Document *dd)
                midmenu.lasthit = Next;
        
                showpage(page, &menu);
       -        esetcursor(nil);
       +        setcursor(mc, nil);
        
                nxt = 0;
                for(;;) {
       t@@ -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';
       +                switch(alt(alts)) {
       +                case CKeyboard:
       +                        if(run <= 0xFF && isdigit(run)) {
       +                                nxt = nxt*10+run-'0';
                                        break;
       -                        } else if(e.kbdc != '\n')
       +                        } else if(run != '\n')
                                        nxt = 0;
       -                        switch(e.kbdc) {
       +                        switch(run) {
                                case 'r':        /* reverse page order */
                                        if(doc->fwdonly)
                                                break;
       t@@ -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 */
       t@@ -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);
       t@@ -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;
       t@@ -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);
       t@@ -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){
       t@@ -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;
       t@@ -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);
       t@@ -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);
       t@@ -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");
       t@@ -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);
       t@@ -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);
       t@@ -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 */
       t@@ -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;
                
       t@@ -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;
       t@@ -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 */
       t@@ -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);
       t@@ -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);
        }
        
        /*
       t@@ -966,129 +982,73 @@ xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
                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;
       -
       -        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);
       +        Channel *cp;
       +        CFid *fd;
       +
       +        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");
       -        }
       -        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");
       +        for(;;) {
       +                send(cp, plumbrecvfid(fd));
                }
       -        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];
       -
       -        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));
       +        int fd[3], pfd[2];
       +        int n, w, h;
       +        char buf[64];
       +        char *p, *pr;
       +
       +        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]);
        }