17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * the actual viewer that handles screen stuff
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include <u.h>
67dd7cddfSDavid du Colombier #include <libc.h>
77dd7cddfSDavid du Colombier #include <draw.h>
87dd7cddfSDavid du Colombier #include <cursor.h>
97dd7cddfSDavid du Colombier #include <event.h>
107dd7cddfSDavid du Colombier #include <bio.h>
117dd7cddfSDavid du Colombier #include <plumb.h>
127dd7cddfSDavid du Colombier #include <ctype.h>
137dd7cddfSDavid du Colombier #include <keyboard.h>
147dd7cddfSDavid du Colombier #include "page.h"
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier Document *doc;
177dd7cddfSDavid du Colombier Image *im;
18493edcedSDavid du Colombier Image *tofree;
197dd7cddfSDavid du Colombier int page;
20a7529a1dSDavid du Colombier int angle = 0;
2159cc4ca5SDavid du Colombier int showbottom = 0; /* on the next showpage, move the image so the bottom is visible. */
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier Rectangle ulrange; /* the upper left corner of the image must be in this rectangle */
247dd7cddfSDavid du Colombier Point ul; /* the upper left corner of the image is at this point on the screen */
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier Point pclip(Point, Rectangle);
277dd7cddfSDavid du Colombier Rectangle mkrange(Rectangle screenr, Rectangle imr);
287dd7cddfSDavid du Colombier void redraw(Image*);
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier Cursor reading={
317dd7cddfSDavid du Colombier {-1, -1},
327dd7cddfSDavid du Colombier {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00,
337dd7cddfSDavid du Colombier 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0,
347dd7cddfSDavid du Colombier 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0,
357dd7cddfSDavid du Colombier 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },
367dd7cddfSDavid du Colombier {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00,
377dd7cddfSDavid du Colombier 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0,
387dd7cddfSDavid du Colombier 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40,
397dd7cddfSDavid du Colombier 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }
407dd7cddfSDavid du Colombier };
417dd7cddfSDavid du Colombier
42223a736eSDavid du Colombier Cursor query = {
43223a736eSDavid du Colombier {-7,-7},
44223a736eSDavid du Colombier {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe,
45223a736eSDavid du Colombier 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8,
46223a736eSDavid du Colombier 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0,
47223a736eSDavid du Colombier 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, },
48223a736eSDavid du Colombier {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c,
49223a736eSDavid du Colombier 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0,
50223a736eSDavid du Colombier 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80,
51223a736eSDavid du Colombier 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
52223a736eSDavid du Colombier };
53223a736eSDavid du Colombier
547dd7cddfSDavid du Colombier enum {
557dd7cddfSDavid du Colombier Left = 1,
567dd7cddfSDavid du Colombier Middle = 2,
577dd7cddfSDavid du Colombier Right = 4,
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier RMenu = 3,
607dd7cddfSDavid du Colombier };
617dd7cddfSDavid du Colombier
62493edcedSDavid du Colombier static void
delayfreeimage(Image * m)63493edcedSDavid du Colombier delayfreeimage(Image *m)
64493edcedSDavid du Colombier {
65493edcedSDavid du Colombier if(m == tofree)
66493edcedSDavid du Colombier return;
67493edcedSDavid du Colombier if(tofree)
68493edcedSDavid du Colombier freeimage(tofree);
69493edcedSDavid du Colombier tofree = m;
70493edcedSDavid du Colombier }
71493edcedSDavid du Colombier
729a747e4fSDavid du Colombier void
unhide(void)739a747e4fSDavid du Colombier unhide(void)
749a747e4fSDavid du Colombier {
759a747e4fSDavid du Colombier static int wctl = -1;
769a747e4fSDavid du Colombier
779a747e4fSDavid du Colombier if(wctl < 0)
789a747e4fSDavid du Colombier wctl = open("/dev/wctl", OWRITE);
799a747e4fSDavid du Colombier if(wctl < 0)
809a747e4fSDavid du Colombier return;
819a747e4fSDavid du Colombier
829a747e4fSDavid du Colombier write(wctl, "unhide", 6);
839a747e4fSDavid du Colombier }
849a747e4fSDavid du Colombier
857dd7cddfSDavid du Colombier int
max(int a,int b)867dd7cddfSDavid du Colombier max(int a, int b)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier return a > b ? a : b;
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier int
min(int a,int b)927dd7cddfSDavid du Colombier min(int a, int b)
937dd7cddfSDavid du Colombier {
947dd7cddfSDavid du Colombier return a < b ? a : b;
957dd7cddfSDavid du Colombier }
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier char*
menugen(int n)997dd7cddfSDavid du Colombier menugen(int n)
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier static char menustr[32];
1027dd7cddfSDavid du Colombier char *p;
1037dd7cddfSDavid du Colombier int len;
1047dd7cddfSDavid du Colombier
1057dd7cddfSDavid du Colombier if(n == doc->npage)
1067dd7cddfSDavid du Colombier return "exit";
1077dd7cddfSDavid du Colombier if(n > doc->npage)
1087dd7cddfSDavid du Colombier return nil;
1097dd7cddfSDavid du Colombier
1107dd7cddfSDavid du Colombier if(reverse)
1117dd7cddfSDavid du Colombier n = doc->npage-1-n;
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier p = doc->pagename(doc, n);
1147dd7cddfSDavid du Colombier len = (sizeof menustr)-2;
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier if(strlen(p) > len && strrchr(p, '/'))
1177dd7cddfSDavid du Colombier p = strrchr(p, '/')+1;
1187dd7cddfSDavid du Colombier if(strlen(p) > len)
1197dd7cddfSDavid du Colombier p = p+strlen(p)-len;
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier strcpy(menustr+1, p);
1227dd7cddfSDavid du Colombier if(page == n)
1237dd7cddfSDavid du Colombier menustr[0] = '>';
1247dd7cddfSDavid du Colombier else
1257dd7cddfSDavid du Colombier menustr[0] = ' ';
1267dd7cddfSDavid du Colombier return menustr;
1277dd7cddfSDavid du Colombier }
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier void
showpage(int page,Menu * m)1307dd7cddfSDavid du Colombier showpage(int page, Menu *m)
1317dd7cddfSDavid du Colombier {
1327dd7cddfSDavid du Colombier if(doc->fwdonly)
1337dd7cddfSDavid du Colombier m->lasthit = 0; /* this page */
1347dd7cddfSDavid du Colombier else
1357dd7cddfSDavid du Colombier m->lasthit = reverse ? doc->npage-1-page : page;
1367dd7cddfSDavid du Colombier
1377dd7cddfSDavid du Colombier esetcursor(&reading);
138493edcedSDavid du Colombier delayfreeimage(nil);
139493edcedSDavid du Colombier im = cachedpage(doc, angle, page);
140493edcedSDavid du Colombier if(im == nil)
1417dd7cddfSDavid du Colombier wexits(0);
142493edcedSDavid du Colombier if(resizing)
1437dd7cddfSDavid du Colombier resize(Dx(im->r), Dy(im->r));
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier esetcursor(nil);
14659cc4ca5SDavid du Colombier if(showbottom){
14759cc4ca5SDavid du Colombier ul.y = screen->r.max.y - Dy(im->r);
14859cc4ca5SDavid du Colombier showbottom = 0;
14959cc4ca5SDavid du Colombier }
1507dd7cddfSDavid du Colombier
1517dd7cddfSDavid du Colombier redraw(screen);
1527dd7cddfSDavid du Colombier flushimage(display, 1);
1537dd7cddfSDavid du Colombier }
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier char*
writebitmap(void)1567dd7cddfSDavid du Colombier writebitmap(void)
1577dd7cddfSDavid du Colombier {
1587dd7cddfSDavid du Colombier char basename[64];
1597dd7cddfSDavid du Colombier char name[64+30];
1607dd7cddfSDavid du Colombier static char result[200];
1617dd7cddfSDavid du Colombier char *p, *q;
1627dd7cddfSDavid du Colombier int fd;
1637dd7cddfSDavid du Colombier
1647dd7cddfSDavid du Colombier if(im == nil)
1657dd7cddfSDavid du Colombier return "no image";
1667dd7cddfSDavid du Colombier
1677dd7cddfSDavid du Colombier memset(basename, 0, sizeof basename);
1687dd7cddfSDavid du Colombier if(doc->docname)
1697dd7cddfSDavid du Colombier strncpy(basename, doc->docname, sizeof(basename)-1);
1707dd7cddfSDavid du Colombier else if((p = menugen(page)) && p[0] != '\0')
1717dd7cddfSDavid du Colombier strncpy(basename, p+1, sizeof(basename)-1);
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier if(basename[0]) {
1747dd7cddfSDavid du Colombier if(q = strrchr(basename, '/'))
1757dd7cddfSDavid du Colombier q++;
1767dd7cddfSDavid du Colombier else
1777dd7cddfSDavid du Colombier q = basename;
1787dd7cddfSDavid du Colombier if(p = strchr(q, '.'))
1797dd7cddfSDavid du Colombier *p = 0;
1807dd7cddfSDavid du Colombier
1817dd7cddfSDavid du Colombier memset(name, 0, sizeof name);
1827dd7cddfSDavid du Colombier snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1);
1837dd7cddfSDavid du Colombier if(access(name, 0) >= 0) {
1847dd7cddfSDavid du Colombier strcat(name, "XXXX");
1857dd7cddfSDavid du Colombier mktemp(name);
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier if(access(name, 0) >= 0)
1887dd7cddfSDavid du Colombier return "couldn't think of a name for bitmap";
1897dd7cddfSDavid du Colombier } else {
1907dd7cddfSDavid du Colombier strcpy(name, "bitXXXX");
1917dd7cddfSDavid du Colombier mktemp(name);
1927dd7cddfSDavid du Colombier if(access(name, 0) >= 0)
1937dd7cddfSDavid du Colombier return "couldn't think of a name for bitmap";
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier if((fd = create(name, OWRITE, 0666)) < 0) {
1977dd7cddfSDavid du Colombier snprint(result, sizeof result, "cannot create %s: %r", name);
1987dd7cddfSDavid du Colombier return result;
1997dd7cddfSDavid du Colombier }
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier if(writeimage(fd, im, 0) < 0) {
2027dd7cddfSDavid du Colombier snprint(result, sizeof result, "cannot writeimage: %r");
2037dd7cddfSDavid du Colombier close(fd);
2047dd7cddfSDavid du Colombier return result;
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier close(fd);
2077dd7cddfSDavid du Colombier
2087dd7cddfSDavid du Colombier snprint(result, sizeof result, "wrote %s", name);
2097dd7cddfSDavid du Colombier return result;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier static void translate(Point);
2137dd7cddfSDavid du Colombier
2147dd7cddfSDavid du Colombier static int
showdata(Plumbmsg * msg)2157dd7cddfSDavid du Colombier showdata(Plumbmsg *msg)
2167dd7cddfSDavid du Colombier {
2177dd7cddfSDavid du Colombier char *s;
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier s = plumblookup(msg->attr, "action");
2207dd7cddfSDavid du Colombier return s && strcmp(s, "showdata")==0;
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier
2230ceffd3cSDavid du Colombier static int
plumbquit(Plumbmsg * msg)2240ceffd3cSDavid du Colombier plumbquit(Plumbmsg *msg)
2250ceffd3cSDavid du Colombier {
2260ceffd3cSDavid du Colombier char *s;
2270ceffd3cSDavid du Colombier
2280ceffd3cSDavid du Colombier s = plumblookup(msg->attr, "action");
2290ceffd3cSDavid du Colombier return s && strcmp(s, "quit")==0;
2300ceffd3cSDavid du Colombier }
2310ceffd3cSDavid du Colombier
23208fd2d13SDavid du Colombier /* correspond to entries in miditems[] below,
23308fd2d13SDavid du Colombier * changing one means you need to change
23408fd2d13SDavid du Colombier */
23508fd2d13SDavid du Colombier enum{
23608fd2d13SDavid du Colombier Restore = 0,
23708fd2d13SDavid du Colombier Zin,
23808fd2d13SDavid du Colombier Fit,
23908fd2d13SDavid du Colombier Rot,
24008fd2d13SDavid du Colombier Upside,
24108fd2d13SDavid du Colombier Empty1,
24208fd2d13SDavid du Colombier Next,
24308fd2d13SDavid du Colombier Prev,
2447def40e1SDavid du Colombier Zerox,
24508fd2d13SDavid du Colombier Empty2,
24608fd2d13SDavid du Colombier Reverse,
24708fd2d13SDavid du Colombier Del,
24808fd2d13SDavid du Colombier Write,
24908fd2d13SDavid du Colombier Empty3,
25008fd2d13SDavid du Colombier Exit,
25108fd2d13SDavid du Colombier };
25208fd2d13SDavid du Colombier
2537dd7cddfSDavid du Colombier void
viewer(Document * dd)2547dd7cddfSDavid du Colombier viewer(Document *dd)
2557dd7cddfSDavid du Colombier {
2567dd7cddfSDavid du Colombier int i, fd, n, oldpage;
2577dd7cddfSDavid du Colombier int nxt;
25808fd2d13SDavid du Colombier Menu menu, midmenu;
2597dd7cddfSDavid du Colombier Mouse m;
2607dd7cddfSDavid du Colombier Event e;
2617dd7cddfSDavid du Colombier Point dxy, oxy, xy0;
2627dd7cddfSDavid du Colombier Rectangle r;
26308fd2d13SDavid du Colombier Image *tmp;
26408fd2d13SDavid du Colombier static char *fwditems[] = { "this page", "next page", "exit", 0 };
26508fd2d13SDavid du Colombier static char *miditems[] = {
26608fd2d13SDavid du Colombier "orig size",
26708fd2d13SDavid du Colombier "zoom in",
26808fd2d13SDavid du Colombier "fit window",
26908fd2d13SDavid du Colombier "rotate 90",
27008fd2d13SDavid du Colombier "upside down",
27108fd2d13SDavid du Colombier "",
27208fd2d13SDavid du Colombier "next",
27308fd2d13SDavid du Colombier "prev",
2747def40e1SDavid du Colombier "zerox",
27508fd2d13SDavid du Colombier "",
27608fd2d13SDavid du Colombier "reverse",
27708fd2d13SDavid du Colombier "discard",
27808fd2d13SDavid du Colombier "write",
27908fd2d13SDavid du Colombier "",
28008fd2d13SDavid du Colombier "quit",
28108fd2d13SDavid du Colombier 0
28208fd2d13SDavid du Colombier };
2837dd7cddfSDavid du Colombier char *s;
2847dd7cddfSDavid du Colombier enum { Eplumb = 4 };
2857dd7cddfSDavid du Colombier Plumbmsg *pm;
2867dd7cddfSDavid du Colombier
2877dd7cddfSDavid du Colombier doc = dd; /* save global for menuhit */
2887dd7cddfSDavid du Colombier ul = screen->r.min;
2897dd7cddfSDavid du Colombier einit(Emouse|Ekeyboard);
2907dd7cddfSDavid du Colombier if(doc->addpage != nil)
2917dd7cddfSDavid du Colombier eplumb(Eplumb, "image");
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier esetcursor(&reading);
2947dd7cddfSDavid du Colombier r.min = ZP;
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier /*
2977dd7cddfSDavid du Colombier * im is a global pointer to the current image.
2987dd7cddfSDavid du Colombier * eventually, i think we will have a layer between
2997dd7cddfSDavid du Colombier * the display routines and the ps/pdf/whatever routines
3007dd7cddfSDavid du Colombier * to perhaps cache and handle images of different
3017dd7cddfSDavid du Colombier * sizes, etc.
3027dd7cddfSDavid du Colombier */
3037dd7cddfSDavid du Colombier im = 0;
3047dd7cddfSDavid du Colombier page = reverse ? doc->npage-1 : 0;
3057dd7cddfSDavid du Colombier
3067dd7cddfSDavid du Colombier if(doc->fwdonly) {
3077dd7cddfSDavid du Colombier menu.item = fwditems;
3087dd7cddfSDavid du Colombier menu.gen = 0;
3097dd7cddfSDavid du Colombier menu.lasthit = 0;
3107dd7cddfSDavid du Colombier } else {
3117dd7cddfSDavid du Colombier menu.item = 0;
3127dd7cddfSDavid du Colombier menu.gen = menugen;
3137dd7cddfSDavid du Colombier menu.lasthit = 0;
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier
31608fd2d13SDavid du Colombier midmenu.item = miditems;
31708fd2d13SDavid du Colombier midmenu.gen = 0;
31808fd2d13SDavid du Colombier midmenu.lasthit = Next;
31908fd2d13SDavid du Colombier
320*ad6ca847SDavid du Colombier if(doc->docname != nil)
321*ad6ca847SDavid du Colombier setlabel(doc->docname);
3227dd7cddfSDavid du Colombier showpage(page, &menu);
3237dd7cddfSDavid du Colombier esetcursor(nil);
3247dd7cddfSDavid du Colombier
3257dd7cddfSDavid du Colombier nxt = 0;
3267dd7cddfSDavid du Colombier for(;;) {
3277dd7cddfSDavid du Colombier /*
3287dd7cddfSDavid du Colombier * throughout, if doc->fwdonly is set, we restrict the functionality
3297dd7cddfSDavid du Colombier * a fair amount. we don't care about doc->npage anymore, and
3307dd7cddfSDavid du Colombier * all that can be done is select the next page.
3317dd7cddfSDavid du Colombier */
332493edcedSDavid du Colombier unlockdisplay(display);
333493edcedSDavid du Colombier i = eread(Emouse|Ekeyboard|Eplumb, &e);
334493edcedSDavid du Colombier lockdisplay(display);
335493edcedSDavid du Colombier switch(i){
3367dd7cddfSDavid du Colombier case Ekeyboard:
3377dd7cddfSDavid du Colombier if(e.kbdc <= 0xFF && isdigit(e.kbdc)) {
3387dd7cddfSDavid du Colombier nxt = nxt*10+e.kbdc-'0';
3397dd7cddfSDavid du Colombier break;
3407dd7cddfSDavid du Colombier } else if(e.kbdc != '\n')
3417dd7cddfSDavid du Colombier nxt = 0;
3427dd7cddfSDavid du Colombier switch(e.kbdc) {
3437dd7cddfSDavid du Colombier case 'r': /* reverse page order */
3447dd7cddfSDavid du Colombier if(doc->fwdonly)
3457dd7cddfSDavid du Colombier break;
3467dd7cddfSDavid du Colombier reverse = !reverse;
3477dd7cddfSDavid du Colombier menu.lasthit = doc->npage-1-menu.lasthit;
3487dd7cddfSDavid du Colombier
3497dd7cddfSDavid du Colombier /*
3507dd7cddfSDavid du Colombier * the theory is that if we are reversing the
3517dd7cddfSDavid du Colombier * document order and are on the first or last
3527dd7cddfSDavid du Colombier * page then we're just starting and really want
3537dd7cddfSDavid du Colombier * to view the other end. maybe the if
3547dd7cddfSDavid du Colombier * should be dropped and this should happen always.
3557dd7cddfSDavid du Colombier */
3567dd7cddfSDavid du Colombier if(page == 0 || page == doc->npage-1) {
3577dd7cddfSDavid du Colombier page = doc->npage-1-page;
3587dd7cddfSDavid du Colombier showpage(page, &menu);
3597dd7cddfSDavid du Colombier }
3607dd7cddfSDavid du Colombier break;
3617dd7cddfSDavid du Colombier case 'w': /* write bitmap of current screen */
3627dd7cddfSDavid du Colombier esetcursor(&reading);
3637dd7cddfSDavid du Colombier s = writebitmap();
3647dd7cddfSDavid du Colombier if(s)
3657dd7cddfSDavid du Colombier string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
3667dd7cddfSDavid du Colombier display->defaultfont, s);
3677dd7cddfSDavid du Colombier esetcursor(nil);
3687dd7cddfSDavid du Colombier flushimage(display, 1);
3697dd7cddfSDavid du Colombier break;
3707dd7cddfSDavid du Colombier case 'd': /* remove image from working set */
3717dd7cddfSDavid du Colombier if(doc->rmpage && page < doc->npage) {
3727dd7cddfSDavid du Colombier if(doc->rmpage(doc, page) >= 0) {
3737dd7cddfSDavid du Colombier if(doc->npage < 0)
3747dd7cddfSDavid du Colombier wexits(0);
3757dd7cddfSDavid du Colombier if(page >= doc->npage)
3767dd7cddfSDavid du Colombier page = doc->npage-1;
3777dd7cddfSDavid du Colombier showpage(page, &menu);
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier }
3807dd7cddfSDavid du Colombier break;
3817dd7cddfSDavid du Colombier case 'q':
3827dd7cddfSDavid du Colombier case 0x04: /* ctrl-d */
3837dd7cddfSDavid du Colombier wexits(0);
3847dd7cddfSDavid du Colombier case 'u':
3857dd7cddfSDavid du Colombier if(im==nil)
3867dd7cddfSDavid du Colombier break;
387a7529a1dSDavid du Colombier angle = (angle+180) % 360;
388493edcedSDavid du Colombier showpage(page, &menu);
3897dd7cddfSDavid du Colombier break;
3907dd7cddfSDavid du Colombier case '-':
3917dd7cddfSDavid du Colombier case '\b':
392223a736eSDavid du Colombier case Kleft:
3937dd7cddfSDavid du Colombier if(page > 0 && !doc->fwdonly) {
3947dd7cddfSDavid du Colombier --page;
3957dd7cddfSDavid du Colombier showpage(page, &menu);
3967dd7cddfSDavid du Colombier }
3977dd7cddfSDavid du Colombier break;
3987dd7cddfSDavid du Colombier case '\n':
3997dd7cddfSDavid du Colombier if(nxt) {
4007dd7cddfSDavid du Colombier nxt--;
4017dd7cddfSDavid du Colombier if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly)
4027dd7cddfSDavid du Colombier showpage(page=nxt, &menu);
4037dd7cddfSDavid du Colombier nxt = 0;
4047dd7cddfSDavid du Colombier break;
4057dd7cddfSDavid du Colombier }
40659cc4ca5SDavid du Colombier goto Gotonext;
407223a736eSDavid du Colombier case Kright:
408223a736eSDavid du Colombier case ' ':
40959cc4ca5SDavid du Colombier Gotonext:
4107dd7cddfSDavid du Colombier if(doc->npage && ++page >= doc->npage && !doc->fwdonly)
4117dd7cddfSDavid du Colombier wexits(0);
4127dd7cddfSDavid du Colombier showpage(page, &menu);
4137dd7cddfSDavid du Colombier break;
41459cc4ca5SDavid du Colombier
41559cc4ca5SDavid du Colombier /*
41659cc4ca5SDavid du Colombier * The upper y coordinate of the image is at ul.y in screen->r.
41759cc4ca5SDavid du Colombier * Panning up means moving the upper left corner down. If the
41859cc4ca5SDavid du Colombier * upper left corner is currently visible, we need to go back a page.
41959cc4ca5SDavid du Colombier */
42059cc4ca5SDavid du Colombier case Kup:
42159cc4ca5SDavid du Colombier if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){
42259cc4ca5SDavid du Colombier if(page > 0 && !doc->fwdonly){
42359cc4ca5SDavid du Colombier --page;
42459cc4ca5SDavid du Colombier showbottom = 1;
42559cc4ca5SDavid du Colombier showpage(page, &menu);
42659cc4ca5SDavid du Colombier }
42759cc4ca5SDavid du Colombier } else {
42859cc4ca5SDavid du Colombier i = Dy(screen->r)/2;
42959cc4ca5SDavid du Colombier if(i > 10)
43059cc4ca5SDavid du Colombier i -= 10;
43159cc4ca5SDavid du Colombier if(i+ul.y > screen->r.min.y)
43259cc4ca5SDavid du Colombier i = screen->r.min.y - ul.y;
43359cc4ca5SDavid du Colombier translate(Pt(0, i));
43459cc4ca5SDavid du Colombier }
43559cc4ca5SDavid du Colombier break;
43659cc4ca5SDavid du Colombier
43759cc4ca5SDavid du Colombier /*
43859cc4ca5SDavid du Colombier * If the lower y coordinate is on the screen, we go to the next page.
43959cc4ca5SDavid du Colombier * The lower y coordinate is at ul.y + Dy(im->r).
44059cc4ca5SDavid du Colombier */
44159cc4ca5SDavid du Colombier case Kdown:
44259cc4ca5SDavid du Colombier i = ul.y + Dy(im->r);
44359cc4ca5SDavid du Colombier if(screen->r.min.y <= i && i <= screen->r.max.y){
44459cc4ca5SDavid du Colombier ul.y = screen->r.min.y;
44559cc4ca5SDavid du Colombier goto Gotonext;
44659cc4ca5SDavid du Colombier } else {
44759cc4ca5SDavid du Colombier i = -Dy(screen->r)/2;
44859cc4ca5SDavid du Colombier if(i < -10)
44959cc4ca5SDavid du Colombier i += 10;
45059cc4ca5SDavid du Colombier if(i+ul.y+Dy(im->r) <= screen->r.max.y)
45159cc4ca5SDavid du Colombier i = screen->r.max.y - Dy(im->r) - ul.y - 1;
45259cc4ca5SDavid du Colombier translate(Pt(0, i));
45359cc4ca5SDavid du Colombier }
45459cc4ca5SDavid du Colombier break;
455223a736eSDavid du Colombier default:
456223a736eSDavid du Colombier esetcursor(&query);
457223a736eSDavid du Colombier sleep(1000);
458223a736eSDavid du Colombier esetcursor(nil);
459223a736eSDavid du Colombier break;
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier break;
4627dd7cddfSDavid du Colombier
4637dd7cddfSDavid du Colombier case Emouse:
4647dd7cddfSDavid du Colombier m = e.mouse;
4657dd7cddfSDavid du Colombier switch(m.buttons){
4667dd7cddfSDavid du Colombier case Left:
4677dd7cddfSDavid du Colombier oxy = m.xy;
4687dd7cddfSDavid du Colombier xy0 = oxy;
4697dd7cddfSDavid du Colombier do {
4707dd7cddfSDavid du Colombier dxy = subpt(m.xy, oxy);
4717dd7cddfSDavid du Colombier oxy = m.xy;
4727dd7cddfSDavid du Colombier translate(dxy);
473493edcedSDavid du Colombier unlockdisplay(display);
4747dd7cddfSDavid du Colombier m = emouse();
475493edcedSDavid du Colombier lockdisplay(display);
4767dd7cddfSDavid du Colombier } while(m.buttons == Left);
4777dd7cddfSDavid du Colombier if(m.buttons) {
4787dd7cddfSDavid du Colombier dxy = subpt(xy0, oxy);
4797dd7cddfSDavid du Colombier translate(dxy);
4807dd7cddfSDavid du Colombier }
4817dd7cddfSDavid du Colombier break;
4827dd7cddfSDavid du Colombier
4837dd7cddfSDavid du Colombier case Middle:
4847dd7cddfSDavid du Colombier if(doc->npage == 0)
4857dd7cddfSDavid du Colombier break;
4867dd7cddfSDavid du Colombier
487493edcedSDavid du Colombier unlockdisplay(display);
48808fd2d13SDavid du Colombier n = emenuhit(Middle, &m, &midmenu);
489493edcedSDavid du Colombier lockdisplay(display);
49008fd2d13SDavid du Colombier if(n == -1)
49108fd2d13SDavid du Colombier break;
49208fd2d13SDavid du Colombier switch(n){
49308fd2d13SDavid du Colombier case Next: /* next */
4947dd7cddfSDavid du Colombier if(reverse)
4957dd7cddfSDavid du Colombier page--;
4967dd7cddfSDavid du Colombier else
4977dd7cddfSDavid du Colombier page++;
49808fd2d13SDavid du Colombier if(page < 0) {
49908fd2d13SDavid du Colombier if(reverse) return;
50008fd2d13SDavid du Colombier else page = 0;
50108fd2d13SDavid du Colombier }
5027dd7cddfSDavid du Colombier
50308fd2d13SDavid du Colombier if((page >= doc->npage) && !doc->fwdonly)
5047dd7cddfSDavid du Colombier return;
5057dd7cddfSDavid du Colombier
5067dd7cddfSDavid du Colombier showpage(page, &menu);
5077dd7cddfSDavid du Colombier nxt = 0;
5087dd7cddfSDavid du Colombier break;
50908fd2d13SDavid du Colombier case Prev: /* prev */
51008fd2d13SDavid du Colombier if(reverse)
51108fd2d13SDavid du Colombier page++;
51208fd2d13SDavid du Colombier else
51308fd2d13SDavid du Colombier page--;
51408fd2d13SDavid du Colombier if(page < 0) {
51508fd2d13SDavid du Colombier if(reverse) return;
51608fd2d13SDavid du Colombier else page = 0;
51708fd2d13SDavid du Colombier }
51808fd2d13SDavid du Colombier
51908fd2d13SDavid du Colombier if((page >= doc->npage) && !doc->fwdonly && !reverse)
52008fd2d13SDavid du Colombier return;
52108fd2d13SDavid du Colombier
52208fd2d13SDavid du Colombier showpage(page, &menu);
52308fd2d13SDavid du Colombier nxt = 0;
52408fd2d13SDavid du Colombier break;
5257def40e1SDavid du Colombier case Zerox: /* prev */
5267def40e1SDavid du Colombier zerox();
52708fd2d13SDavid du Colombier break;
52808fd2d13SDavid du Colombier case Zin: /* zoom in */
52908fd2d13SDavid du Colombier {
53008fd2d13SDavid du Colombier double delta;
53108fd2d13SDavid du Colombier Rectangle r;
53208fd2d13SDavid du Colombier
53308fd2d13SDavid du Colombier r = egetrect(Middle, &m);
53408fd2d13SDavid du Colombier if((rectclip(&r, rectaddpt(im->r, ul)) == 0) ||
53508fd2d13SDavid du Colombier Dx(r) == 0 || Dy(r) == 0)
53608fd2d13SDavid du Colombier break;
53708fd2d13SDavid du Colombier /* use the smaller side to expand */
53808fd2d13SDavid du Colombier if(Dx(r) < Dy(r))
53908fd2d13SDavid du Colombier delta = (double)Dx(im->r)/(double)Dx(r);
54008fd2d13SDavid du Colombier else
54108fd2d13SDavid du Colombier delta = (double)Dy(im->r)/(double)Dy(r);
54208fd2d13SDavid du Colombier
54308fd2d13SDavid du Colombier esetcursor(&reading);
5445316891fSDavid du Colombier tmp = xallocimage(display,
54508fd2d13SDavid du Colombier Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)),
54608fd2d13SDavid du Colombier im->chan, 0, DBlack);
5475316891fSDavid du Colombier if(tmp == nil) {
5485316891fSDavid du Colombier fprint(2, "out of memory during zoom: %r\n");
5495316891fSDavid du Colombier wexits("memory");
5505316891fSDavid du Colombier }
55108fd2d13SDavid du Colombier resample(im, tmp);
55208fd2d13SDavid du Colombier im = tmp;
553493edcedSDavid du Colombier delayfreeimage(tmp);
55408fd2d13SDavid du Colombier esetcursor(nil);
55508fd2d13SDavid du Colombier ul = screen->r.min;
55608fd2d13SDavid du Colombier redraw(screen);
55708fd2d13SDavid du Colombier flushimage(display, 1);
55808fd2d13SDavid du Colombier break;
55908fd2d13SDavid du Colombier }
56008fd2d13SDavid du Colombier case Fit: /* fit */
56108fd2d13SDavid du Colombier {
56208fd2d13SDavid du Colombier double delta;
56308fd2d13SDavid du Colombier Rectangle r;
56408fd2d13SDavid du Colombier
56508fd2d13SDavid du Colombier delta = (double)Dx(screen->r)/(double)Dx(im->r);
56608fd2d13SDavid du Colombier if((double)Dy(im->r)*delta > Dy(screen->r))
56708fd2d13SDavid du Colombier delta = (double)Dy(screen->r)/(double)Dy(im->r);
56808fd2d13SDavid du Colombier
56908fd2d13SDavid du Colombier r = Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta));
57008fd2d13SDavid du Colombier esetcursor(&reading);
5715316891fSDavid du Colombier tmp = xallocimage(display, r, im->chan, 0, DBlack);
5725316891fSDavid du Colombier if(tmp == nil) {
5735316891fSDavid du Colombier fprint(2, "out of memory during fit: %r\n");
5745316891fSDavid du Colombier wexits("memory");
5755316891fSDavid du Colombier }
57608fd2d13SDavid du Colombier resample(im, tmp);
57708fd2d13SDavid du Colombier im = tmp;
578493edcedSDavid du Colombier delayfreeimage(tmp);
57908fd2d13SDavid du Colombier esetcursor(nil);
58008fd2d13SDavid du Colombier ul = screen->r.min;
58108fd2d13SDavid du Colombier redraw(screen);
58208fd2d13SDavid du Colombier flushimage(display, 1);
58308fd2d13SDavid du Colombier break;
58408fd2d13SDavid du Colombier }
58508fd2d13SDavid du Colombier case Rot: /* rotate 90 */
586a7529a1dSDavid du Colombier angle = (angle+90) % 360;
587493edcedSDavid du Colombier showpage(page, &menu);
58808fd2d13SDavid du Colombier break;
58908fd2d13SDavid du Colombier case Upside: /* upside-down */
590a7529a1dSDavid du Colombier angle = (angle+180) % 360;
591493edcedSDavid du Colombier showpage(page, &menu);
59208fd2d13SDavid du Colombier break;
59308fd2d13SDavid du Colombier case Restore: /* restore */
59408fd2d13SDavid du Colombier showpage(page, &menu);
59508fd2d13SDavid du Colombier break;
59608fd2d13SDavid du Colombier case Reverse: /* reverse */
59708fd2d13SDavid du Colombier if(doc->fwdonly)
59808fd2d13SDavid du Colombier break;
59908fd2d13SDavid du Colombier reverse = !reverse;
60008fd2d13SDavid du Colombier menu.lasthit = doc->npage-1-menu.lasthit;
60108fd2d13SDavid du Colombier
60208fd2d13SDavid du Colombier if(page == 0 || page == doc->npage-1) {
60308fd2d13SDavid du Colombier page = doc->npage-1-page;
60408fd2d13SDavid du Colombier showpage(page, &menu);
60508fd2d13SDavid du Colombier }
60608fd2d13SDavid du Colombier break;
60708fd2d13SDavid du Colombier case Write: /* write */
60808fd2d13SDavid du Colombier esetcursor(&reading);
60908fd2d13SDavid du Colombier s = writebitmap();
61008fd2d13SDavid du Colombier if(s)
61108fd2d13SDavid du Colombier string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,
61208fd2d13SDavid du Colombier display->defaultfont, s);
61308fd2d13SDavid du Colombier esetcursor(nil);
61408fd2d13SDavid du Colombier flushimage(display, 1);
61508fd2d13SDavid du Colombier break;
61608fd2d13SDavid du Colombier case Del: /* delete */
61708fd2d13SDavid du Colombier if(doc->rmpage && page < doc->npage) {
61808fd2d13SDavid du Colombier if(doc->rmpage(doc, page) >= 0) {
61908fd2d13SDavid du Colombier if(doc->npage < 0)
62008fd2d13SDavid du Colombier wexits(0);
62108fd2d13SDavid du Colombier if(page >= doc->npage)
62208fd2d13SDavid du Colombier page = doc->npage-1;
62308fd2d13SDavid du Colombier showpage(page, &menu);
62408fd2d13SDavid du Colombier }
62508fd2d13SDavid du Colombier }
62608fd2d13SDavid du Colombier break;
62708fd2d13SDavid du Colombier case Exit: /* exit */
62808fd2d13SDavid du Colombier return;
62908fd2d13SDavid du Colombier case Empty1:
63008fd2d13SDavid du Colombier case Empty2:
63108fd2d13SDavid du Colombier case Empty3:
63208fd2d13SDavid du Colombier break;
63308fd2d13SDavid du Colombier
63408fd2d13SDavid du Colombier };
63508fd2d13SDavid du Colombier
63608fd2d13SDavid du Colombier
6377dd7cddfSDavid du Colombier
6387dd7cddfSDavid du Colombier case Right:
6397dd7cddfSDavid du Colombier if(doc->npage == 0)
6407dd7cddfSDavid du Colombier break;
6417dd7cddfSDavid du Colombier
6427dd7cddfSDavid du Colombier oldpage = page;
643493edcedSDavid du Colombier unlockdisplay(display);
6447dd7cddfSDavid du Colombier n = emenuhit(RMenu, &m, &menu);
645493edcedSDavid du Colombier lockdisplay(display);
6467dd7cddfSDavid du Colombier if(n == -1)
6477dd7cddfSDavid du Colombier break;
6487dd7cddfSDavid du Colombier
6497dd7cddfSDavid du Colombier if(doc->fwdonly) {
6507dd7cddfSDavid du Colombier switch(n){
6517dd7cddfSDavid du Colombier case 0: /* this page */
6527dd7cddfSDavid du Colombier break;
6537dd7cddfSDavid du Colombier case 1: /* next page */
6547dd7cddfSDavid du Colombier showpage(++page, &menu);
6557dd7cddfSDavid du Colombier break;
6567dd7cddfSDavid du Colombier case 2: /* exit */
6577dd7cddfSDavid du Colombier return;
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier break;
6607dd7cddfSDavid du Colombier }
6617dd7cddfSDavid du Colombier
6627dd7cddfSDavid du Colombier if(n == doc->npage)
6637dd7cddfSDavid du Colombier return;
6647dd7cddfSDavid du Colombier else
6657dd7cddfSDavid du Colombier page = reverse ? doc->npage-1-n : n;
6667dd7cddfSDavid du Colombier
6677dd7cddfSDavid du Colombier if(oldpage != page)
6687dd7cddfSDavid du Colombier showpage(page, &menu);
6697dd7cddfSDavid du Colombier nxt = 0;
6707dd7cddfSDavid du Colombier break;
6717dd7cddfSDavid du Colombier }
6727dd7cddfSDavid du Colombier break;
6737dd7cddfSDavid du Colombier
6747dd7cddfSDavid du Colombier case Eplumb:
6757dd7cddfSDavid du Colombier pm = e.v;
6767dd7cddfSDavid du Colombier if(pm->ndata <= 0){
6777dd7cddfSDavid du Colombier plumbfree(pm);
6787dd7cddfSDavid du Colombier break;
6797dd7cddfSDavid du Colombier }
6800ceffd3cSDavid du Colombier if(plumbquit(pm))
6810ceffd3cSDavid du Colombier exits(nil);
6827dd7cddfSDavid du Colombier if(showdata(pm)) {
6837dd7cddfSDavid du Colombier s = estrdup("/tmp/pageplumbXXXXXXX");
6847dd7cddfSDavid du Colombier fd = opentemp(s);
6857dd7cddfSDavid du Colombier write(fd, pm->data, pm->ndata);
6867dd7cddfSDavid du Colombier /* lose fd reference on purpose; the file is open ORCLOSE */
6877dd7cddfSDavid du Colombier } else if(pm->data[0] == '/') {
6887dd7cddfSDavid du Colombier s = estrdup(pm->data);
6897dd7cddfSDavid du Colombier } else {
6907dd7cddfSDavid du Colombier s = emalloc(strlen(pm->wdir)+1+pm->ndata+1);
6917dd7cddfSDavid du Colombier sprint(s, "%s/%s", pm->wdir, pm->data);
6927dd7cddfSDavid du Colombier cleanname(s);
6937dd7cddfSDavid du Colombier }
6947dd7cddfSDavid du Colombier if((i = doc->addpage(doc, s)) >= 0) {
6957dd7cddfSDavid du Colombier page = i;
6969a747e4fSDavid du Colombier unhide();
6977dd7cddfSDavid du Colombier showpage(page, &menu);
6987dd7cddfSDavid du Colombier }
6997dd7cddfSDavid du Colombier free(s);
7007dd7cddfSDavid du Colombier plumbfree(pm);
7017dd7cddfSDavid du Colombier break;
7027dd7cddfSDavid du Colombier }
7037dd7cddfSDavid du Colombier }
7047dd7cddfSDavid du Colombier }
7057dd7cddfSDavid du Colombier
7067dd7cddfSDavid du Colombier Image *gray;
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier /*
7097dd7cddfSDavid du Colombier * A draw operation that touches only the area contained in bot but not in top.
7107dd7cddfSDavid du Colombier * mp and sp get aligned with bot.min.
7117dd7cddfSDavid du Colombier */
7127dd7cddfSDavid du Colombier static void
gendrawdiff(Image * dst,Rectangle bot,Rectangle top,Image * src,Point sp,Image * mask,Point mp,int op)7137dd7cddfSDavid du Colombier gendrawdiff(Image *dst, Rectangle bot, Rectangle top,
7146b6b9ac8SDavid du Colombier Image *src, Point sp, Image *mask, Point mp, int op)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier Rectangle r;
7177dd7cddfSDavid du Colombier Point origin;
7187dd7cddfSDavid du Colombier Point delta;
7197dd7cddfSDavid du Colombier
72008fd2d13SDavid du Colombier USED(op);
72108fd2d13SDavid du Colombier
7227dd7cddfSDavid du Colombier if(Dx(bot)*Dy(bot) == 0)
7237dd7cddfSDavid du Colombier return;
7247dd7cddfSDavid du Colombier
7257dd7cddfSDavid du Colombier /* no points in bot - top */
7267dd7cddfSDavid du Colombier if(rectinrect(bot, top))
7277dd7cddfSDavid du Colombier return;
7287dd7cddfSDavid du Colombier
7297dd7cddfSDavid du Colombier /* bot - top ≡ bot */
7307dd7cddfSDavid du Colombier if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){
7316b6b9ac8SDavid du Colombier gendrawop(dst, bot, src, sp, mask, mp, op);
7327dd7cddfSDavid du Colombier return;
7337dd7cddfSDavid du Colombier }
7347dd7cddfSDavid du Colombier
7357dd7cddfSDavid du Colombier origin = bot.min;
7367dd7cddfSDavid du Colombier /* split bot into rectangles that don't intersect top */
7377dd7cddfSDavid du Colombier /* left side */
7387dd7cddfSDavid du Colombier if(bot.min.x < top.min.x){
7397dd7cddfSDavid du Colombier r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y);
7407dd7cddfSDavid du Colombier delta = subpt(r.min, origin);
7416b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
7427dd7cddfSDavid du Colombier bot.min.x = top.min.x;
7437dd7cddfSDavid du Colombier }
7447dd7cddfSDavid du Colombier
7457dd7cddfSDavid du Colombier /* right side */
7467dd7cddfSDavid du Colombier if(bot.max.x > top.max.x){
7477dd7cddfSDavid du Colombier r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y);
7487dd7cddfSDavid du Colombier delta = subpt(r.min, origin);
7496b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
7507dd7cddfSDavid du Colombier bot.max.x = top.max.x;
7517dd7cddfSDavid du Colombier }
7527dd7cddfSDavid du Colombier
7537dd7cddfSDavid du Colombier /* top */
7547dd7cddfSDavid du Colombier if(bot.min.y < top.min.y){
7557dd7cddfSDavid du Colombier r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y);
7567dd7cddfSDavid du Colombier delta = subpt(r.min, origin);
7576b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
7587dd7cddfSDavid du Colombier bot.min.y = top.min.y;
7597dd7cddfSDavid du Colombier }
7607dd7cddfSDavid du Colombier
7617dd7cddfSDavid du Colombier /* bottom */
7627dd7cddfSDavid du Colombier if(bot.max.y > top.max.y){
7637dd7cddfSDavid du Colombier r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y);
7647dd7cddfSDavid du Colombier delta = subpt(r.min, origin);
7656b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op);
7667dd7cddfSDavid du Colombier bot.max.y = top.max.y;
7677dd7cddfSDavid du Colombier }
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier
7707dd7cddfSDavid du Colombier static void
drawdiff(Image * dst,Rectangle bot,Rectangle top,Image * src,Image * mask,Point p,int op)7716b6b9ac8SDavid du Colombier drawdiff(Image *dst, Rectangle bot, Rectangle top, Image *src, Image *mask, Point p, int op)
7727dd7cddfSDavid du Colombier {
7736b6b9ac8SDavid du Colombier gendrawdiff(dst, bot, top, src, p, mask, p, op);
7747dd7cddfSDavid du Colombier }
7757dd7cddfSDavid du Colombier
7767dd7cddfSDavid du Colombier /*
7777dd7cddfSDavid du Colombier * Translate the image in the window by delta.
7787dd7cddfSDavid du Colombier */
7797dd7cddfSDavid du Colombier static void
translate(Point delta)7807dd7cddfSDavid du Colombier translate(Point delta)
7817dd7cddfSDavid du Colombier {
7827dd7cddfSDavid du Colombier Point u;
7837dd7cddfSDavid du Colombier Rectangle r, or;
7847dd7cddfSDavid du Colombier
7857dd7cddfSDavid du Colombier if(im == nil)
7867dd7cddfSDavid du Colombier return;
7877dd7cddfSDavid du Colombier
7887dd7cddfSDavid du Colombier u = pclip(addpt(ul, delta), ulrange);
7897dd7cddfSDavid du Colombier delta = subpt(u, ul);
7907dd7cddfSDavid du Colombier if(delta.x == 0 && delta.y == 0)
7917dd7cddfSDavid du Colombier return;
7927dd7cddfSDavid du Colombier
7937dd7cddfSDavid du Colombier /*
7947dd7cddfSDavid du Colombier * The upper left corner of the image is currently at ul.
7957dd7cddfSDavid du Colombier * We want to move it to u.
7967dd7cddfSDavid du Colombier */
7977dd7cddfSDavid du Colombier or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul);
7987dd7cddfSDavid du Colombier r = rectaddpt(or, delta);
7997dd7cddfSDavid du Colombier
8006b6b9ac8SDavid du Colombier drawop(screen, r, screen, nil, ul, S);
8017dd7cddfSDavid du Colombier ul = u;
8027dd7cddfSDavid du Colombier
8037dd7cddfSDavid du Colombier /* fill in gray where image used to be but isn't. */
8046b6b9ac8SDavid du Colombier drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP, S);
8057dd7cddfSDavid du Colombier
8067dd7cddfSDavid du Colombier /* fill in black border */
8076b6b9ac8SDavid du Colombier drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S);
8087dd7cddfSDavid du Colombier
8097dd7cddfSDavid du Colombier /* fill in image where it used to be off the screen. */
8106b6b9ac8SDavid du Colombier if(rectclip(&or, screen->r))
8116b6b9ac8SDavid du Colombier drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min, S);
8126b6b9ac8SDavid du Colombier else
8136b6b9ac8SDavid du Colombier drawop(screen, r, im, nil, im->r.min, S);
8147dd7cddfSDavid du Colombier flushimage(display, 1);
8157dd7cddfSDavid du Colombier }
8167dd7cddfSDavid du Colombier
8177dd7cddfSDavid du Colombier void
redraw(Image * screen)8187dd7cddfSDavid du Colombier redraw(Image *screen)
8197dd7cddfSDavid du Colombier {
8207dd7cddfSDavid du Colombier Rectangle r;
8217dd7cddfSDavid du Colombier
8227dd7cddfSDavid du Colombier if(im == nil)
8237dd7cddfSDavid du Colombier return;
8247dd7cddfSDavid du Colombier
8257dd7cddfSDavid du Colombier ulrange.max = screen->r.max;
8267dd7cddfSDavid du Colombier ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r)));
8277dd7cddfSDavid du Colombier
8287dd7cddfSDavid du Colombier ul = pclip(ul, ulrange);
8296b6b9ac8SDavid du Colombier drawop(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min)), S);
8307dd7cddfSDavid du Colombier
8317dd7cddfSDavid du Colombier if(im->repl)
8327dd7cddfSDavid du Colombier return;
8337dd7cddfSDavid du Colombier
8347dd7cddfSDavid du Colombier /* fill in any outer edges */
8357dd7cddfSDavid du Colombier /* black border */
8367dd7cddfSDavid du Colombier r = rectaddpt(im->r, subpt(ul, im->r.min));
8377dd7cddfSDavid du Colombier border(screen, r, -2, display->black, ZP);
8387dd7cddfSDavid du Colombier r.min = subpt(r.min, Pt(2,2));
8397dd7cddfSDavid du Colombier r.max = addpt(r.max, Pt(2,2));
8407dd7cddfSDavid du Colombier
8417dd7cddfSDavid du Colombier /* gray for the rest */
8427dd7cddfSDavid du Colombier if(gray == nil) {
8437dd7cddfSDavid du Colombier gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF);
8447dd7cddfSDavid du Colombier if(gray == nil) {
8457dd7cddfSDavid du Colombier fprint(2, "g out of memory: %r\n");
8467dd7cddfSDavid du Colombier wexits("mem");
8477dd7cddfSDavid du Colombier }
8487dd7cddfSDavid du Colombier }
8497dd7cddfSDavid du Colombier border(screen, r, -4000, gray, ZP);
8507dd7cddfSDavid du Colombier // flushimage(display, 0);
8517dd7cddfSDavid du Colombier }
8527dd7cddfSDavid du Colombier
8537dd7cddfSDavid du Colombier void
eresized(int new)8547dd7cddfSDavid du Colombier eresized(int new)
8557dd7cddfSDavid du Colombier {
8567dd7cddfSDavid du Colombier Rectangle r;
8577dd7cddfSDavid du Colombier r = screen->r;
8587dd7cddfSDavid du Colombier if(new && getwindow(display, Refnone) < 0)
8597dd7cddfSDavid du Colombier fprint(2,"can't reattach to window");
8607dd7cddfSDavid du Colombier ul = addpt(ul, subpt(screen->r.min, r.min));
8617dd7cddfSDavid du Colombier redraw(screen);
8627dd7cddfSDavid du Colombier }
8637dd7cddfSDavid du Colombier
8647dd7cddfSDavid du Colombier /* clip p to be in r */
8657dd7cddfSDavid du Colombier Point
pclip(Point p,Rectangle r)8667dd7cddfSDavid du Colombier pclip(Point p, Rectangle r)
8677dd7cddfSDavid du Colombier {
8687dd7cddfSDavid du Colombier if(p.x < r.min.x)
8697dd7cddfSDavid du Colombier p.x = r.min.x;
8707dd7cddfSDavid du Colombier else if(p.x >= r.max.x)
8717dd7cddfSDavid du Colombier p.x = r.max.x-1;
8727dd7cddfSDavid du Colombier
8737dd7cddfSDavid du Colombier if(p.y < r.min.y)
8747dd7cddfSDavid du Colombier p.y = r.min.y;
8757dd7cddfSDavid du Colombier else if(p.y >= r.max.y)
8767dd7cddfSDavid du Colombier p.y = r.max.y-1;
8777dd7cddfSDavid du Colombier
8787dd7cddfSDavid du Colombier return p;
8797dd7cddfSDavid du Colombier }
8807dd7cddfSDavid du Colombier
8817dd7cddfSDavid du Colombier /*
8827dd7cddfSDavid du Colombier * resize is perhaps a misnomer.
8837dd7cddfSDavid du Colombier * this really just grows the window to be at least dx across
8847dd7cddfSDavid du Colombier * and dy high. if the window hits the bottom or right edge,
8857dd7cddfSDavid du Colombier * it is backed up until it hits the top or left edge.
8867dd7cddfSDavid du Colombier */
8877dd7cddfSDavid du Colombier void
resize(int dx,int dy)8887dd7cddfSDavid du Colombier resize(int dx, int dy)
8897dd7cddfSDavid du Colombier {
8907dd7cddfSDavid du Colombier static Rectangle sr;
8917dd7cddfSDavid du Colombier Rectangle r, or;
8927dd7cddfSDavid du Colombier
8937dd7cddfSDavid du Colombier dx += 2*Borderwidth;
8947dd7cddfSDavid du Colombier dy += 2*Borderwidth;
8957dd7cddfSDavid du Colombier if(wctlfd < 0){
8967dd7cddfSDavid du Colombier wctlfd = open("/dev/wctl", OWRITE);
8977dd7cddfSDavid du Colombier if(wctlfd < 0)
8987dd7cddfSDavid du Colombier return;
8997dd7cddfSDavid du Colombier }
9007dd7cddfSDavid du Colombier
9017dd7cddfSDavid du Colombier r = insetrect(screen->r, -Borderwidth);
9027dd7cddfSDavid du Colombier if(Dx(r) >= dx && Dy(r) >= dy)
9037dd7cddfSDavid du Colombier return;
9047dd7cddfSDavid du Colombier
9057dd7cddfSDavid du Colombier if(Dx(sr)*Dy(sr) == 0)
9067dd7cddfSDavid du Colombier sr = screenrect();
9077dd7cddfSDavid du Colombier
9087dd7cddfSDavid du Colombier or = r;
9097dd7cddfSDavid du Colombier
9107dd7cddfSDavid du Colombier r.max.x = max(r.min.x+dx, r.max.x);
9117dd7cddfSDavid du Colombier r.max.y = max(r.min.y+dy, r.max.y);
9127dd7cddfSDavid du Colombier if(r.max.x > sr.max.x){
9137dd7cddfSDavid du Colombier if(Dx(r) > Dx(sr)){
9147dd7cddfSDavid du Colombier r.min.x = 0;
9157dd7cddfSDavid du Colombier r.max.x = sr.max.x;
9167dd7cddfSDavid du Colombier }else
9177dd7cddfSDavid du Colombier r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0));
9187dd7cddfSDavid du Colombier }
9197dd7cddfSDavid du Colombier if(r.max.y > sr.max.y){
9207dd7cddfSDavid du Colombier if(Dy(r) > Dy(sr)){
9217dd7cddfSDavid du Colombier r.min.y = 0;
9227dd7cddfSDavid du Colombier r.max.y = sr.max.y;
9237dd7cddfSDavid du Colombier }else
9247dd7cddfSDavid du Colombier r = rectaddpt(r, Pt(0, sr.max.y-r.max.y));
9257dd7cddfSDavid du Colombier }
9267dd7cddfSDavid du Colombier
9277dd7cddfSDavid du Colombier /*
9287dd7cddfSDavid du Colombier * Sometimes we can't actually grow the window big enough,
9297dd7cddfSDavid du Colombier * and resizing it to the same shape makes it flash.
9307dd7cddfSDavid du Colombier */
9317dd7cddfSDavid du Colombier if(Dx(r) == Dx(or) && Dy(r) == Dy(or))
9327dd7cddfSDavid du Colombier return;
9337dd7cddfSDavid du Colombier
9347dd7cddfSDavid du Colombier fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n",
9357dd7cddfSDavid du Colombier r.min.x, r.min.y, r.max.x, r.max.y);
9367dd7cddfSDavid du Colombier }
9377dd7cddfSDavid du Colombier
9387dd7cddfSDavid du Colombier /*
9397dd7cddfSDavid du Colombier * If we allocimage after a resize but before flushing the draw buffer,
9407dd7cddfSDavid du Colombier * we won't have seen the reshape event, and we won't have called
9417dd7cddfSDavid du Colombier * getwindow, and allocimage will fail. So we flushimage before every alloc.
9427dd7cddfSDavid du Colombier */
9437dd7cddfSDavid du Colombier Image*
xallocimage(Display * d,Rectangle r,ulong chan,int repl,ulong val)9447dd7cddfSDavid du Colombier xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
9457dd7cddfSDavid du Colombier {
9467dd7cddfSDavid du Colombier flushimage(display, 0);
9477dd7cddfSDavid du Colombier return allocimage(d, r, chan, repl, val);
9487dd7cddfSDavid du Colombier }
9497dd7cddfSDavid du Colombier
9507dd7cddfSDavid du Colombier /* all code below this line should be in the library, but is stolen from colors instead */
9517dd7cddfSDavid du Colombier static char*
rdenv(char * name)9527dd7cddfSDavid du Colombier rdenv(char *name)
9537dd7cddfSDavid du Colombier {
9547dd7cddfSDavid du Colombier char *v;
9557dd7cddfSDavid du Colombier int fd, size;
9567dd7cddfSDavid du Colombier
9577dd7cddfSDavid du Colombier fd = open(name, OREAD);
9587dd7cddfSDavid du Colombier if(fd < 0)
9597dd7cddfSDavid du Colombier return 0;
9607dd7cddfSDavid du Colombier size = seek(fd, 0, 2);
9617dd7cddfSDavid du Colombier v = malloc(size+1);
9627dd7cddfSDavid du Colombier if(v == 0){
9637dd7cddfSDavid du Colombier fprint(2, "page: can't malloc: %r\n");
9647dd7cddfSDavid du Colombier wexits("no mem");
9657dd7cddfSDavid du Colombier }
9667dd7cddfSDavid du Colombier seek(fd, 0, 0);
9677dd7cddfSDavid du Colombier read(fd, v, size);
9687dd7cddfSDavid du Colombier v[size] = 0;
9697dd7cddfSDavid du Colombier close(fd);
9707dd7cddfSDavid du Colombier return v;
9717dd7cddfSDavid du Colombier }
9727dd7cddfSDavid du Colombier
9737dd7cddfSDavid du Colombier void
newwin(void)9747dd7cddfSDavid du Colombier newwin(void)
9757dd7cddfSDavid du Colombier {
9767dd7cddfSDavid du Colombier char *srv, *mntsrv;
9777dd7cddfSDavid du Colombier char spec[100];
9787dd7cddfSDavid du Colombier int srvfd, cons, pid;
9797dd7cddfSDavid du Colombier
9807dd7cddfSDavid du Colombier switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){
9817dd7cddfSDavid du Colombier case -1:
9827dd7cddfSDavid du Colombier fprint(2, "page: can't fork: %r\n");
9837dd7cddfSDavid du Colombier wexits("no fork");
9847dd7cddfSDavid du Colombier case 0:
9857dd7cddfSDavid du Colombier break;
9867dd7cddfSDavid du Colombier default:
9877dd7cddfSDavid du Colombier wexits(0);
9887dd7cddfSDavid du Colombier }
9897dd7cddfSDavid du Colombier
9907dd7cddfSDavid du Colombier srv = rdenv("/env/wsys");
9917dd7cddfSDavid du Colombier if(srv == 0){
9927dd7cddfSDavid du Colombier mntsrv = rdenv("/mnt/term/env/wsys");
9937dd7cddfSDavid du Colombier if(mntsrv == 0){
9947dd7cddfSDavid du Colombier fprint(2, "page: can't find $wsys\n");
9957dd7cddfSDavid du Colombier wexits("srv");
9967dd7cddfSDavid du Colombier }
9977dd7cddfSDavid du Colombier srv = malloc(strlen(mntsrv)+10);
9987dd7cddfSDavid du Colombier sprint(srv, "/mnt/term%s", mntsrv);
9997dd7cddfSDavid du Colombier free(mntsrv);
10007dd7cddfSDavid du Colombier pid = 0; /* can't send notes to remote processes! */
10017dd7cddfSDavid du Colombier }else
10027dd7cddfSDavid du Colombier pid = getpid();
10037dd7cddfSDavid du Colombier srvfd = open(srv, ORDWR);
10047dd7cddfSDavid du Colombier if(srvfd == -1){
10057dd7cddfSDavid du Colombier fprint(2, "page: can't open %s: %r\n", srv);
10067dd7cddfSDavid du Colombier wexits("no srv");
10077dd7cddfSDavid du Colombier }
1008fae06aafSDavid du Colombier free(srv);
10097dd7cddfSDavid du Colombier sprint(spec, "new -pid %d", pid);
10109a747e4fSDavid du Colombier if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
10117dd7cddfSDavid du Colombier fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
10127dd7cddfSDavid du Colombier wexits("no mount");
10137dd7cddfSDavid du Colombier }
10147dd7cddfSDavid du Colombier close(srvfd);
10157dd7cddfSDavid du Colombier unmount("/mnt/acme", "/dev");
10167dd7cddfSDavid du Colombier bind("/mnt/wsys", "/dev", MBEFORE);
10177dd7cddfSDavid du Colombier cons = open("/dev/cons", OREAD);
10187dd7cddfSDavid du Colombier if(cons==-1){
10197dd7cddfSDavid du Colombier NoCons:
10207dd7cddfSDavid du Colombier fprint(2, "page: can't open /dev/cons: %r");
10217dd7cddfSDavid du Colombier wexits("no cons");
10227dd7cddfSDavid du Colombier }
10237dd7cddfSDavid du Colombier dup(cons, 0);
10247dd7cddfSDavid du Colombier close(cons);
10257dd7cddfSDavid du Colombier cons = open("/dev/cons", OWRITE);
10267dd7cddfSDavid du Colombier if(cons==-1)
10277dd7cddfSDavid du Colombier goto NoCons;
10287dd7cddfSDavid du Colombier dup(cons, 1);
10297dd7cddfSDavid du Colombier dup(cons, 2);
10307dd7cddfSDavid du Colombier close(cons);
10317dd7cddfSDavid du Colombier // wctlfd = open("/dev/wctl", OWRITE);
10327dd7cddfSDavid du Colombier }
10337dd7cddfSDavid du Colombier
10347dd7cddfSDavid du Colombier Rectangle
screenrect(void)10357dd7cddfSDavid du Colombier screenrect(void)
10367dd7cddfSDavid du Colombier {
10377dd7cddfSDavid du Colombier int fd;
10387dd7cddfSDavid du Colombier char buf[12*5];
10397dd7cddfSDavid du Colombier
10407dd7cddfSDavid du Colombier fd = open("/dev/screen", OREAD);
10417dd7cddfSDavid du Colombier if(fd == -1)
10427dd7cddfSDavid du Colombier fd=open("/mnt/term/dev/screen", OREAD);
10437dd7cddfSDavid du Colombier if(fd == -1){
10447dd7cddfSDavid du Colombier fprint(2, "page: can't open /dev/screen: %r\n");
10457dd7cddfSDavid du Colombier wexits("window read");
10467dd7cddfSDavid du Colombier }
10477dd7cddfSDavid du Colombier if(read(fd, buf, sizeof buf) != sizeof buf){
10487dd7cddfSDavid du Colombier fprint(2, "page: can't read /dev/screen: %r\n");
10497dd7cddfSDavid du Colombier wexits("screen read");
10507dd7cddfSDavid du Colombier }
10517dd7cddfSDavid du Colombier close(fd);
10527dd7cddfSDavid du Colombier return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
10537dd7cddfSDavid du Colombier }
10547dd7cddfSDavid du Colombier
10557def40e1SDavid du Colombier void
zerox(void)10567def40e1SDavid du Colombier zerox(void)
10577def40e1SDavid du Colombier {
10587def40e1SDavid du Colombier int pfd[2];
10597def40e1SDavid du Colombier
10607def40e1SDavid du Colombier pipe(pfd);
10617def40e1SDavid du Colombier switch(rfork(RFFDG|RFREND|RFPROC)) {
10627def40e1SDavid du Colombier case -1:
10637def40e1SDavid du Colombier wexits("cannot fork in zerox: %r");
10647def40e1SDavid du Colombier case 0:
10657def40e1SDavid du Colombier dup(pfd[1], 0);
10667def40e1SDavid du Colombier close(pfd[0]);
1067f19e7b74SDavid du Colombier execl("/bin/page", "page", "-w", nil);
10687def40e1SDavid du Colombier wexits("cannot exec in zerox: %r\n");
10697def40e1SDavid du Colombier default:
10707def40e1SDavid du Colombier close(pfd[1]);
10717def40e1SDavid du Colombier writeimage(pfd[0], im, 0);
10727def40e1SDavid du Colombier close(pfd[0]);
10737def40e1SDavid du Colombier break;
10747def40e1SDavid du Colombier }
10757def40e1SDavid du Colombier }
1076