9 typedef struct Page Page;
42 ulong imemlimit = 8*MiB;
45 Image *frame, *paper, *ground;
47 char pagespool[] = "/tmp/pagespool.";
79 [Corigsize] "orig size", 'o', Kesc, 0,
80 [Czoomin] "zoom in", '+', 0, 0,
81 [Czoomout] "zoom out", '-', 0, 0,
82 [Cfitwidth] "fit width", 'f', 0, 0,
83 [Cfitheight] "fit height", 'h', 0, 0,
84 [Crotate90] "rotate 90", 'r', 0, 0,
85 [Cupsidedown] "upside down", 'u', 0, 0,
86 [Cdummy1] "", 0, 0, 0,
87 [Cnext] "next", Kright, ' ', '\n',
88 [Cprev] "prev", Kleft, Kbs, 0,
89 [Czerox] "zerox", 'z', 0, 0,
90 [Cwrite] "write", 'w', 0, 0,
91 [Cext] "ext", 'x', 0, 0,
92 [Cdummy2] "", 0, 0, 0,
93 [Cquit] "quit", 'q', Kdel, Keof,
96 char *pagemenugen(int i);
97 char *cmdmenugen(int i);
113 {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00,
114 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0,
115 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0,
116 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
117 {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00,
118 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0,
119 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
120 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
123 void showpage1(Page *);
124 void showpage(Page *);
125 void drawpage(Page *);
126 Point pagesize(Page *);
129 addpage(Page *up, char *label, int (*popen)(Page *), void *pdata, int fd)
133 p = mallocz(sizeof(*p), 1);
134 p->label = strdup(label);
147 up->down = up->tail = p;
155 if(up && current == up)
161 resizewin(Point size)
165 if((wctl = open("/dev/wctl", OWRITE)) < 0)
168 size = addpt(size, Pt(Borderwidth*2, Borderwidth*2));
170 Point dsize = subpt(display->image->r.max, display->image->r.min);
175 /* can't just conver whole display */
176 if(eqpt(size, dsize))
179 fprint(wctl, "resize -dx %d -dy %d\n", size.x, size.y);
188 snprint(nam, sizeof nam, "%s%s%.12d%.8lux", pagespool, pfx, getpid(), id++);
189 return create(nam, OEXCL|ORCLOSE|ORDWR, 0600);
193 catchnote(void *, char *msg)
195 if(strstr(msg, "sys: write on closed pipe"))
197 if(strstr(msg, "hangup"))
199 if(strstr(msg, "alarm"))
201 if(strstr(msg, "interrupt"))
203 if(strstr(msg, "kill"))
216 for(mfd = 0; fd >= 0; fd = va_arg(arg, int), mfd++)
221 if((fd = open("/fd", OREAD)) < 0)
222 sysfatal("open: %r");
223 n = dirreadall(fd, &dir);
225 if(strstr(dir[i].name, "ctl"))
227 fd = atoi(dir[i].name);
235 pipeline(int fd, char *fmt, ...)
237 char buf[NPATH], *argv[4];
247 vsnprint(buf, sizeof buf, fmt, arg);
249 switch(rfork(RFPROC|RFMEM|RFFDG|RFREND|RFNOWAIT)){
255 dupfds(fd, pfd[1], 2, -1);
260 exec("/bin/rc", argv);
261 sysfatal("exec: %r");
273 while(strlen(s) > 20){
274 if((x = strchr(s, '/')) == nil)
292 if((fd = dup(p->fd, -1)) < 0){
301 if(strcmp(p->ext, "ico") == 0)
302 snprint(nam, sizeof(nam), "%s -c", p->ext);
304 snprint(nam, sizeof(nam), "%s -t9", p->ext);
305 pipeline(fd, "%s", nam);
309 * dont keep the file descriptor arround if it can simply
312 fd2path(p->fd, nam, sizeof(nam));
313 if(strncmp(nam, pagespool, strlen(pagespool))){
316 p->data = strdup(nam);
328 pipeline(p->fd, "%s", (char*)p->data);
338 char mnt[32], cmd[64], *argv[4];
341 snprint(mnt, sizeof(mnt), "/n/tapefs.%.12d%.8lux", getpid(), (ulong)p);
342 snprint(cmd, sizeof(cmd), "%s -m %s /fd/0", (char*)p->data, mnt);
343 switch(rfork(RFPROC|RFMEM|RFFDG|RFREND)){
349 dupfds(p->fd, 1, 2, -1);
354 exec("/bin/rc", argv);
355 sysfatal("exec: %r");
360 p->data = strdup(mnt);
368 char buf[NPATH], *s, *e;
374 e = buf+sizeof(buf)-1;
375 s += snprint(s, e-s, "%s/", (char*)p->data);
378 pipeline(fd, "awk '/\\<rootfile/{"
379 "if(match($0, /full\\-path\\=\\\"([^\\\"]+)\\\"/)){"
380 "print substr($0, RSTART+11,RLENGTH-12);exit}}'");
381 n = read(fd, s, e - s);
385 while(n > 0 && s[n-1] == '\n')
389 if((fd = open(buf, OREAD)) < 0)
391 pipeline(fd, "awk '/\\<item/{"
392 "if(match($0, /id\\=\\\"([^\\\"]+)\\\"/)){"
393 "id=substr($0, RSTART+4, RLENGTH-5);"
394 "if(match($0, /href\\=\\\"([^\\\"]+)\\\"/)){"
395 "item[id]=substr($0, RSTART+6, RLENGTH-7)}}};"
397 "if(match($0, /idref\\=\\\"([^\\\"]+)\\\"/)){"
398 "ref=substr($0, RSTART+7, RLENGTH-8);"
399 "print item[ref]; fflush}}'");
400 s = strrchr(buf, '/')+1;
401 while((n = read(fd, s, e-s)) > 0){
402 while(n > 0 && s[n-1] == '\n')
405 addpage(p, shortname(buf), popenfile, strdup(buf), -1);
411 typedef struct Ghost Ghost;
430 switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT)){
438 dupfds(gs->pdat, gs->pin, pfd[1], -1);
439 fprint(1, "%s DoPDFPage\n"
442 "dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring "
443 "flushfile\n", p->label);
444 while((n = read(0, buf, sizeof buf)) > 0){
445 if(memcmp(buf, "THIS IS NOT AN INFERNO BITMAP\n", 30) == 0)
457 infernobithdr(char *buf, int n)
460 if(memcmp(buf, "compressed\n", 11) == 0)
462 if(strtochan((char*)buf))
464 if(memcmp(buf, " ", 10) == 0 &&
465 '0' <= buf[10] && buf[10] <= '9' &&
475 int n, i, pdf, ifd, ofd, pin[2], pout[2], pdat[2];
476 char buf[NBUF], nam[32], *argv[16];
482 if(read(ifd, buf, 5) != 5)
485 if(memcmp(buf, "%PDF-", 5) == 0)
505 argv[0] = (char*)p->data;
506 switch(rfork(RFPROC|RFMEM|RFFDG|RFREND|RFNOWAIT)){
511 dupfds(pin[1], pout[1], 2, pdat[1], ifd, -1);
513 dupfds(nullfd, nullfd, 2, pdat[1], ifd, -1);
515 pipeline(4, "%s", argv[0]);
518 argv[2] = "-sDEVICE=plan9";
519 argv[3] = "-sOutputFile=/fd/3";
521 argv[5] = pdf ? "-dDELAYSAFER" : "-dSAFER";
523 argv[7] = "-dTextAlphaBits=4";
524 argv[8] = "-dGraphicsAlphaBits=4";
525 snprint(buf, sizeof buf, "-r%d", ppi);
527 argv[10] = "-dDOINTERPOLATE";
528 argv[11] = pdf ? "-" : "/fd/4";
530 exec("/bin/gs", argv);
531 sysfatal("exec: %r");
542 "/PAGEOUT (/fd/1) (w) file def\n"
543 "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n"
547 "/PDFSave null def\n"
548 "/DSCPageCount 0 def\n"
549 "/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def\n"
551 "GS_PDF_ProcSet begin\n"
553 "(/fd/4) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n"
555 "pdfpagecount PAGE==\n";
558 if(write(pin[0], prolog, n) != n)
560 if((n = read(pout[0], buf, sizeof(buf)-1)) < 0)
568 gs = mallocz(sizeof(*gs), 1);
573 snprint(nam, sizeof nam, "%d", i);
574 addpage(p, nam, popenpdf, gs, -1);
577 /* keep ghostscript arround */
582 while((n = read(pdat[0], buf, sizeof(buf))) >= 0){
583 if(ofd >= 0 && (n <= 0 || infernobithdr(buf, n))){
584 snprint(nam, sizeof nam, "%d", i);
585 addpage(p, nam, popenimg, nil, ofd);
591 snprint(nam, sizeof nam, "%.4d", ++i);
592 if((ofd = createtmp(nam)) < 0)
593 ofd = dup(nullfd, -1);
595 if(write(ofd, buf, n) != n)
609 filetype(char *buf, int nbuf, char *typ, int ntyp)
611 int n, ifd[2], ofd[2];
614 if(infernobithdr(buf, nbuf)){
615 strncpy(typ, "image/p9bit", ntyp);
627 if(rfork(RFPROC|RFMEM|RFFDG|RFREND|RFNOWAIT) == 0){
628 dupfds(ifd[1], ofd[1], 2, -1);
632 exec("/bin/file", argv);
636 if(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT) == 0){
642 if((n = readn(ofd[0], typ, ntyp-1)) < 0)
645 while(n > 0 && typ[n-1] == '\n')
652 dircmp(void *p1, void *p2)
659 return strcmp(d1->name, d2->name);
670 "application/pdf", popengs, nil,
671 "application/postscript", popengs, nil,
672 "application/troff", popengs, "lp -dstdout",
673 "text/plain", popengs, "lp -dstdout",
674 "text/html", popengs, "uhtml | html2ms | tbl | troff -ms | lp -dstdout",
675 "application/dvi", popengs, "dvips -Pps -r0 -q1 -f1",
676 "application/doc", popengs, "doc2ps",
677 "application/zip", popentape, "fs/zipfs",
678 "application/x-tar", popentape, "fs/tarfs",
679 "application/x-ustar", popentape, "fs/tarfs",
680 "application/x-compress", popenfilter, "uncompress",
681 "application/x-gzip", popenfilter, "gunzip",
682 "application/x-bzip2", popenfilter, "bunzip2",
683 "image/gif", popenimg, "gif",
684 "image/jpeg", popenimg, "jpg",
685 "image/png", popenimg, "png",
686 "image/tiff", popenimg, "tif",
687 "image/ppm", popenimg, "ppm",
688 "image/bmp", popenimg, "bmp",
689 "image/tga", popenimg, "tga",
690 "image/x-icon", popenimg, "ico",
691 "image/p9bit", popenimg, nil,
694 char buf[NBUF], typ[128], *file;
704 if((fd = open(file, OREAD)) < 0){
711 if((d = dirfstat(fd)) == nil){
720 snprint(buf, sizeof(buf), "%s/META-INF/container.xml", file);
721 if((tfd = open(buf, OREAD)) >= 0){
729 if((n = dirreadall(fd, &d)) < 0)
731 qsort(d, n, sizeof d[0], dircmp);
733 addpage(p, d[i].name, popenfile, smprint("%s/%s", file, d[i].name), -1);
739 memset(buf, 0, NBUF/2);
740 if((n = readn(fd, buf, NBUF/2)) <= 0)
742 filetype(buf, n, typ, sizeof(typ));
743 for(i=0; i<nelem(tab); i++)
744 if(strncmp(typ, tab[i].typ, strlen(tab[i].typ)) == 0)
747 werrstr("unknown image format: %s", typ);
751 p->data = tab[i].data;
752 p->open = tab[i].open;
753 if(seek(fd, 0, 0) < 0)
755 if((i = readn(fd, buf+n, n)) < 0)
757 if(i != n || memcmp(buf, buf+n, i)){
760 if((tfd = createtmp("file")) < 0)
763 if(write(tfd, buf, n) != n)
765 if((n = read(fd, buf, sizeof(buf))) < 0)
768 if(dup(tfd, fd) < 0){
798 for(p = root->down; p; p = t)
799 if((t = nextpage(p)) == x)
811 if(p->open == nil || (fd = p->open(p)) < 0)
815 pipeline(fd, "rotate -r %d", rotate);
817 pipeline(fd, "resize -x %d", resize.x);
819 pipeline(fd, "resize -y %d", resize.y);
829 return Dy(i->r)*bytesperline(i->r, i->depth);
837 if(p->open && p->image == nil){
840 if((p->image = readimage(display, fd, 1)) == nil)
841 fprint(2, "readimage: %r\n");
847 lockdisplay(display);
848 imemsize += imagesize(p->image);
849 unlockdisplay(display);
857 if(p->open == nil || p->image == nil)
859 lockdisplay(display);
860 imemsize -= imagesize(p->image);
862 unlockdisplay(display);
867 unloadpages(ulong limit)
871 for(p = root->down; p && imemsize >= limit; p = nextpage(p)){
879 loadpages(Page *p, int oviewgen)
881 while(p && viewgen == oviewgen){
884 if(viewgen != oviewgen){
894 if(size.x && size.y && newwin){
898 lockdisplay(display);
900 unlockdisplay(display);
903 if(p != current || imemsize >= imemlimit)
910 * A draw operation that touches only the area contained in bot but not in top.
911 * mp and sp get aligned with bot.min.
914 gendrawdiff(Image *dst, Rectangle bot, Rectangle top,
915 Image *src, Point sp, Image *mask, Point mp, int op)
921 if(Dx(bot)*Dy(bot) == 0)
924 /* no points in bot - top */
925 if(rectinrect(bot, top))
928 /* bot - top ≡ bot */
929 if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){
930 gendrawop(dst, bot, src, sp, mask, mp, op);
935 /* split bot into rectangles that don't intersect top */
937 if(bot.min.x < top.min.x){
938 r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y);
939 delta = subpt(r.min, origin);
940 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
941 bot.min.x = top.min.x;
945 if(bot.max.x > top.max.x){
946 r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y);
947 delta = subpt(r.min, origin);
948 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
949 bot.max.x = top.max.x;
953 if(bot.min.y < top.min.y){
954 r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y);
955 delta = subpt(r.min, origin);
956 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
957 bot.min.y = top.min.y;
961 if(bot.max.y > top.max.y){
962 r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y);
963 delta = subpt(r.min, origin);
964 gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
965 bot.max.y = top.max.y;
970 alphachan(ulong chan)
972 for(; chan; chan >>= 8)
973 if(TYPE(chan) == CAlpha)
979 zoomdraw(Image *d, Rectangle r, Rectangle top, Image *b, Image *s, Point sp, int f)
987 if(r.min.x < d->r.min.x){
988 sp.x += (d->r.min.x - r.min.x)/f;
989 a.x = (d->r.min.x - r.min.x)%f;
990 r.min.x = d->r.min.x;
992 if(r.min.y < d->r.min.y){
993 sp.y += (d->r.min.y - r.min.y)/f;
994 a.y = (d->r.min.y - r.min.y)%f;
995 r.min.y = d->r.min.y;
998 w = s->r.max.x - sp.x;
1002 dr.max.x = dr.min.x+w;
1003 if(!alphachan(s->chan))
1006 if(b) gendrawdiff(d, dr, top, b, sp, nil, ZP, SoverD);
1007 gendrawdiff(d, dr, top, s, sp, nil, ZP, SoverD);
1010 if((t = allocimage(display, dr, s->chan, 0, 0)) == nil)
1012 for(; dr.min.y < r.max.y; dr.min.y++){
1013 dr.max.y = dr.min.y+1;
1014 draw(t, dr, s, nil, sp);
1021 for(sp=dr.min; dr.min.x < r.max.x; sp.x++){
1022 dr.max.x = dr.min.x+1;
1023 if(b) gendrawdiff(d, dr, top, b, sp, nil, ZP, SoverD);
1024 gendrawdiff(d, dr, top, t, sp, nil, ZP, SoverD);
1025 for(dr.min.x++; ++a.x < f && dr.min.x < r.max.x; dr.min.x++){
1026 dr.max.x = dr.min.x+1;
1027 gendrawdiff(d, dr, top, d, Pt(dr.min.x-1, dr.min.y), nil, ZP, SoverD);
1037 return p->image ? mulpt(subpt(p->image->r.max, p->image->r.min), zoom) : ZP;
1041 drawframe(Rectangle r)
1043 border(screen, r, -Borderwidth, frame, ZP);
1044 gendrawdiff(screen, screen->r, insetrect(r, -Borderwidth), ground, ZP, nil, ZP, SoverD);
1045 flushimage(display, 1);
1055 r = rectaddpt(Rpt(ZP, pagesize(p)), addpt(pos, screen->r.min));
1056 zoomdraw(screen, r, ZR, paper, i, i->r.min, zoom);
1058 r = Rpt(ZP, stringsize(font, p->label));
1059 r = rectaddpt(r, addpt(subpt(divpt(subpt(screen->r.max, screen->r.min), 2),
1060 divpt(r.max, 2)), screen->r.min));
1061 draw(screen, r, paper, nil, ZP);
1062 string(screen, r.min, display->black, ZP, font, p->label);
1068 translate(Page *p, Point d)
1074 if(i==0 || d.x==0 && d.y==0)
1076 r = rectaddpt(Rpt(ZP, pagesize(p)), addpt(pos, screen->r.min));
1077 pos = addpt(pos, d);
1078 nr = rectaddpt(r, d);
1079 rectclip(&r, screen->r);
1080 draw(screen, rectaddpt(r, d), screen, nil, r.min);
1081 zoomdraw(screen, nr, rectaddpt(r, d), paper, i, i->r.min, zoom);
1086 findpage(char *name)
1092 /* look in current document first */
1093 if(current && current->up){
1094 for(p = current->up->down; p; p = p->next)
1095 if(cistrncmp(p->label, name, n) == 0)
1098 /* look everywhere */
1099 for(p = root->down; p; p = nextpage(p))
1100 if(cistrncmp(p->label, name, n) == 0)
1110 for(p = root->down; i > 0 && p; p = nextpage(p))
1121 for(i = 0, p = root->down; p && p != x; p = nextpage(p))
1123 return (p == x) ? i : -1;
1138 if(i < 0 || i >= nelem(cmds))
1144 * spawn new proc to load a run of pages starting with p
1145 * the display should *not* be locked as it gets called
1146 * from recursive page load.
1156 esetcursor(&reading);
1159 switch(rfork(RFPROC|RFMEM)){
1161 sysfatal("rfork: %r");
1163 loadpages(p, oviewgen);
1166 if(++nproc >= NPROC)
1171 /* recursive display lock, called from main proc only */
1173 drawlock(int dolock){
1177 lockdisplay(display);
1180 unlockdisplay(display);
1192 unloadpages(imemlimit/2);
1202 for(p = nextpage(current); p; p = nextpage(p))
1203 if(p->image || p->open)
1213 for(p = prevpage(current); p; p = prevpage(p))
1214 if(p->image || p->open)
1222 char nam[64], *argv[4];
1229 if((fd = openpage(p)) < 0)
1231 if(rfork(RFPROC|RFMEM|RFFDG|RFENVG|RFNOTEG|RFNOWAIT) == 0){
1232 dupfds(fd, 1, 2, -1);
1233 snprint(nam, sizeof nam, "/bin/%s", argv0);
1238 sysfatal("exec: %r");
1249 char buf[128], label[64], *argv[4];
1255 snprint(label, sizeof(label), "%s %s", p->ext, p->label);
1258 ps = addpt(subpt(p->image->r.max, p->image->r.min), Pt(24, 24));
1260 if((fd = p->fd) < 0){
1261 if(p->open != popenfile)
1263 fd = open((char*)p->data, OREAD);
1268 if(rfork(RFPROC|RFMEM|RFFDG|RFNOTEG|RFNAMEG|RFNOWAIT) == 0){
1269 snprint(buf, sizeof(buf), "-pid %d", getpid());
1270 if(newwindow(buf) != -1){
1271 dupfds(fd, 1, 2, -1);
1272 if((fd = open("/dev/label", OWRITE)) >= 0){
1273 write(fd, label, strlen(label));
1282 exec("/bin/rc", argv);
1297 if(new && getwindow(display, Refnone) == -1)
1298 sysfatal("getwindow: %r");
1309 void killcohort(void)
1312 for(i=0;i!=3;i++){ /* It's a long way to the kitchen */
1313 postnote(PNGROUP, cohort, "kill");
1318 void drawerr(Display *, char *msg)
1320 sysfatal("draw: %s", msg);
1326 fprint(2, "usage: %s [ -iRw ] [ -m mb ] [ -p ppi ] [ file ... ]\n", argv0);
1331 docmd(int i, Mouse *m)
1333 char buf[NPATH], *s;
1359 resize = subpt(screen->r.max, screen->r.min);
1365 resize = subpt(screen->r.max, screen->r.min);
1370 if(current == nil || !canqlock(current))
1372 o = subpt(m->xy, screen->r.min);
1376 pos = addpt(mulpt(subpt(pos, o), 2), o);
1381 pos = addpt(divpt(subpt(pos, o), 2), o);
1388 if(current == nil || !canqlock(current))
1392 if(current->up && current->up != root)
1393 s = current->up->label;
1394 snprint(buf, sizeof(buf), "%s%s%s.bit",
1398 if(eenter("Write", buf, sizeof(buf), m) > 0){
1399 if((fd = create(buf, OWRITE, 0666)) < 0){
1400 errstr(buf, sizeof(buf));
1401 eenter(buf, 0, 0, m);
1403 esetcursor(&reading);
1404 writeimage(fd, current->image, 0);
1413 if(current == nil || !canqlock(current))
1433 main(int argc, char *argv[])
1435 enum { Eplumb = 4 };
1461 imemlimit = atol(EARGF(usage()))*MiB;
1464 ppi = atoi(EARGF(usage()));
1471 * so that we can stop all subprocesses with a note,
1472 * and to isolate rendezvous from other processes
1474 atnotify(catchnote, 1);
1475 if(cohort = rfork(RFPROC|RFNOTEG|RFNAMEG|RFREND)){
1484 s = smprint("-pid %d", getpid());
1485 if(newwindow(s) < 0)
1486 sysfatal("newwindow: %r");
1489 if(initdraw(drawerr, nil, argv0) < 0)
1490 sysfatal("initdraw: %r");
1491 paper = display->white;
1492 frame = display->black;
1493 ground = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x777777FF);
1494 display->locking = 1;
1495 unlockdisplay(display);
1498 einit(Ekeyboard|Emouse);
1499 eplumb(Eplumb, "image");
1500 memset(&m, 0, sizeof(m));
1501 if((nullfd = open("/dev/null", ORDWR)) < 0)
1502 sysfatal("open: %r");
1503 current = root = addpage(nil, "", nil, nil, -1);
1504 if(*argv == nil && !imode)
1505 addpage(root, "stdin", popenfile, strdup("/fd/0"), -1);
1506 for(; *argv; argv++)
1507 addpage(root, shortname(*argv), popenfile, strdup(*argv), -1);
1518 if(current && canqlock(current)){
1522 if((m.buttons & 1) == 0)
1524 translate(current, subpt(m.xy, o));
1528 } else if(m.buttons & 2){
1530 i = emenuhit(2, &m, &cmdmenu);
1533 } else if(m.buttons & 4){
1538 pagemenu.lasthit = pageindex(current);
1539 x = pageat(emenuhit(3, &m, &pagemenu));
1548 if(current == nil || !canqlock(current))
1551 translate(current, Pt(0, Dy(screen->r)/2));
1555 if(prevpage(current))
1561 if(current == nil || !canqlock(current))
1563 o = addpt(pos, pagesize(current));
1564 if(o.y > Dy(screen->r)){
1565 translate(current, Pt(0, -Dy(screen->r)/2));
1569 if(nextpage(current))
1575 for(i = 0; i<nelem(cmds); i++)
1576 if((cmds[i].k1 == e.kbdc) ||
1577 (cmds[i].k2 == e.kbdc) ||
1578 (cmds[i].k3 == e.kbdc))
1580 if(i < nelem(cmds)){
1584 if((e.kbdc < 0x20) ||
1585 (e.kbdc & 0xFF00) == KF ||
1586 (e.kbdc & 0xFF00) == Spec)
1588 snprint(buf, sizeof(buf), "%C", (Rune)e.kbdc);
1589 if(eenter("Go to", buf, sizeof(buf), &m) > 0)
1590 showpage(findpage(buf));
1595 if(pm && pm->ndata > 0){
1599 s = plumblookup(pm->attr, "action");
1600 if(s && strcmp(s, "quit")==0)
1602 if(s && strcmp(s, "showdata")==0){
1603 if((fd = createtmp("plumb")) < 0){
1604 fprint(2, "plumb: createtmp: %r\n");
1608 if(fd2path(fd, s, NPATH) < 0){
1612 write(fd, pm->data, pm->ndata);
1613 }else if(pm->data[0] == '/'){
1614 s = strdup(pm->data);
1616 s = malloc(strlen(pm->wdir)+1+pm->ndata+1);
1617 sprint(s, "%s/%s", pm->wdir, pm->data);
1620 showpage(addpage(root, shortname(s), popenfile, s, fd));