diff options
Diffstat (limited to 'src/cmd/page/view.c')
-rw-r--r-- | src/cmd/page/view.c | 1022 |
1 files changed, 1022 insertions, 0 deletions
diff --git a/src/cmd/page/view.c b/src/cmd/page/view.c new file mode 100644 index 00000000..92aedeb9 --- /dev/null +++ b/src/cmd/page/view.c @@ -0,0 +1,1022 @@ +/* + * the actual viewer that handles screen stuff + */ + +#include <u.h> +#include <libc.h> +#include <draw.h> +#include <cursor.h> +#include <event.h> +#include <bio.h> +#include <plumb.h> +#include <ctype.h> +#include <keyboard.h> +#include "page.h" + +Document *doc; +Image *im; +int page; +int upside = 0; +int showbottom = 0; /* on the next showpage, move the image so the bottom is visible. */ + +Rectangle ulrange; /* the upper left corner of the image must be in this rectangle */ +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*); + +Cursor reading={ + {-1, -1}, + {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, + 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0, + 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0, + 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, }, + {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00, + 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0, + 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40, + 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, } +}; + +Cursor query = { + {-7,-7}, + {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, + 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, + 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, + 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, }, + {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, + 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, + 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, + 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } +}; + +enum { + Left = 1, + Middle = 2, + Right = 4, + + 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); +} + +int +max(int a, int b) +{ + return a > b ? a : b; +} + +int +min(int a, int b) +{ + return a < b ? a : b; +} + + +char* +menugen(int n) +{ + static char menustr[32]; + char *p; + int len; + + if(n == doc->npage) + return "exit"; + if(n > doc->npage) + return nil; + + if(reverse) + n = doc->npage-1-n; + + p = doc->pagename(doc, n); + len = (sizeof menustr)-2; + + if(strlen(p) > len && strrchr(p, '/')) + p = strrchr(p, '/')+1; + if(strlen(p) > len) + p = p+strlen(p)-len; + + strcpy(menustr+1, p); + if(page == n) + menustr[0] = '>'; + else + menustr[0] = ' '; + return menustr; +} + +void +showpage(int page, Menu *m) +{ + Image *tmp; + + if(doc->fwdonly) + m->lasthit = 0; /* this page */ + else + m->lasthit = reverse ? doc->npage-1-page : page; + + esetcursor(&reading); + freeimage(im); + if((page < 0 || page >= doc->npage) && !doc->fwdonly){ + im = nil; + return; + } + im = doc->drawpage(doc, page); + if(im == nil) { + if(doc->fwdonly) /* this is how we know we're out of pages */ + wexits(0); + + im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack); + if(im == nil) { + fprint(2, "out of memory: %r\n"); + wexits("memory"); + } + string(im, ZP, display->white, ZP, display->defaultfont, "?"); + }else if(resizing){ + resize(Dx(im->r), Dy(im->r)); + } + if(im->r.min.x > 0 || im->r.min.y > 0) { + tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill); + if(tmp == nil) { + fprint(2, "out of memory during showpage: %r\n"); + wexits("memory"); + } + drawop(tmp, tmp->r, im, nil, im->r.min, S); + freeimage(im); + im = tmp; + } + + if(upside) + rot180(im); + + esetcursor(nil); + if(showbottom){ + ul.y = screen->r.max.y - Dy(im->r); + showbottom = 0; + } + + redraw(screen); + flushimage(display, 1); +} + +char* +writebitmap(void) +{ + char basename[64]; + char name[64+30]; + static char result[200]; + char *p, *q; + int fd; + + if(im == nil) + return "no image"; + + memset(basename, 0, sizeof basename); + if(doc->docname) + strncpy(basename, doc->docname, sizeof(basename)-1); + else if((p = menugen(page)) && p[0] != '\0') + strncpy(basename, p+1, sizeof(basename)-1); + + if(basename[0]) { + if(q = strrchr(basename, '/')) + q++; + else + q = basename; + if(p = strchr(q, '.')) + *p = 0; + + memset(name, 0, sizeof name); + snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1); + if(access(name, 0) >= 0) { + strcat(name, "XXXX"); + mktemp(name); + } + if(access(name, 0) >= 0) + return "couldn't think of a name for bitmap"; + } else { + strcpy(name, "bitXXXX"); + mktemp(name); + if(access(name, 0) >= 0) + return "couldn't think of a name for bitmap"; + } + + if((fd = create(name, OWRITE, 0666)) < 0) { + snprint(result, sizeof result, "cannot create %s: %r", name); + return result; + } + + if(writeimage(fd, im, 0) < 0) { + snprint(result, sizeof result, "cannot writeimage: %r"); + close(fd); + return result; + } + close(fd); + + snprint(result, sizeof result, "wrote %s", name); + return result; +} + +static void translate(Point); + +static int +showdata(Plumbmsg *msg) +{ + char *s; + + s = plumblookup(msg->attr, "action"); + return s && strcmp(s, "showdata")==0; +} + +/* correspond to entries in miditems[] below, + * changing one means you need to change + */ +enum{ + Restore = 0, + Zin, + Fit, + Rot, + Upside, + Empty1, + Next, + Prev, + Zerox, + Empty2, + Reverse, + Del, + Write, + Empty3, + Exit, +}; + +void +viewer(Document *dd) +{ + int i, fd, n, oldpage; + int nxt; + Menu menu, midmenu; + Mouse m; + Event e; + Point dxy, oxy, xy0; + Rectangle r; + Image *tmp; + static char *fwditems[] = { "this page", "next page", "exit", 0 }; + static char *miditems[] = { + "orig size", + "zoom in", + "fit window", + "rotate 90", + "upside down", + "", + "next", + "prev", + "zerox", + "", + "reverse", + "discard", + "write", + "", + "quit", + 0 + }; + char *s; + enum { Eplumb = 4 }; + Plumbmsg *pm; + + doc = dd; /* save global for menuhit */ + ul = screen->r.min; + einit(Emouse|Ekeyboard); + if(doc->addpage != nil) + eplumb(Eplumb, "image"); + + esetcursor(&reading); + r.min = ZP; + + /* + * im is a global pointer to the current image. + * eventually, i think we will have a layer between + * the display routines and the ps/pdf/whatever routines + * to perhaps cache and handle images of different + * sizes, etc. + */ + im = 0; + page = reverse ? doc->npage-1 : 0; + + if(doc->fwdonly) { + menu.item = fwditems; + menu.gen = 0; + menu.lasthit = 0; + } else { + menu.item = 0; + menu.gen = menugen; + menu.lasthit = 0; + } + + midmenu.item = miditems; + midmenu.gen = 0; + midmenu.lasthit = Next; + + showpage(page, &menu); + esetcursor(nil); + + nxt = 0; + for(;;) { + /* + * throughout, if doc->fwdonly is set, we restrict the functionality + * a fair amount. we don't care about doc->npage anymore, and + * all that can be done is select the next page. + */ + switch(eread(Emouse|Ekeyboard|Eplumb, &e)){ + case Ekeyboard: + if(e.kbdc <= 0xFF && isdigit(e.kbdc)) { + nxt = nxt*10+e.kbdc-'0'; + break; + } else if(e.kbdc != '\n') + nxt = 0; + switch(e.kbdc) { + case 'r': /* reverse page order */ + if(doc->fwdonly) + break; + reverse = !reverse; + menu.lasthit = doc->npage-1-menu.lasthit; + + /* + * the theory is that if we are reversing the + * document order and are on the first or last + * page then we're just starting and really want + * to view the other end. maybe the if + * should be dropped and this should happen always. + */ + if(page == 0 || page == doc->npage-1) { + page = doc->npage-1-page; + showpage(page, &menu); + } + break; + case 'w': /* write bitmap of current screen */ + esetcursor(&reading); + s = writebitmap(); + if(s) + string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, + display->defaultfont, s); + esetcursor(nil); + flushimage(display, 1); + break; + case 'd': /* remove image from working set */ + if(doc->rmpage && page < doc->npage) { + if(doc->rmpage(doc, page) >= 0) { + if(doc->npage < 0) + wexits(0); + if(page >= doc->npage) + page = doc->npage-1; + showpage(page, &menu); + } + } + break; + case 'q': + case 0x04: /* ctrl-d */ + wexits(0); + case 'u': + if(im==nil) + break; + esetcursor(&reading); + rot180(im); + esetcursor(nil); + upside = !upside; + redraw(screen); + flushimage(display, 1); + break; + case '-': + case '\b': + case Kleft: + if(page > 0 && !doc->fwdonly) { + --page; + showpage(page, &menu); + } + break; + case '\n': + if(nxt) { + nxt--; + if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly) + showpage(page=nxt, &menu); + nxt = 0; + break; + } + goto Gotonext; + case Kright: + case ' ': + Gotonext: + if(doc->npage && ++page >= doc->npage && !doc->fwdonly) + wexits(0); + showpage(page, &menu); + break; + + /* + * The upper y coordinate of the image is at ul.y in screen->r. + * Panning up means moving the upper left corner down. If the + * upper left corner is currently visible, we need to go back a page. + */ + case Kup: + if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){ + if(page > 0 && !doc->fwdonly){ + --page; + showbottom = 1; + showpage(page, &menu); + } + } else { + i = Dy(screen->r)/2; + if(i > 10) + i -= 10; + if(i+ul.y > screen->r.min.y) + i = screen->r.min.y - ul.y; + translate(Pt(0, i)); + } + break; + + /* + * If the lower y coordinate is on the screen, we go to the next page. + * The lower y coordinate is at ul.y + Dy(im->r). + */ + case Kdown: + i = ul.y + Dy(im->r); + if(screen->r.min.y <= i && i <= screen->r.max.y){ + ul.y = screen->r.min.y; + goto Gotonext; + } else { + i = -Dy(screen->r)/2; + if(i < -10) + i += 10; + if(i+ul.y+Dy(im->r) <= screen->r.max.y) + i = screen->r.max.y - Dy(im->r) - ul.y - 1; + translate(Pt(0, i)); + } + break; + default: + esetcursor(&query); + sleep(1000); + esetcursor(nil); + break; + } + break; + + case Emouse: + m = e.mouse; + switch(m.buttons){ + case Left: + oxy = m.xy; + xy0 = oxy; + do { + dxy = subpt(m.xy, oxy); + oxy = m.xy; + translate(dxy); + m = emouse(); + } while(m.buttons == Left); + if(m.buttons) { + dxy = subpt(xy0, oxy); + translate(dxy); + } + break; + + case Middle: + if(doc->npage == 0) + break; + + n = emenuhit(Middle, &m, &midmenu); + if(n == -1) + break; + switch(n){ + case Next: /* next */ + if(reverse) + page--; + else + page++; + if(page < 0) { + if(reverse) return; + else page = 0; + } + + if((page >= doc->npage) && !doc->fwdonly) + return; + + showpage(page, &menu); + nxt = 0; + break; + case Prev: /* prev */ + if(reverse) + page++; + else + page--; + if(page < 0) { + if(reverse) return; + else page = 0; + } + + if((page >= doc->npage) && !doc->fwdonly && !reverse) + return; + + showpage(page, &menu); + nxt = 0; + break; + case Zerox: /* prev */ + zerox(); + break; + case Zin: /* zoom in */ + { + double delta; + Rectangle r; + + r = egetrect(Middle, &m); + if((rectclip(&r, rectaddpt(im->r, ul)) == 0) || + Dx(r) == 0 || Dy(r) == 0) + break; + /* use the smaller side to expand */ + if(Dx(r) < Dy(r)) + delta = (double)Dx(im->r)/(double)Dx(r); + else + delta = (double)Dy(im->r)/(double)Dy(r); + + esetcursor(&reading); + tmp = xallocimage(display, + Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)), + im->chan, 0, DBlack); + if(tmp == nil) { + fprint(2, "out of memory during zoom: %r\n"); + wexits("memory"); + } + resample(im, tmp); + freeimage(im); + im = tmp; + esetcursor(nil); + ul = screen->r.min; + redraw(screen); + flushimage(display, 1); + break; + } + case Fit: /* fit */ + { + double delta; + Rectangle r; + + delta = (double)Dx(screen->r)/(double)Dx(im->r); + if((double)Dy(im->r)*delta > Dy(screen->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)); + esetcursor(&reading); + tmp = xallocimage(display, r, im->chan, 0, DBlack); + if(tmp == nil) { + fprint(2, "out of memory during fit: %r\n"); + wexits("memory"); + } + resample(im, tmp); + freeimage(im); + im = tmp; + esetcursor(nil); + ul = screen->r.min; + redraw(screen); + flushimage(display, 1); + break; + } + case Rot: /* rotate 90 */ + esetcursor(&reading); + im = rot90(im); + esetcursor(nil); + redraw(screen); + flushimage(display, 1); + break; + case Upside: /* upside-down */ + if(im==nil) + break; + esetcursor(&reading); + rot180(im); + esetcursor(nil); + upside = !upside; + redraw(screen); + flushimage(display, 1); + break; + case Restore: /* restore */ + showpage(page, &menu); + break; + case Reverse: /* reverse */ + if(doc->fwdonly) + break; + reverse = !reverse; + menu.lasthit = doc->npage-1-menu.lasthit; + + if(page == 0 || page == doc->npage-1) { + page = doc->npage-1-page; + showpage(page, &menu); + } + break; + case Write: /* write */ + esetcursor(&reading); + s = writebitmap(); + if(s) + string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, + display->defaultfont, s); + esetcursor(nil); + flushimage(display, 1); + break; + case Del: /* delete */ + if(doc->rmpage && page < doc->npage) { + if(doc->rmpage(doc, page) >= 0) { + if(doc->npage < 0) + wexits(0); + if(page >= doc->npage) + page = doc->npage-1; + showpage(page, &menu); + } + } + break; + case Exit: /* exit */ + return; + case Empty1: + case Empty2: + case Empty3: + break; + + }; + + + + case Right: + if(doc->npage == 0) + break; + + oldpage = page; + n = emenuhit(RMenu, &m, &menu); + if(n == -1) + break; + + if(doc->fwdonly) { + switch(n){ + case 0: /* this page */ + break; + case 1: /* next page */ + showpage(++page, &menu); + break; + case 2: /* exit */ + return; + } + break; + } + + if(n == doc->npage) + return; + else + page = reverse ? doc->npage-1-n : n; + + if(oldpage != page) + showpage(page, &menu); + nxt = 0; + break; + } + break; + + case Eplumb: + pm = e.v; + if(pm->ndata <= 0){ + plumbfree(pm); + break; + } + if(showdata(pm)) { + s = estrdup("/tmp/pageplumbXXXXXXX"); + fd = opentemp(s); + write(fd, pm->data, pm->ndata); + /* lose fd reference on purpose; the file is open ORCLOSE */ + } else if(pm->data[0] == '/') { + s = estrdup(pm->data); + } else { + s = emalloc(strlen(pm->wdir)+1+pm->ndata+1); + sprint(s, "%s/%s", pm->wdir, pm->data); + cleanname(s); + } + if((i = doc->addpage(doc, s)) >= 0) { + page = i; + unhide(); + showpage(page, &menu); + } + free(s); + plumbfree(pm); + break; + } + } +} + +Image *gray; + +/* + * A draw operation that touches only the area contained in bot but not in top. + * mp and sp get aligned with bot.min. + */ +static void +gendrawdiff(Image *dst, Rectangle bot, Rectangle top, + Image *src, Point sp, Image *mask, Point mp, int op) +{ + Rectangle r; + Point origin; + Point delta; + + USED(op); + + if(Dx(bot)*Dy(bot) == 0) + return; + + /* no points in bot - top */ + if(rectinrect(bot, top)) + return; + + /* bot - top ≡ bot */ + if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){ + gendrawop(dst, bot, src, sp, mask, mp, op); + return; + } + + origin = bot.min; + /* split bot into rectangles that don't intersect top */ + /* left side */ + if(bot.min.x < top.min.x){ + r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y); + delta = subpt(r.min, origin); + gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); + bot.min.x = top.min.x; + } + + /* right side */ + if(bot.max.x > top.max.x){ + r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y); + delta = subpt(r.min, origin); + gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); + bot.max.x = top.max.x; + } + + /* top */ + if(bot.min.y < top.min.y){ + r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y); + delta = subpt(r.min, origin); + gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); + bot.min.y = top.min.y; + } + + /* bottom */ + if(bot.max.y > top.max.y){ + r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y); + delta = subpt(r.min, origin); + gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); + bot.max.y = top.max.y; + } +} + +static void +drawdiff(Image *dst, Rectangle bot, Rectangle top, Image *src, Image *mask, Point p, int op) +{ + gendrawdiff(dst, bot, top, src, p, mask, p, op); +} + +/* + * Translate the image in the window by delta. + */ +static void +translate(Point delta) +{ + Point u; + Rectangle r, or; + + if(im == nil) + return; + + u = pclip(addpt(ul, delta), ulrange); + delta = subpt(u, ul); + if(delta.x == 0 && delta.y == 0) + return; + + /* + * The upper left corner of the image is currently at ul. + * We want to move it to u. + */ + or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul); + r = rectaddpt(or, delta); + + drawop(screen, r, screen, nil, ul, S); + ul = u; + + /* fill in gray where image used to be but isn't. */ + drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP, S); + + /* fill in black border */ + drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S); + + /* fill in image where it used to be off the screen. */ + if(rectclip(&or, screen->r)) + drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min, S); + else + drawop(screen, r, im, nil, im->r.min, S); + flushimage(display, 1); +} + +void +redraw(Image *screen) +{ + Rectangle r; + + if(im == nil) + return; + + ulrange.max = screen->r.max; + ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r))); + + ul = pclip(ul, ulrange); + drawop(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min)), S); + + if(im->repl) + return; + + /* fill in any outer edges */ + /* black border */ + r = rectaddpt(im->r, subpt(ul, im->r.min)); + border(screen, r, -2, display->black, ZP); + r.min = subpt(r.min, Pt(2,2)); + r.max = addpt(r.max, Pt(2,2)); + + /* gray for the rest */ + if(gray == nil) { + gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF); + if(gray == nil) { + fprint(2, "g out of memory: %r\n"); + wexits("mem"); + } + } + 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); +} + +/* clip p to be in r */ +Point +pclip(Point p, Rectangle r) +{ + if(p.x < r.min.x) + p.x = r.min.x; + else if(p.x >= r.max.x) + p.x = r.max.x-1; + + if(p.y < r.min.y) + p.y = r.min.y; + else if(p.y >= r.max.y) + p.y = r.max.y-1; + + return p; +} + +/* + * resize is perhaps a misnomer. + * this really just grows the window to be at least dx across + * and dy high. if the window hits the bottom or right edge, + * it is backed up until it hits the top or left edge. + */ +void +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 = 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); + r.max.y = max(r.min.y+dy, r.max.y); + if(r.max.x > sr.max.x){ + if(Dx(r) > Dx(sr)){ + r.min.x = 0; + r.max.x = sr.max.x; + }else + r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0)); + } + if(r.max.y > sr.max.y){ + if(Dy(r) > Dy(sr)){ + r.min.y = 0; + r.max.y = sr.max.y; + }else + r = rectaddpt(r, Pt(0, sr.max.y-r.max.y)); + } + + /* + * Sometimes we can't actually grow the window big enough, + * and resizing it to the same shape makes it flash. + */ + 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); +} + +/* + * If we allocimage after a resize but before flushing the draw buffer, + * we won't have seen the reshape event, and we won't have called + * getwindow, and allocimage will fail. So we flushimage before every alloc. + */ +Image* +xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) +{ + flushimage(display, 0); + 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; +} + +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)); +} + +void +zerox(void) +{ + int pfd[2]; + + 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", 0); + wexits("cannot exec in zerox: %r\n"); + default: + close(pfd[1]); + writeimage(pfd[0], im, 0); + close(pfd[0]); + break; + } +} |