add page (Kris Maglione)

This commit is contained in:
rsc 2007-03-26 20:55:26 +00:00
parent 6c4c5c5b95
commit 05a4d855f1
15 changed files with 448 additions and 480 deletions

View file

@ -4,7 +4,7 @@ TARG=`ls *.[cy] *.lx | egrep -v "\.tab\.c$|^x\." | sed 's/\.[cy]//; s/\.lx//'`
<$PLAN9/src/mkmany <$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$'` DIRS=lex `ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"|egrep -v '^lex$'`
<$PLAN9/src/mkdirs <$PLAN9/src/mkdirs

View file

@ -1,9 +1,9 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <thread.h>
#include <event.h>
#include <bio.h> #include <bio.h>
#include <cursor.h>
#include "page.h" #include "page.h"
Document* Document*
@ -24,7 +24,7 @@ initfilt(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf, char *type, cha
if(docopy){ if(docopy){
if(pipe(p) < 0){ if(pipe(p) < 0){
fprint(2, "pipe fails: %r\n"); fprint(2, "pipe fails: %r\n");
exits("Epipe"); threadexits("Epipe");
} }
}else{ }else{
p[0] = open("/dev/null", ORDWR); p[0] = open("/dev/null", ORDWR);
@ -35,27 +35,29 @@ initfilt(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf, char *type, cha
switch(fork()){ switch(fork()){
case -1: case -1:
fprint(2, "fork fails: %r\n"); fprint(2, "fork fails: %r\n");
exits("Efork"); threadexits("Efork");
default: default:
close(p[1]); close(p[0]);
if(docopy){ if(docopy){
write(p[0], buf, nbuf); write(p[1], buf, nbuf);
if(b) if(b)
while((n = Bread(b, xbuf, sizeof xbuf)) > 0) while((n = Bread(b, xbuf, sizeof xbuf)) > 0)
write(p[0], xbuf, n); write(p[1], xbuf, n);
else else
while((n = read(stdinfd, xbuf, sizeof xbuf)) > 0) 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(); waitpid();
break; break;
case 0: case 0:
close(p[0]); close(p[1]);
dup(p[1], 0); dup(p[0], 0);
dup(ofd, 1); dup(ofd, 1);
/* stderr shines through */ /* 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; break;
} }
@ -81,7 +83,7 @@ initdvi(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
*/ */
if(b == nil){ /* standard input; spool to disk (ouch) */ if(b == nil){ /* standard input; spool to disk (ouch) */
fd = spooltodisk(buf, nbuf, &name); fd = spooltodisk(buf, nbuf, &name);
sprint(fdbuf, "/fd/%d", fd); sprint(fdbuf, "/dev/fd/%d", fd);
b = Bopen(fdbuf, OREAD); b = Bopen(fdbuf, OREAD);
if(b == nil){ if(b == nil){
fprint(2, "cannot open disk spool file\n"); fprint(2, "cannot open disk spool file\n");

View file

@ -5,14 +5,13 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <thread.h>
#include <event.h>
#include <bio.h> #include <bio.h>
#include <cursor.h>
#include "page.h" #include "page.h"
typedef struct Convert Convert; typedef struct Convert Convert;
typedef struct GfxInfo GfxInfo; typedef struct GfxInfo GfxInfo;
typedef struct Graphic Graphic;
struct Convert { struct Convert {
char *name; char *name;
@ -24,29 +23,6 @@ struct GfxInfo {
Graphic *g; 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 * N.B. These commands need to read stdin if %a is replaced
* with an empty string. * 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" }, [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" }, [Ipng] { "png", "png -9 %a", "png -t9 %a" },
[Iyuv] { "yuv", "yuv -9 %a", "yuv -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 Image* gfxdrawpage(Document *d, int page);
static char* gfxpagename(Document*, int); static char* gfxpagename(Document*, int);
static int spawnrc(char*, uchar*, int); static int spawnrc(char*, Graphic*);
static void waitrc(void); //static void waitrc(void);
static int spawnpost(int); //static int spawnpost(int);
static int addpage(Document*, char*); static int addpage(Document*, char*);
static int rmpage(Document*, int); static int rmpage(Document*, int);
static int genaddpage(Document*, char*, uchar*, int); static int genaddpage(Document*, char*, uchar*, int);
@ -202,12 +177,12 @@ genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
else else
g->type = Icvt2pic; g->type = Icvt2pic;
if(name) if(name){
g->name = estrdup(name); g->name = estrdup(name);
else{ g->fd = -1;
}else{
g->name = estrdup("stdin"); /* so it can be freed */ g->name = estrdup("stdin"); /* so it can be freed */
g->buf = buf; g->fd = stdinpipe(buf, nbuf);
g->nbuf = nbuf;
} }
if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name); 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) convert(Graphic *g)
{ {
int fd; int fd;
@ -253,25 +228,24 @@ convert(Graphic *g)
char *name, buf[1000]; char *name, buf[1000];
Image *im; Image *im;
int rcspawned = 0; int rcspawned = 0;
Waitmsg *w;
c = cvt[g->type]; c = cvt[g->type];
if(c.cmd == nil) { if(c.cmd == nil) {
if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name); 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); fd = open(g->name, OREAD);
if(fd < 0) { if(fd < 0) {
fprint(2, "cannot open file: %r\n"); fprint(2, "cannot open file: %r\n");
wexits("open"); wexits("open");
} }
}else }else
fd = stdinpipe(g->buf, g->nbuf); fd = g->fd;
} else { } else {
cmd = c.cmd; cmd = c.cmd;
if(truecolor && c.truecmd) if(truecolor && c.truecmd)
cmd = c.truecmd; cmd = c.truecmd;
if(g->buf != nil) /* is stdin */ if(g->fd >= 0) /* is pipe */
name = ""; name = "";
else else
name = g->name; name = g->name;
@ -281,7 +255,7 @@ convert(Graphic *g)
} }
snprint(buf, sizeof buf, cmd, name); snprint(buf, sizeof buf, cmd, name);
if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->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++; rcspawned++;
if(fd < 0) { if(fd < 0) {
fprint(2, "cannot spawn converter: %r\n"); fprint(2, "cannot spawn converter: %r\n");
@ -293,43 +267,31 @@ convert(Graphic *g)
if(im == nil) { if(im == nil) {
fprint(2, "warning: couldn't read image: %r\n"); fprint(2, "warning: couldn't read image: %r\n");
} }
close(fd);
/* for some reason rx doesn't work well with wait */ close(fd);
/* 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);
}
return im; return im;
} }
static int static int
spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf) spawnrc(char *cmd, Graphic *g)
{ {
int pfd[2]; int pfd[2];
int pid; int fd[3];
if(chatty) fprint(2, "spawning(%s)...", cmd); if(chatty) fprint(2, "spawning(%s)...", cmd);
if(pipe(pfd) < 0) if(pipe(pfd) < 0)
return -1; 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; return -1;
if(pid == 0) { return pfd[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];
} }

View file

@ -7,9 +7,9 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <thread.h>
#include <event.h>
#include <bio.h> #include <bio.h>
#include <cursor.h>
#include "page.h" #include "page.h"
static int gspid; /* globals for atexit */ static int gspid; /* globals for atexit */
@ -37,87 +37,41 @@ killgs(void)
postnote(PNPROC, gspid, "die yankee pig dog"); postnote(PNPROC, gspid, "die yankee pig dog");
} }
int void
spawnwriter(GSInfo *g, Biobuf *b) spawnreader(void *cp)
{ {
char buf[4096]; int n, fd, pfd[2];
int n;
int fd;
switch(fork()){
case -1: return -1;
case 0: break;
default: return 0;
}
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;
}
int
spawnreader(int fd)
{
int n, pfd[2];
char buf[1024]; char buf[1024];
if(pipe(pfd)<0) recv(cp, &fd);
return -1;
switch(fork()){ if(pipe(pfd)<0)
case -1: wexits("pipe failed");
return -1;
case 0: send(cp, &pfd[1]);
break;
default:
close(pfd[0]);
return pfd[1];
}
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) { while((n=read(pfd[0], buf, sizeof buf)) > 0) {
write(1, buf, n); write(1, buf, n);
write(fd, buf, n); write(fd, buf, n);
} }
break;
} close(pfd[0]);
postnote(PNGROUP, getpid(), "i'm die-ing"); threadexits(0);
_exits(0);
return -1;
} }
void void
spawnmonitor(int fd) spawnmonitor(void *cp)
{ {
char buf[4096]; char buf[4096];
char *xbuf; char *xbuf;
int fd;
int n; int n;
int out; int out;
int first; int first;
switch(rfork(RFFDG|RFNOTEG|RFPROC)){ recv(cp, &fd);
case -1:
default:
return;
case 0: out = open("/dev/tty", OWRITE);
break;
}
out = open("/dev/cons", OWRITE);
if(out < 0) if(out < 0)
out = 2; out = 2;
@ -131,17 +85,19 @@ spawnmonitor(int fd)
write(out, xbuf, n); write(out, xbuf, n);
alarm(500); alarm(500);
} }
_exits(0); threadexits(0);
} }
int int
spawngs(GSInfo *g, char *safer) spawngs(GSInfo *g, char *safer)
{ {
Channel *cp;
char *args[16]; char *args[16];
char tb[32], gb[32]; char tb[32], gb[32];
int i, nargs; int i, nargs;
int devnull; int devnull;
int stdinout[2]; int stdinp[2];
int stdoutp[2];
int dataout[2]; int dataout[2];
int errout[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 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. * 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; return -1;
nargs = 0; nargs = 0;
args[nargs++] = "gs"; args[nargs++] = "gs";
args[nargs++] = "-dNOPAUSE"; args[nargs++] = "-dNOPAUSE";
args[nargs++] = safer; args[nargs++] = "-dDELAYSAFER";
args[nargs++] = "-sDEVICE=plan9"; args[nargs++] = "-sDEVICE=bmp16m";
args[nargs++] = "-sOutputFile=/fd/3"; args[nargs++] = "-sOutputFile=/dev/fd/3";
args[nargs++] = "-dQUIET"; args[nargs++] = "-dQUIET";
args[nargs++] = "-r100"; args[nargs++] = "-r100";
sprint(tb, "-dTextAlphaBits=%d", textbits); sprint(tb, "-dTextAlphaBits=%d", textbits);
@ -175,9 +131,10 @@ spawngs(GSInfo *g, char *safer)
gspid = fork(); gspid = fork();
if(gspid == 0) { if(gspid == 0) {
close(stdinout[1]); close(stdinp[1]);
close(dataout[1]); close(stdoutp[0]);
close(errout[1]); close(dataout[0]);
close(errout[0]);
/* /*
* Horrible problem: we want to dup fd's 0-4 below, * 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) while((devnull = open("/dev/null", ORDWR)) < 5)
; ;
stdinout[0] = dup(stdinout[0], -1); stdinp[0] = dup(stdinp[0], -1);
errout[0] = dup(errout[0], -1); stdoutp[1] = dup(stdoutp[1], -1);
dataout[0] = dup(dataout[0], -1); errout[1] = dup(errout[1], -1);
dataout[1] = dup(dataout[1], -1);
dup(stdinout[0], 0); dup(stdinp[0], 0);
dup(errout[0], 1); dup(errout[1], 1);
dup(devnull, 2); /* never anything useful */ dup(errout[1], devnull); /* never anything useful */
dup(dataout[0], 3); dup(dataout[1], 3);
dup(stdinout[0], 4); dup(stdoutp[1], 4);
for(i=5; i<20; i++) for(i=5; i<20; i++)
close(i); close(i);
exec("/bin/gs", args); execvp("gs", args);
wexits("exec"); wexits("exec");
} }
close(stdinout[0]); close(stdinp[0]);
close(errout[0]); close(stdoutp[1]);
close(dataout[0]); close(errout[1]);
close(dataout[1]);
atexit(killgs); atexit(killgs);
if(teegs) cp = chancreate(sizeof(int), 0);
stdinout[1] = spawnreader(stdinout[1]); if(teegs) {
proccreate(spawnreader, cp, mainstacksize);
send(cp, &stdoutp[0]);
recv(cp, &stdoutp[0]);
}
gsfd = g->gsfd = stdinout[1]; gsfd = g->gsfd = stdinp[1];
g->gsdfd = dataout[1];
g->gspid = gspid; g->gspid = gspid;
g->g.fd = dataout[0];
g->g.name = "gs pipe";
g->g.type = Ibmp;
spawnmonitor(errout[1]); proccreate(spawnmonitor, cp, mainstacksize);
Binit(&g->gsrd, g->gsfd, OREAD); 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"); gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n");
waitgs(g); waitgs(g);
@ -269,11 +239,14 @@ setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape)
if(!Dx(bbox)) if(!Dx(bbox))
bbox = Rect(0, 0, 612, 792); /* 8½×11 */ bbox = Rect(0, 0, 612, 792); /* 8½×11 */
if(landscape) switch(landscape){
pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x); case 0:
else
pbox = bbox; 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, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox));
gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y); gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y);
gscmd(gs, "currentdevice putdeviceprops pop\n"); gscmd(gs, "currentdevice putdeviceprops pop\n");
@ -305,10 +278,10 @@ waitgs(GSInfo *gs)
uchar buf[1024]; uchar buf[1024];
int n; int n;
/* gscmd(gs, "(\\n**bstack\\n) print flush\n"); */ // gscmd(gs, "(\\n**bstack\\n) print flush\n");
/* gscmd(gs, "stack flush\n"); */ // gscmd(gs, "stack flush\n");
/* gscmd(gs, "(**estack\\n) print flush\n"); */ // gscmd(gs, "(**estack\\n) print flush\n");
gscmd(gs, "(\\n/*GO.SYSIN DD\\n) PAGE==\n"); */ gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n");
alarm(300*1000); alarm(300*1000);
for(;;) { for(;;) {

View file

@ -14,8 +14,18 @@ OFILES=\
util.$O\ util.$O\
view.$O\ view.$O\
LIB=$PLAN9/lib/libdraw.a
UPDATE=\
mkfile\
${OFILES:%.$O=%.c}\
pdfprolog.ps\
$HFILES\
<$PLAN9/src/mkone <$PLAN9/src/mkone
BIN=$PLAN9/bin
pdfprolog.c: pdfprolog.ps pdfprolog.c: pdfprolog.ps
cat pdfprolog.ps | sed 's/.*/"&\\n"/g' >pdfprolog.c cat pdfprolog.ps | sed 's/.*/"&\\n"/g' >pdfprolog.c

View file

@ -15,15 +15,15 @@
#include <libc.h> #include <libc.h>
#include <bio.h> #include <bio.h>
#include <draw.h> #include <draw.h>
#include <thread.h>
#include <cursor.h> #include <cursor.h>
#include <event.h>
#include "page.h" #include "page.h"
int ndraw = 0; int ndraw = 0;
enum { enum {
Xaxis, Xaxis,
Yaxis Yaxis,
}; };
static void reverse(Image*, Image*, int); static void reverse(Image*, Image*, int);
@ -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. * r0 is the lower rectangle, while r1 is the upper one.
*/ */
draw(tmp, tmp->r, img, nil draw(tmp, tmp->r, img, nil,
} }
void void

View file

@ -1,9 +1,10 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <thread.h>
#include <event.h> #include <thread.h>
#include <bio.h> #include <bio.h>
#include <cursor.h>
#include "page.h" #include "page.h"
int resizing; int resizing;
@ -16,10 +17,45 @@ int ppi = 100;
int teegs = 0; int teegs = 0;
int truetoboundingbox; int truetoboundingbox;
int textbits=4, gfxbits=4; int textbits=4, gfxbits=4;
int wctlfd = -1;
int stdinfd; int stdinfd;
int truecolor; int truecolor;
int imagemode; 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 static int
afmt(Fmt *fmt) afmt(Fmt *fmt)
@ -37,14 +73,15 @@ void
usage(void) usage(void)
{ {
fprint(2, "usage: page [-biRrw] [-p ppi] file...\n"); fprint(2, "usage: page [-biRrw] [-p ppi] file...\n");
exits("usage"); wexits("usage");
} }
void void
main(int argc, char **argv) threadmain(int argc, char **argv)
{ {
Document *doc; Document *doc;
Biobuf *b; Biobuf *b;
char *basename = argv[0];
enum { Ninput = 16 }; enum { Ninput = 16 };
uchar buf[Ninput+1]; uchar buf[Ninput+1];
int readstdin; int readstdin;
@ -82,7 +119,7 @@ main(int argc, char **argv)
truetoboundingbox = 1; truetoboundingbox = 1;
break; break;
case 'w': case 'w':
mknewwindow = 1; fprint(2, "%s: -w has only the effect of -R X11 systems\n", basename);
resizing = 1; resizing = 1;
break; break;
case 'i': case 'i':
@ -92,14 +129,30 @@ main(int argc, char **argv)
usage(); usage();
}ARGEND; }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); rfork(RFNOTEG);
atnotify(bell, 1);
readstdin = 0; readstdin = 0;
if(imagemode == 0 && argc == 0){ if(imagemode == 0 && argc == 0){
readstdin = 1; readstdin = 1;
stdinfd = dup(0, -1); stdinfd = dup(0, -1);
close(0); close(0);
open("/dev/cons", OREAD); open("/dev/tty", OREAD);
} }
quotefmtinstall(); quotefmtinstall();
@ -107,8 +160,9 @@ main(int argc, char **argv)
fmtinstall('R', Rfmt); fmtinstall('R', Rfmt);
fmtinstall('P', Pfmt); fmtinstall('P', Pfmt);
/*
if(mknewwindow) if(mknewwindow)
newwin(); newwin(); */
if(readstdin){ if(readstdin){
b = nil; b = nil;
@ -179,5 +233,9 @@ main(int argc, char **argv)
void void
wexits(char *s) 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);
} }

View file

@ -1,3 +1,5 @@
#undef pipe
typedef struct Document Document; typedef struct Document Document;
struct Document { struct Document {
@ -12,6 +14,31 @@ struct Document {
void *extra; 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 *emalloc(int);
void *erealloc(void*, int); void *erealloc(void*, int);
char *estrdup(char*); char *estrdup(char*);
@ -48,10 +75,10 @@ Image *resample(Image*, Image*);
/* ghostscript interface shared by ps, pdf */ /* ghostscript interface shared by ps, pdf */
typedef struct GSInfo GSInfo; typedef struct GSInfo GSInfo;
struct GSInfo { struct GSInfo {
Graphic g;
int gsfd; int gsfd;
Biobuf gsrd; Biobuf gsrd;
int gspid; int gspid;
int gsdfd;
int ppi; int ppi;
}; };
void waitgs(GSInfo*); void waitgs(GSInfo*);
@ -70,6 +97,7 @@ void wexits(char*);
Image* xallocimage(Display*, Rectangle, ulong, int, ulong); Image* xallocimage(Display*, Rectangle, ulong, int, ulong);
int bell(void*, char*); int bell(void*, char*);
int opentemp(char *template); int opentemp(char *template);
Image* convert(Graphic *g);
extern int stdinfd; extern int stdinfd;
extern int truecolor; extern int truecolor;

View file

@ -8,7 +8,7 @@
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <cursor.h>
#include <event.h> #include <thread.h>
#include <bio.h> #include <bio.h>
#include "page.h" #include "page.h"
@ -66,7 +66,7 @@ initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
fprint(2, "reading through pdf...\n"); fprint(2, "reading through pdf...\n");
if(b == nil){ /* standard input; spool to disk (ouch) */ if(b == nil){ /* standard input; spool to disk (ouch) */
fd = spooltodisk(buf, nbuf, &fn); fd = spooltodisk(buf, nbuf, &fn);
sprint(fdbuf, "/fd/%d", fd); sprint(fdbuf, "/dev/fd/%d", fd);
b = Bopen(fdbuf, OREAD); b = Bopen(fdbuf, OREAD);
if(b == nil){ if(b == nil){
fprint(2, "cannot open disk spool file\n"); fprint(2, "cannot open disk spool file\n");
@ -122,7 +122,7 @@ initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
pdf->pagebbox = emalloc(sizeof(Rectangle)*npage); pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
for(i=0; i<npage; i++) { for(i=0; i<npage; i++) {
gscmd(&pdf->gs, "%d pdfgetpage\n", i+1); 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) if(Dx(pdf->pagebbox[i]) <= 0)
pdf->pagebbox[i] = bbox; pdf->pagebbox[i] = bbox;
} }
@ -136,7 +136,7 @@ pdfdrawpage(Document *doc, int page)
Image *im; Image *im;
gscmd(&pdf->gs, "%d DoPDFPage\n", page+1); gscmd(&pdf->gs, "%d DoPDFPage\n", page+1);
im = readimage(display, pdf->gs.gsdfd, 0); im = convert(&pdf->gs.g);
if(im == nil) { if(im == nil) {
fprint(2, "fatal: readimage error %r\n"); fprint(2, "fatal: readimage error %r\n");
wexits("readimage"); wexits("readimage");

View file

@ -2,28 +2,19 @@
"/Page# 0 def\n" "/Page# 0 def\n"
"/PDFSave null def\n" "/PDFSave null def\n"
"/DSCPageCount 0 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" "\n"
"/pdfshowpage_mysetpage { % <pagedict> pdfshowpage_mysetpage <pagedict>\n" "/pdfshowpage_mysetpage { % <pagedict> pdfshowpage_mysetpage <pagedict>\n"
" dup /CropBox pget {\n" " dup /CropBox pget {\n"
" boxrect\n" " boxrect\n"
" 2 array astore /PageSize exch 4 2 roll\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" " << 5 1 roll >> setpagedevice\n"
" } if\n" " } if\n"
"} bind def\n" "} bind def\n"
"\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" "GS_PDF_ProcSet begin\n"
"pdfdict begin\n" "pdfdict begin\n"

View file

@ -2,28 +2,19 @@
/Page# 0 def /Page# 0 def
/PDFSave null def /PDFSave null def
/DSCPageCount 0 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> /pdfshowpage_mysetpage { % <pagedict> pdfshowpage_mysetpage <pagedict>
dup /CropBox pget { dup /CropBox pget {
boxrect boxrect
2 array astore /PageSize exch 4 2 roll 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 << 5 1 roll >> setpagedevice
} if } if
} bind def } 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 GS_PDF_ProcSet begin
pdfdict begin pdfdict begin

View file

@ -8,7 +8,7 @@
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <cursor.h>
#include <event.h> #include <thread.h>
#include <bio.h> #include <bio.h>
#include <ctype.h> #include <ctype.h>
#include "page.h" #include "page.h"
@ -158,7 +158,7 @@ initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
fprint(2, "reading through postscript...\n"); fprint(2, "reading through postscript...\n");
if(b == nil){ /* standard input; spool to disk (ouch) */ if(b == nil){ /* standard input; spool to disk (ouch) */
fd = spooltodisk(buf, nbuf, nil); fd = spooltodisk(buf, nbuf, nil);
sprint(fdbuf, "/fd/%d", fd); sprint(fdbuf, "/dev/fd/%d", fd);
b = Bopen(fdbuf, OREAD); b = Bopen(fdbuf, OREAD);
if(b == nil){ if(b == nil){
fprint(2, "cannot open disk spool file\n"); fprint(2, "cannot open disk spool file\n");
@ -367,7 +367,7 @@ Keepreading:
if(dumb) { if(dumb) {
fprint(ps->gs.gsfd, "(%s) run\n", argv[0]); 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; ps->bbox = bbox;
@ -417,7 +417,7 @@ psdrawpage(Document *d, int page)
Image *im; Image *im;
if(ps->clueless) if(ps->clueless)
return readimage(display, ps->gs.gsdfd, 0); return convert(&ps->gs.g);
waitgs(&ps->gs); waitgs(&ps->gs);
@ -433,7 +433,7 @@ psdrawpage(Document *d, int page)
* so send one to avoid deadlock. * so send one to avoid deadlock.
*/ */
write(ps->gs.gsfd, "\n", 1); write(ps->gs.gsfd, "\n", 1);
im = readimage(display, ps->gs.gsdfd, 0); im = convert(&ps->gs.g);
if(im == nil) { if(im == nil) {
fprint(2, "fatal: readimage error %r\n"); fprint(2, "fatal: readimage error %r\n");
wexits("readimage"); wexits("readimage");

View file

@ -15,14 +15,14 @@
#include <libc.h> #include <libc.h>
#include <bio.h> #include <bio.h>
#include <draw.h> #include <draw.h>
#include <thread.h>
#include <cursor.h> #include <cursor.h>
#include <event.h>
#include "page.h" #include "page.h"
int ndraw = 0; int ndraw = 0;
enum { enum {
Xaxis = 0, Xaxis = 0,
Yaxis = 1 Yaxis = 1,
}; };
Image *mtmp; Image *mtmp;
@ -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); drawop(tmp, tmp->r, im, nil, im->r.min, S);
switch(axis){ switch(axis){
default:
case Xaxis: case Xaxis:
range = Rect(a, im->r.min.y, c, im->r.max.y); range = Rect(a, im->r.min.y, c, im->r.max.y);
dr0 = range; dr0 = range;
@ -67,6 +66,7 @@ moveup(Image *im, Image *tmp, int a, int b, int c, int axis)
p1 = Pt(a, im->r.min.y); p1 = Pt(a, im->r.min.y);
break; break;
case Yaxis: case Yaxis:
default:
range = Rect(im->r.min.x, a, im->r.max.x, c); range = Rect(im->r.min.x, a, im->r.max.x, c);
dr0 = range; dr0 = range;
dr0.max.y = dr0.min.y+(c-b); dr0.max.y = dr0.min.y+(c-b);
@ -90,7 +90,6 @@ interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
r0 = im->r; r0 = im->r;
r1 = im->r; r1 = im->r;
switch(axis) { switch(axis) {
default:
case Xaxis: case Xaxis:
r0.max.x = n; r0.max.x = n;
r1.min.x = n; r1.min.x = n;
@ -98,6 +97,7 @@ interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
p1 = (Point){-gran, 0}; p1 = (Point){-gran, 0};
break; break;
case Yaxis: case Yaxis:
default:
r0.max.y = n; r0.max.y = n;
r1.min.y = n; r1.min.y = n;
p0 = (Point){0, gran}; p0 = (Point){0, gran};
@ -132,12 +132,12 @@ interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran)
int int
nextmask(Image *mask, int axis, int maskdim) 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); drawop(mtmp, mtmp->r, mask, nil, mask->r.min, S);
gendrawop(mask, mask->r, mtmp, delta, mtmp, divpt(delta,-2), S); gendrawop(mask, mask->r, mtmp, o, mtmp, divpt(o,-2), S);
/* writefile("mask", mask, maskdim/2); */ // writefile("mask", mask, maskdim/2);
return maskdim/2; return maskdim/2;
} }
@ -153,13 +153,13 @@ shuffle(Image *im, Image *tmp, int axis, int n, Image *mask, int gran,
nn = n - left; nn = n - left;
interlace(im, tmp, axis, nn, mask, gran); interlace(im, tmp, axis, nn, mask, gran);
/* writefile("interlace", im, gran); */ // writefile("interlace", im, gran);
gran = nextmask(mask, axis, gran); gran = nextmask(mask, axis, gran);
shuffle(im, tmp, axis, n, mask, gran, nn); shuffle(im, tmp, axis, n, mask, gran, nn);
/* writefile("shuffle", im, gran); */ // writefile("shuffle", im, gran);
moveup(im, tmp, lastnn, nn, n, axis); moveup(im, tmp, lastnn, nn, n, axis);
/* writefile("move", im, gran); */ // writefile("move", im, gran);
} }
void void
@ -198,7 +198,7 @@ rot180(Image *im)
} }
rmask.max.x = gran; rmask.max.x = gran;
drawop(mask, rmask, display->opaque, nil, ZP, S); 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); shuffle(im, tmp, Xaxis, Dx(im->r), mask, gran, 0);
freeimage(mask); freeimage(mask);
freeimage(mtmp); freeimage(mtmp);
@ -309,11 +309,11 @@ i0(double x)
} }
double 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 0.;
return i0(alpha*sqrt(1-(x*x/(tau*tau))))/i0(alpha); return i0(a*sqrt(1-(x*x/(t*t))))/i0(a);
} }

View file

@ -1,9 +1,9 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <thread.h>
#include <event.h>
#include <bio.h> #include <bio.h>
#include <cursor.h>
#include "page.h" #include "page.h"
void* void*
@ -41,30 +41,6 @@ estrdup(char *s)
return t; 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. * spool standard input to /tmp.
* we've already read the initial in bytes into ibuf. * we've already read the initial in bytes into ibuf.
@ -96,37 +72,54 @@ spooltodisk(uchar *ibuf, int in, char **name)
return fd; return fd;
} }
typedef struct StdinArg StdinArg;
struct StdinArg {
Channel *cp;
uchar *ibuf;
int in;
};
/* /*
* spool standard input into a pipe. * spool standard input into a pipe.
* we've already ready the first in bytes into ibuf * we've already ready the first in bytes into ibuf
*/ */
int static void
stdinpipe(uchar *ibuf, int in) _stdinpipe(void *a)
{ {
uchar buf[8192]; uchar buf[8192];
int n; StdinArg *arg;
int p[2]; int p[2];
int n;
arg = a;
if(pipe(p) < 0){ if(pipe(p) < 0){
fprint(2, "pipe fails: %r\n"); fprint(2, "pipe fails: %r\n");
wexits("pipe"); wexits("pipe");
} }
switch(rfork(RFPROC|RFFDG)){ send(arg->cp, &p[0]);
case -1:
fprint(2, "fork fails: %r\n");
wexits("fork");
default:
close(p[1]);
return p[0];
case 0:
break;
}
close(p[0]); write(p[1], arg->ibuf, arg->in);
write(p[1], ibuf, in);
while((n = read(stdinfd, buf, sizeof buf)) > 0) while((n = read(stdinfd, buf, sizeof buf)) > 0)
write(p[1], buf, n); write(p[1], buf, n);
_exits(0); close(p[1]);
return -1; /* not reached */ threadexits(0);
}
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;
} }

View file

@ -4,17 +4,19 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <9pclient.h>
#include <draw.h> #include <draw.h>
#include <cursor.h> #include <cursor.h>
#include <cursor.h> #include <mouse.h>
#include <event.h> #include <keyboard.h>
#include <thread.h>
#include <bio.h> #include <bio.h>
#include <plumb.h> #include <plumb.h>
#include <ctype.h> #include <ctype.h>
#include <keyboard.h>
#include "page.h" #include "page.h"
Document *doc; Document *doc;
Mousectl *mc;
Image *im; Image *im;
int page; int page;
int angle = 0; int angle = 0;
@ -26,6 +28,7 @@ Point ul; /* the upper left corner of the image is at this point on the screen
Point pclip(Point, Rectangle); Point pclip(Point, Rectangle);
Rectangle mkrange(Rectangle screenr, Rectangle imr); Rectangle mkrange(Rectangle screenr, Rectangle imr);
void redraw(Image*); void redraw(Image*);
void plumbproc(void*);
Cursor reading={ Cursor reading={
{-1, -1}, {-1, -1},
@ -56,20 +59,13 @@ enum {
Middle = 2, Middle = 2,
Right = 4, Right = 4,
RMenu = 3 RMenu = 3,
}; };
void void
unhide(void) unhide(void)
{ {
static int wctl = -1; USED(nil);
if(wctl < 0)
wctl = open("/dev/wctl", OWRITE);
if(wctl < 0)
return;
write(wctl, "unhide", 6);
} }
int int
@ -126,7 +122,7 @@ showpage(int page, Menu *m)
else else
m->lasthit = reverse ? doc->npage-1-page : page; m->lasthit = reverse ? doc->npage-1-page : page;
esetcursor(&reading); setcursor(mc, &reading);
freeimage(im); freeimage(im);
if((page < 0 || page >= doc->npage) && !doc->fwdonly){ if((page < 0 || page >= doc->npage) && !doc->fwdonly){
im = nil; im = nil;
@ -169,7 +165,7 @@ showpage(int page, Menu *m)
break; break;
} }
esetcursor(nil); setcursor(mc, nil);
if(showbottom){ if(showbottom){
ul.y = screen->r.max.y - Dy(im->r); ul.y = screen->r.max.y - Dy(im->r);
showbottom = 0; showbottom = 0;
@ -186,7 +182,7 @@ writebitmap(void)
char name[64+30]; char name[64+30];
static char result[200]; static char result[200];
char *p, *q; char *p, *q;
int fd; int fd = -1;
if(im == nil) if(im == nil)
return "no image"; return "no image";
@ -209,18 +205,18 @@ writebitmap(void)
snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1); snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1);
if(access(name, 0) >= 0) { if(access(name, 0) >= 0) {
strcat(name, "XXXX"); 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"; return "couldn't think of a name for bitmap";
} else { } else {
strcpy(name, "bitXXXX"); strcpy(name, "bitXXXX");
mktemp(name); mkstemp(name);
if(access(name, 0) >= 0) if(fd < 0)
return "couldn't think of a name for bitmap"; 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); snprint(result, sizeof result, "cannot create %s: %r", name);
return result; return result;
} }
@ -265,7 +261,7 @@ enum{
Del, Del,
Write, Write,
Empty3, Empty3,
Exit Exit,
}; };
void void
@ -273,11 +269,14 @@ viewer(Document *dd)
{ {
int i, fd, n, oldpage; int i, fd, n, oldpage;
int nxt; int nxt;
Channel *cp;
Menu menu, midmenu; Menu menu, midmenu;
Mouse m; Mouse m;
Event e; Keyboardctl *kc;
Point dxy, oxy, xy0; Point dxy, oxy, xy0;
Rune run;
Rectangle r; Rectangle r;
int size[2];
Image *tmp; Image *tmp;
static char *fwditems[] = { "this page", "next page", "exit", 0 }; static char *fwditems[] = { "this page", "next page", "exit", 0 };
static char *miditems[] = { static char *miditems[] = {
@ -299,16 +298,44 @@ viewer(Document *dd)
0 0
}; };
char *s; char *s;
enum { Eplumb = 4 }; enum {
CMouse,
CResize,
CKeyboard,
CPlumb,
CN
};
Alt alts[CN+1];
Plumbmsg *pm; Plumbmsg *pm;
cp = chancreate(sizeof pm, 0);
assert(cp);
doc = dd; /* save global for menuhit */ doc = dd; /* save global for menuhit */
ul = screen->r.min; ul = screen->r.min;
einit(Emouse|Ekeyboard); mc = initmouse(nil, screen);
if(doc->addpage != nil) kc = initkeyboard(nil);
eplumb(Eplumb, "image"); 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; r.min = ZP;
/* /*
@ -336,7 +363,7 @@ viewer(Document *dd)
midmenu.lasthit = Next; midmenu.lasthit = Next;
showpage(page, &menu); showpage(page, &menu);
esetcursor(nil); setcursor(mc, nil);
nxt = 0; nxt = 0;
for(;;) { for(;;) {
@ -345,14 +372,14 @@ viewer(Document *dd)
* a fair amount. we don't care about doc->npage anymore, and * a fair amount. we don't care about doc->npage anymore, and
* all that can be done is select the next page. * all that can be done is select the next page.
*/ */
switch(eread(Emouse|Ekeyboard|Eplumb, &e)){ switch(alt(alts)) {
case Ekeyboard: case CKeyboard:
if(e.kbdc <= 0xFF && isdigit(e.kbdc)) { if(run <= 0xFF && isdigit(run)) {
nxt = nxt*10+e.kbdc-'0'; nxt = nxt*10+run-'0';
break; break;
} else if(e.kbdc != '\n') } else if(run != '\n')
nxt = 0; nxt = 0;
switch(e.kbdc) { switch(run) {
case 'r': /* reverse page order */ case 'r': /* reverse page order */
if(doc->fwdonly) if(doc->fwdonly)
break; break;
@ -372,12 +399,12 @@ viewer(Document *dd)
} }
break; break;
case 'w': /* write bitmap of current screen */ case 'w': /* write bitmap of current screen */
esetcursor(&reading); setcursor(mc, &reading);
s = writebitmap(); s = writebitmap();
if(s) if(s)
string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
display->defaultfont, s); display->defaultfont, s);
esetcursor(nil); setcursor(mc, nil);
flushimage(display, 1); flushimage(display, 1);
break; break;
case 'd': /* remove image from working set */ case 'd': /* remove image from working set */
@ -397,9 +424,9 @@ viewer(Document *dd)
case 'u': case 'u':
if(im==nil) if(im==nil)
break; break;
esetcursor(&reading); setcursor(mc, &reading);
rot180(im); rot180(im);
esetcursor(nil); setcursor(mc, nil);
angle = (angle+180) % 360; angle = (angle+180) % 360;
redraw(screen); redraw(screen);
flushimage(display, 1); flushimage(display, 1);
@ -470,15 +497,14 @@ viewer(Document *dd)
} }
break; break;
default: default:
esetcursor(&query); setcursor(mc, &query);
sleep(1000); sleep(1000);
esetcursor(nil); setcursor(mc, nil);
break; break;
} }
break; break;
case Emouse: case CMouse:
m = e.mouse;
switch(m.buttons){ switch(m.buttons){
case Left: case Left:
oxy = m.xy; oxy = m.xy;
@ -487,7 +513,7 @@ viewer(Document *dd)
dxy = subpt(m.xy, oxy); dxy = subpt(m.xy, oxy);
oxy = m.xy; oxy = m.xy;
translate(dxy); translate(dxy);
m = emouse(); recv(mc->c, &m);
} while(m.buttons == Left); } while(m.buttons == Left);
if(m.buttons) { if(m.buttons) {
dxy = subpt(xy0, oxy); dxy = subpt(xy0, oxy);
@ -499,7 +525,7 @@ viewer(Document *dd)
if(doc->npage == 0) if(doc->npage == 0)
break; break;
n = emenuhit(Middle, &m, &midmenu); n = menuhit(Middle, mc, &midmenu, nil);
if(n == -1) if(n == -1)
break; break;
switch(n){ switch(n){
@ -543,7 +569,7 @@ viewer(Document *dd)
double delta; double delta;
Rectangle r; Rectangle r;
r = egetrect(Middle, &m); r = getrect(Middle, mc);
if((rectclip(&r, rectaddpt(im->r, ul)) == 0) || if((rectclip(&r, rectaddpt(im->r, ul)) == 0) ||
Dx(r) == 0 || Dy(r) == 0) Dx(r) == 0 || Dy(r) == 0)
break; break;
@ -553,7 +579,7 @@ viewer(Document *dd)
else else
delta = (double)Dy(im->r)/(double)Dy(r); delta = (double)Dy(im->r)/(double)Dy(r);
esetcursor(&reading); setcursor(mc, &reading);
tmp = xallocimage(display, tmp = xallocimage(display,
Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)), Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)),
im->chan, 0, DBlack); im->chan, 0, DBlack);
@ -564,7 +590,7 @@ viewer(Document *dd)
resample(im, tmp); resample(im, tmp);
freeimage(im); freeimage(im);
im = tmp; im = tmp;
esetcursor(nil); setcursor(mc, nil);
ul = screen->r.min; ul = screen->r.min;
redraw(screen); redraw(screen);
flushimage(display, 1); flushimage(display, 1);
@ -580,7 +606,7 @@ viewer(Document *dd)
delta = (double)Dy(screen->r)/(double)Dy(im->r); 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)); 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); tmp = xallocimage(display, r, im->chan, 0, DBlack);
if(tmp == nil) { if(tmp == nil) {
fprint(2, "out of memory during fit: %r\n"); fprint(2, "out of memory during fit: %r\n");
@ -589,16 +615,16 @@ viewer(Document *dd)
resample(im, tmp); resample(im, tmp);
freeimage(im); freeimage(im);
im = tmp; im = tmp;
esetcursor(nil); setcursor(mc, nil);
ul = screen->r.min; ul = screen->r.min;
redraw(screen); redraw(screen);
flushimage(display, 1); flushimage(display, 1);
break; break;
} }
case Rot: /* rotate 90 */ case Rot: /* rotate 90 */
esetcursor(&reading); setcursor(mc, &reading);
im = rot90(im); im = rot90(im);
esetcursor(nil); setcursor(mc, nil);
angle = (angle+90) % 360; angle = (angle+90) % 360;
redraw(screen); redraw(screen);
flushimage(display, 1); flushimage(display, 1);
@ -606,9 +632,9 @@ viewer(Document *dd)
case Upside: /* upside-down */ case Upside: /* upside-down */
if(im==nil) if(im==nil)
break; break;
esetcursor(&reading); setcursor(mc, &reading);
rot180(im); rot180(im);
esetcursor(nil); setcursor(mc, nil);
angle = (angle+180) % 360; angle = (angle+180) % 360;
redraw(screen); redraw(screen);
flushimage(display, 1); flushimage(display, 1);
@ -628,12 +654,12 @@ viewer(Document *dd)
} }
break; break;
case Write: /* write */ case Write: /* write */
esetcursor(&reading); setcursor(mc, &reading);
s = writebitmap(); s = writebitmap();
if(s) if(s)
string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
display->defaultfont, s); display->defaultfont, s);
esetcursor(nil); setcursor(mc, nil);
flushimage(display, 1); flushimage(display, 1);
break; break;
case Del: /* delete */ case Del: /* delete */
@ -663,7 +689,7 @@ viewer(Document *dd)
break; break;
oldpage = page; oldpage = page;
n = emenuhit(RMenu, &m, &menu); n = menuhit(RMenu, mc, &menu, nil);
if(n == -1) if(n == -1)
break; break;
@ -691,9 +717,15 @@ viewer(Document *dd)
break; break;
} }
break; break;
case CResize:
case Eplumb: r = screen->r;
pm = e.v; 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){ if(pm->ndata <= 0){
plumbfree(pm); plumbfree(pm);
break; break;
@ -866,18 +898,7 @@ redraw(Image *screen)
} }
} }
border(screen, r, -4000, gray, ZP); border(screen, r, -4000, gray, ZP);
/* flushimage(display, 0); */ // 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);
} }
/* clip p to be in r */ /* clip p to be in r */
@ -909,21 +930,17 @@ resize(int dx, int dy)
static Rectangle sr; static Rectangle sr;
Rectangle r, or; Rectangle r, or;
dx += 2*Borderwidth; r = screen->r;
dy += 2*Borderwidth; if(Dx(sr)*Dy(sr) == 0) {
if(wctlfd < 0){ sr = screenrect();
wctlfd = open("/dev/wctl", OWRITE); /* Start with the size of the first image */
if(wctlfd < 0) r.max.x = r.min.x;
return; r.max.y = r.min.y;
} }
r = insetrect(screen->r, -Borderwidth);
if(Dx(r) >= dx && Dy(r) >= dy) if(Dx(r) >= dx && Dy(r) >= dy)
return; return;
if(Dx(sr)*Dy(sr) == 0)
sr = screenrect();
or = r; or = r;
r.max.x = max(r.min.x+dx, r.max.x); 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)) if(Dx(r) == Dx(or) && Dy(r) == Dy(or))
return; return;
fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n", drawresizewindow(r);
r.min.x, r.min.y, r.max.x, r.max.y);
} }
/* /*
@ -966,129 +982,73 @@ xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
return allocimage(d, r, chan, repl, 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 void
newwin(void) plumbproc(void *c)
{ {
char *srv, *mntsrv; Channel *cp;
char spec[100]; CFid *fd;
int srvfd, cons, pid;
switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ cp = c;
case -1: fd = plumbopenfid("image", OREAD|OCEXEC);
fprint(2, "page: can't fork: %r\n"); if(fd == nil) {
wexits("no fork"); fprint(2, "Cannot connect to the plumber");
case 0: threadexits("plumber");
break;
default:
wexits(0);
} }
for(;;) {
srv = rdenv("/env/wsys"); send(cp, plumbrecvfid(fd));
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");
}
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 Rectangle
screenrect(void) screenrect(void)
{ {
int fd; int fd[3], pfd[2];
char buf[12*5]; int n, w, h;
char buf[64];
char *p, *pr;
fd = open("/dev/screen", OREAD); if(pipe(pfd) < 0)
if(fd == -1) wexits("pipe failed");
fd=open("/mnt/term/dev/screen", OREAD);
if(fd == -1){ fd[0] = open("/dev/null", OREAD);
fprint(2, "page: can't open /dev/screen: %r\n"); fd[1] = pfd[1];
wexits("window read"); fd[2] = dup(2, -1);
} if(threadspawnl(fd, "rc", "rc", "-c", "xdpyinfo | grep 'dimensions:'", nil) == -1)
if(read(fd, buf, sizeof buf) != sizeof buf){ wexits("threadspawnl failed");
fprint(2, "page: can't read /dev/screen: %r\n");
wexits("screen read"); if((n = read(pfd[0], buf, 63)) <= 0)
} wexits("read xdpyinfo failed");
close(fd); close(fd[0]);
return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
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 void
zerox(void) zerox(void)
{ {
int pfd[2]; int pfd[2];
int fd[3];
pipe(pfd); pipe(pfd);
switch(rfork(RFFDG|RFPROC)) { fd[0] = pfd[0];
case -1: fd[1] = dup(1, -1);
wexits("cannot fork in zerox: %r"); fd[2] = dup(2, -1);
case 0: threadspawnl(fd, "page", "page", "-R", nil);
dup(pfd[1], 0);
close(pfd[0]); writeimage(pfd[1], im, 0);
execl("/bin/page", "page", "-w", nil);
wexits("cannot exec in zerox: %r\n");
default:
close(pfd[1]); close(pfd[1]);
writeimage(pfd[0], im, 0);
close(pfd[0]);
break;
}
} }