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 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 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 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 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* 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 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* 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 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 223*0ceffd3cSDavid du Colombier static int 224*0ceffd3cSDavid du Colombier plumbquit(Plumbmsg *msg) 225*0ceffd3cSDavid du Colombier { 226*0ceffd3cSDavid du Colombier char *s; 227*0ceffd3cSDavid du Colombier 228*0ceffd3cSDavid du Colombier s = plumblookup(msg->attr, "action"); 229*0ceffd3cSDavid du Colombier return s && strcmp(s, "quit")==0; 230*0ceffd3cSDavid du Colombier } 231*0ceffd3cSDavid 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 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 3207dd7cddfSDavid du Colombier showpage(page, &menu); 3217dd7cddfSDavid du Colombier esetcursor(nil); 3227dd7cddfSDavid du Colombier 3237dd7cddfSDavid du Colombier nxt = 0; 3247dd7cddfSDavid du Colombier for(;;) { 3257dd7cddfSDavid du Colombier /* 3267dd7cddfSDavid du Colombier * throughout, if doc->fwdonly is set, we restrict the functionality 3277dd7cddfSDavid du Colombier * a fair amount. we don't care about doc->npage anymore, and 3287dd7cddfSDavid du Colombier * all that can be done is select the next page. 3297dd7cddfSDavid du Colombier */ 330493edcedSDavid du Colombier unlockdisplay(display); 331493edcedSDavid du Colombier i = eread(Emouse|Ekeyboard|Eplumb, &e); 332493edcedSDavid du Colombier lockdisplay(display); 333493edcedSDavid du Colombier switch(i){ 3347dd7cddfSDavid du Colombier case Ekeyboard: 3357dd7cddfSDavid du Colombier if(e.kbdc <= 0xFF && isdigit(e.kbdc)) { 3367dd7cddfSDavid du Colombier nxt = nxt*10+e.kbdc-'0'; 3377dd7cddfSDavid du Colombier break; 3387dd7cddfSDavid du Colombier } else if(e.kbdc != '\n') 3397dd7cddfSDavid du Colombier nxt = 0; 3407dd7cddfSDavid du Colombier switch(e.kbdc) { 3417dd7cddfSDavid du Colombier case 'r': /* reverse page order */ 3427dd7cddfSDavid du Colombier if(doc->fwdonly) 3437dd7cddfSDavid du Colombier break; 3447dd7cddfSDavid du Colombier reverse = !reverse; 3457dd7cddfSDavid du Colombier menu.lasthit = doc->npage-1-menu.lasthit; 3467dd7cddfSDavid du Colombier 3477dd7cddfSDavid du Colombier /* 3487dd7cddfSDavid du Colombier * the theory is that if we are reversing the 3497dd7cddfSDavid du Colombier * document order and are on the first or last 3507dd7cddfSDavid du Colombier * page then we're just starting and really want 3517dd7cddfSDavid du Colombier * to view the other end. maybe the if 3527dd7cddfSDavid du Colombier * should be dropped and this should happen always. 3537dd7cddfSDavid du Colombier */ 3547dd7cddfSDavid du Colombier if(page == 0 || page == doc->npage-1) { 3557dd7cddfSDavid du Colombier page = doc->npage-1-page; 3567dd7cddfSDavid du Colombier showpage(page, &menu); 3577dd7cddfSDavid du Colombier } 3587dd7cddfSDavid du Colombier break; 3597dd7cddfSDavid du Colombier case 'w': /* write bitmap of current screen */ 3607dd7cddfSDavid du Colombier esetcursor(&reading); 3617dd7cddfSDavid du Colombier s = writebitmap(); 3627dd7cddfSDavid du Colombier if(s) 3637dd7cddfSDavid du Colombier string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, 3647dd7cddfSDavid du Colombier display->defaultfont, s); 3657dd7cddfSDavid du Colombier esetcursor(nil); 3667dd7cddfSDavid du Colombier flushimage(display, 1); 3677dd7cddfSDavid du Colombier break; 3687dd7cddfSDavid du Colombier case 'd': /* remove image from working set */ 3697dd7cddfSDavid du Colombier if(doc->rmpage && page < doc->npage) { 3707dd7cddfSDavid du Colombier if(doc->rmpage(doc, page) >= 0) { 3717dd7cddfSDavid du Colombier if(doc->npage < 0) 3727dd7cddfSDavid du Colombier wexits(0); 3737dd7cddfSDavid du Colombier if(page >= doc->npage) 3747dd7cddfSDavid du Colombier page = doc->npage-1; 3757dd7cddfSDavid du Colombier showpage(page, &menu); 3767dd7cddfSDavid du Colombier } 3777dd7cddfSDavid du Colombier } 3787dd7cddfSDavid du Colombier break; 3797dd7cddfSDavid du Colombier case 'q': 3807dd7cddfSDavid du Colombier case 0x04: /* ctrl-d */ 3817dd7cddfSDavid du Colombier wexits(0); 3827dd7cddfSDavid du Colombier case 'u': 3837dd7cddfSDavid du Colombier if(im==nil) 3847dd7cddfSDavid du Colombier break; 385a7529a1dSDavid du Colombier angle = (angle+180) % 360; 386493edcedSDavid du Colombier showpage(page, &menu); 3877dd7cddfSDavid du Colombier break; 3887dd7cddfSDavid du Colombier case '-': 3897dd7cddfSDavid du Colombier case '\b': 390223a736eSDavid du Colombier case Kleft: 3917dd7cddfSDavid du Colombier if(page > 0 && !doc->fwdonly) { 3927dd7cddfSDavid du Colombier --page; 3937dd7cddfSDavid du Colombier showpage(page, &menu); 3947dd7cddfSDavid du Colombier } 3957dd7cddfSDavid du Colombier break; 3967dd7cddfSDavid du Colombier case '\n': 3977dd7cddfSDavid du Colombier if(nxt) { 3987dd7cddfSDavid du Colombier nxt--; 3997dd7cddfSDavid du Colombier if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly) 4007dd7cddfSDavid du Colombier showpage(page=nxt, &menu); 4017dd7cddfSDavid du Colombier nxt = 0; 4027dd7cddfSDavid du Colombier break; 4037dd7cddfSDavid du Colombier } 40459cc4ca5SDavid du Colombier goto Gotonext; 405223a736eSDavid du Colombier case Kright: 406223a736eSDavid du Colombier case ' ': 40759cc4ca5SDavid du Colombier Gotonext: 4087dd7cddfSDavid du Colombier if(doc->npage && ++page >= doc->npage && !doc->fwdonly) 4097dd7cddfSDavid du Colombier wexits(0); 4107dd7cddfSDavid du Colombier showpage(page, &menu); 4117dd7cddfSDavid du Colombier break; 41259cc4ca5SDavid du Colombier 41359cc4ca5SDavid du Colombier /* 41459cc4ca5SDavid du Colombier * The upper y coordinate of the image is at ul.y in screen->r. 41559cc4ca5SDavid du Colombier * Panning up means moving the upper left corner down. If the 41659cc4ca5SDavid du Colombier * upper left corner is currently visible, we need to go back a page. 41759cc4ca5SDavid du Colombier */ 41859cc4ca5SDavid du Colombier case Kup: 41959cc4ca5SDavid du Colombier if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){ 42059cc4ca5SDavid du Colombier if(page > 0 && !doc->fwdonly){ 42159cc4ca5SDavid du Colombier --page; 42259cc4ca5SDavid du Colombier showbottom = 1; 42359cc4ca5SDavid du Colombier showpage(page, &menu); 42459cc4ca5SDavid du Colombier } 42559cc4ca5SDavid du Colombier } else { 42659cc4ca5SDavid du Colombier i = Dy(screen->r)/2; 42759cc4ca5SDavid du Colombier if(i > 10) 42859cc4ca5SDavid du Colombier i -= 10; 42959cc4ca5SDavid du Colombier if(i+ul.y > screen->r.min.y) 43059cc4ca5SDavid du Colombier i = screen->r.min.y - ul.y; 43159cc4ca5SDavid du Colombier translate(Pt(0, i)); 43259cc4ca5SDavid du Colombier } 43359cc4ca5SDavid du Colombier break; 43459cc4ca5SDavid du Colombier 43559cc4ca5SDavid du Colombier /* 43659cc4ca5SDavid du Colombier * If the lower y coordinate is on the screen, we go to the next page. 43759cc4ca5SDavid du Colombier * The lower y coordinate is at ul.y + Dy(im->r). 43859cc4ca5SDavid du Colombier */ 43959cc4ca5SDavid du Colombier case Kdown: 44059cc4ca5SDavid du Colombier i = ul.y + Dy(im->r); 44159cc4ca5SDavid du Colombier if(screen->r.min.y <= i && i <= screen->r.max.y){ 44259cc4ca5SDavid du Colombier ul.y = screen->r.min.y; 44359cc4ca5SDavid du Colombier goto Gotonext; 44459cc4ca5SDavid du Colombier } else { 44559cc4ca5SDavid du Colombier i = -Dy(screen->r)/2; 44659cc4ca5SDavid du Colombier if(i < -10) 44759cc4ca5SDavid du Colombier i += 10; 44859cc4ca5SDavid du Colombier if(i+ul.y+Dy(im->r) <= screen->r.max.y) 44959cc4ca5SDavid du Colombier i = screen->r.max.y - Dy(im->r) - ul.y - 1; 45059cc4ca5SDavid du Colombier translate(Pt(0, i)); 45159cc4ca5SDavid du Colombier } 45259cc4ca5SDavid du Colombier break; 453223a736eSDavid du Colombier default: 454223a736eSDavid du Colombier esetcursor(&query); 455223a736eSDavid du Colombier sleep(1000); 456223a736eSDavid du Colombier esetcursor(nil); 457223a736eSDavid du Colombier break; 4587dd7cddfSDavid du Colombier } 4597dd7cddfSDavid du Colombier break; 4607dd7cddfSDavid du Colombier 4617dd7cddfSDavid du Colombier case Emouse: 4627dd7cddfSDavid du Colombier m = e.mouse; 4637dd7cddfSDavid du Colombier switch(m.buttons){ 4647dd7cddfSDavid du Colombier case Left: 4657dd7cddfSDavid du Colombier oxy = m.xy; 4667dd7cddfSDavid du Colombier xy0 = oxy; 4677dd7cddfSDavid du Colombier do { 4687dd7cddfSDavid du Colombier dxy = subpt(m.xy, oxy); 4697dd7cddfSDavid du Colombier oxy = m.xy; 4707dd7cddfSDavid du Colombier translate(dxy); 471493edcedSDavid du Colombier unlockdisplay(display); 4727dd7cddfSDavid du Colombier m = emouse(); 473493edcedSDavid du Colombier lockdisplay(display); 4747dd7cddfSDavid du Colombier } while(m.buttons == Left); 4757dd7cddfSDavid du Colombier if(m.buttons) { 4767dd7cddfSDavid du Colombier dxy = subpt(xy0, oxy); 4777dd7cddfSDavid du Colombier translate(dxy); 4787dd7cddfSDavid du Colombier } 4797dd7cddfSDavid du Colombier break; 4807dd7cddfSDavid du Colombier 4817dd7cddfSDavid du Colombier case Middle: 4827dd7cddfSDavid du Colombier if(doc->npage == 0) 4837dd7cddfSDavid du Colombier break; 4847dd7cddfSDavid du Colombier 485493edcedSDavid du Colombier unlockdisplay(display); 48608fd2d13SDavid du Colombier n = emenuhit(Middle, &m, &midmenu); 487493edcedSDavid du Colombier lockdisplay(display); 48808fd2d13SDavid du Colombier if(n == -1) 48908fd2d13SDavid du Colombier break; 49008fd2d13SDavid du Colombier switch(n){ 49108fd2d13SDavid du Colombier case Next: /* next */ 4927dd7cddfSDavid du Colombier if(reverse) 4937dd7cddfSDavid du Colombier page--; 4947dd7cddfSDavid du Colombier else 4957dd7cddfSDavid du Colombier page++; 49608fd2d13SDavid du Colombier if(page < 0) { 49708fd2d13SDavid du Colombier if(reverse) return; 49808fd2d13SDavid du Colombier else page = 0; 49908fd2d13SDavid du Colombier } 5007dd7cddfSDavid du Colombier 50108fd2d13SDavid du Colombier if((page >= doc->npage) && !doc->fwdonly) 5027dd7cddfSDavid du Colombier return; 5037dd7cddfSDavid du Colombier 5047dd7cddfSDavid du Colombier showpage(page, &menu); 5057dd7cddfSDavid du Colombier nxt = 0; 5067dd7cddfSDavid du Colombier break; 50708fd2d13SDavid du Colombier case Prev: /* prev */ 50808fd2d13SDavid du Colombier if(reverse) 50908fd2d13SDavid du Colombier page++; 51008fd2d13SDavid du Colombier else 51108fd2d13SDavid du Colombier page--; 51208fd2d13SDavid du Colombier if(page < 0) { 51308fd2d13SDavid du Colombier if(reverse) return; 51408fd2d13SDavid du Colombier else page = 0; 51508fd2d13SDavid du Colombier } 51608fd2d13SDavid du Colombier 51708fd2d13SDavid du Colombier if((page >= doc->npage) && !doc->fwdonly && !reverse) 51808fd2d13SDavid du Colombier return; 51908fd2d13SDavid du Colombier 52008fd2d13SDavid du Colombier showpage(page, &menu); 52108fd2d13SDavid du Colombier nxt = 0; 52208fd2d13SDavid du Colombier break; 5237def40e1SDavid du Colombier case Zerox: /* prev */ 5247def40e1SDavid du Colombier zerox(); 52508fd2d13SDavid du Colombier break; 52608fd2d13SDavid du Colombier case Zin: /* zoom in */ 52708fd2d13SDavid du Colombier { 52808fd2d13SDavid du Colombier double delta; 52908fd2d13SDavid du Colombier Rectangle r; 53008fd2d13SDavid du Colombier 53108fd2d13SDavid du Colombier r = egetrect(Middle, &m); 53208fd2d13SDavid du Colombier if((rectclip(&r, rectaddpt(im->r, ul)) == 0) || 53308fd2d13SDavid du Colombier Dx(r) == 0 || Dy(r) == 0) 53408fd2d13SDavid du Colombier break; 53508fd2d13SDavid du Colombier /* use the smaller side to expand */ 53608fd2d13SDavid du Colombier if(Dx(r) < Dy(r)) 53708fd2d13SDavid du Colombier delta = (double)Dx(im->r)/(double)Dx(r); 53808fd2d13SDavid du Colombier else 53908fd2d13SDavid du Colombier delta = (double)Dy(im->r)/(double)Dy(r); 54008fd2d13SDavid du Colombier 54108fd2d13SDavid du Colombier esetcursor(&reading); 5425316891fSDavid du Colombier tmp = xallocimage(display, 54308fd2d13SDavid du Colombier Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)), 54408fd2d13SDavid du Colombier im->chan, 0, DBlack); 5455316891fSDavid du Colombier if(tmp == nil) { 5465316891fSDavid du Colombier fprint(2, "out of memory during zoom: %r\n"); 5475316891fSDavid du Colombier wexits("memory"); 5485316891fSDavid du Colombier } 54908fd2d13SDavid du Colombier resample(im, tmp); 55008fd2d13SDavid du Colombier im = tmp; 551493edcedSDavid du Colombier delayfreeimage(tmp); 55208fd2d13SDavid du Colombier esetcursor(nil); 55308fd2d13SDavid du Colombier ul = screen->r.min; 55408fd2d13SDavid du Colombier redraw(screen); 55508fd2d13SDavid du Colombier flushimage(display, 1); 55608fd2d13SDavid du Colombier break; 55708fd2d13SDavid du Colombier } 55808fd2d13SDavid du Colombier case Fit: /* fit */ 55908fd2d13SDavid du Colombier { 56008fd2d13SDavid du Colombier double delta; 56108fd2d13SDavid du Colombier Rectangle r; 56208fd2d13SDavid du Colombier 56308fd2d13SDavid du Colombier delta = (double)Dx(screen->r)/(double)Dx(im->r); 56408fd2d13SDavid du Colombier if((double)Dy(im->r)*delta > Dy(screen->r)) 56508fd2d13SDavid du Colombier delta = (double)Dy(screen->r)/(double)Dy(im->r); 56608fd2d13SDavid du Colombier 56708fd2d13SDavid du Colombier r = Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)); 56808fd2d13SDavid du Colombier esetcursor(&reading); 5695316891fSDavid du Colombier tmp = xallocimage(display, r, im->chan, 0, DBlack); 5705316891fSDavid du Colombier if(tmp == nil) { 5715316891fSDavid du Colombier fprint(2, "out of memory during fit: %r\n"); 5725316891fSDavid du Colombier wexits("memory"); 5735316891fSDavid du Colombier } 57408fd2d13SDavid du Colombier resample(im, tmp); 57508fd2d13SDavid du Colombier im = tmp; 576493edcedSDavid du Colombier delayfreeimage(tmp); 57708fd2d13SDavid du Colombier esetcursor(nil); 57808fd2d13SDavid du Colombier ul = screen->r.min; 57908fd2d13SDavid du Colombier redraw(screen); 58008fd2d13SDavid du Colombier flushimage(display, 1); 58108fd2d13SDavid du Colombier break; 58208fd2d13SDavid du Colombier } 58308fd2d13SDavid du Colombier case Rot: /* rotate 90 */ 584a7529a1dSDavid du Colombier angle = (angle+90) % 360; 585493edcedSDavid du Colombier showpage(page, &menu); 58608fd2d13SDavid du Colombier break; 58708fd2d13SDavid du Colombier case Upside: /* upside-down */ 588a7529a1dSDavid du Colombier angle = (angle+180) % 360; 589493edcedSDavid du Colombier showpage(page, &menu); 59008fd2d13SDavid du Colombier break; 59108fd2d13SDavid du Colombier case Restore: /* restore */ 59208fd2d13SDavid du Colombier showpage(page, &menu); 59308fd2d13SDavid du Colombier break; 59408fd2d13SDavid du Colombier case Reverse: /* reverse */ 59508fd2d13SDavid du Colombier if(doc->fwdonly) 59608fd2d13SDavid du Colombier break; 59708fd2d13SDavid du Colombier reverse = !reverse; 59808fd2d13SDavid du Colombier menu.lasthit = doc->npage-1-menu.lasthit; 59908fd2d13SDavid du Colombier 60008fd2d13SDavid du Colombier if(page == 0 || page == doc->npage-1) { 60108fd2d13SDavid du Colombier page = doc->npage-1-page; 60208fd2d13SDavid du Colombier showpage(page, &menu); 60308fd2d13SDavid du Colombier } 60408fd2d13SDavid du Colombier break; 60508fd2d13SDavid du Colombier case Write: /* write */ 60608fd2d13SDavid du Colombier esetcursor(&reading); 60708fd2d13SDavid du Colombier s = writebitmap(); 60808fd2d13SDavid du Colombier if(s) 60908fd2d13SDavid du Colombier string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, 61008fd2d13SDavid du Colombier display->defaultfont, s); 61108fd2d13SDavid du Colombier esetcursor(nil); 61208fd2d13SDavid du Colombier flushimage(display, 1); 61308fd2d13SDavid du Colombier break; 61408fd2d13SDavid du Colombier case Del: /* delete */ 61508fd2d13SDavid du Colombier if(doc->rmpage && page < doc->npage) { 61608fd2d13SDavid du Colombier if(doc->rmpage(doc, page) >= 0) { 61708fd2d13SDavid du Colombier if(doc->npage < 0) 61808fd2d13SDavid du Colombier wexits(0); 61908fd2d13SDavid du Colombier if(page >= doc->npage) 62008fd2d13SDavid du Colombier page = doc->npage-1; 62108fd2d13SDavid du Colombier showpage(page, &menu); 62208fd2d13SDavid du Colombier } 62308fd2d13SDavid du Colombier } 62408fd2d13SDavid du Colombier break; 62508fd2d13SDavid du Colombier case Exit: /* exit */ 62608fd2d13SDavid du Colombier return; 62708fd2d13SDavid du Colombier case Empty1: 62808fd2d13SDavid du Colombier case Empty2: 62908fd2d13SDavid du Colombier case Empty3: 63008fd2d13SDavid du Colombier break; 63108fd2d13SDavid du Colombier 63208fd2d13SDavid du Colombier }; 63308fd2d13SDavid du Colombier 63408fd2d13SDavid du Colombier 6357dd7cddfSDavid du Colombier 6367dd7cddfSDavid du Colombier case Right: 6377dd7cddfSDavid du Colombier if(doc->npage == 0) 6387dd7cddfSDavid du Colombier break; 6397dd7cddfSDavid du Colombier 6407dd7cddfSDavid du Colombier oldpage = page; 641493edcedSDavid du Colombier unlockdisplay(display); 6427dd7cddfSDavid du Colombier n = emenuhit(RMenu, &m, &menu); 643493edcedSDavid du Colombier lockdisplay(display); 6447dd7cddfSDavid du Colombier if(n == -1) 6457dd7cddfSDavid du Colombier break; 6467dd7cddfSDavid du Colombier 6477dd7cddfSDavid du Colombier if(doc->fwdonly) { 6487dd7cddfSDavid du Colombier switch(n){ 6497dd7cddfSDavid du Colombier case 0: /* this page */ 6507dd7cddfSDavid du Colombier break; 6517dd7cddfSDavid du Colombier case 1: /* next page */ 6527dd7cddfSDavid du Colombier showpage(++page, &menu); 6537dd7cddfSDavid du Colombier break; 6547dd7cddfSDavid du Colombier case 2: /* exit */ 6557dd7cddfSDavid du Colombier return; 6567dd7cddfSDavid du Colombier } 6577dd7cddfSDavid du Colombier break; 6587dd7cddfSDavid du Colombier } 6597dd7cddfSDavid du Colombier 6607dd7cddfSDavid du Colombier if(n == doc->npage) 6617dd7cddfSDavid du Colombier return; 6627dd7cddfSDavid du Colombier else 6637dd7cddfSDavid du Colombier page = reverse ? doc->npage-1-n : n; 6647dd7cddfSDavid du Colombier 6657dd7cddfSDavid du Colombier if(oldpage != page) 6667dd7cddfSDavid du Colombier showpage(page, &menu); 6677dd7cddfSDavid du Colombier nxt = 0; 6687dd7cddfSDavid du Colombier break; 6697dd7cddfSDavid du Colombier } 6707dd7cddfSDavid du Colombier break; 6717dd7cddfSDavid du Colombier 6727dd7cddfSDavid du Colombier case Eplumb: 6737dd7cddfSDavid du Colombier pm = e.v; 6747dd7cddfSDavid du Colombier if(pm->ndata <= 0){ 6757dd7cddfSDavid du Colombier plumbfree(pm); 6767dd7cddfSDavid du Colombier break; 6777dd7cddfSDavid du Colombier } 678*0ceffd3cSDavid du Colombier if(plumbquit(pm)) 679*0ceffd3cSDavid du Colombier exits(nil); 6807dd7cddfSDavid du Colombier if(showdata(pm)) { 6817dd7cddfSDavid du Colombier s = estrdup("/tmp/pageplumbXXXXXXX"); 6827dd7cddfSDavid du Colombier fd = opentemp(s); 6837dd7cddfSDavid du Colombier write(fd, pm->data, pm->ndata); 6847dd7cddfSDavid du Colombier /* lose fd reference on purpose; the file is open ORCLOSE */ 6857dd7cddfSDavid du Colombier } else if(pm->data[0] == '/') { 6867dd7cddfSDavid du Colombier s = estrdup(pm->data); 6877dd7cddfSDavid du Colombier } else { 6887dd7cddfSDavid du Colombier s = emalloc(strlen(pm->wdir)+1+pm->ndata+1); 6897dd7cddfSDavid du Colombier sprint(s, "%s/%s", pm->wdir, pm->data); 6907dd7cddfSDavid du Colombier cleanname(s); 6917dd7cddfSDavid du Colombier } 6927dd7cddfSDavid du Colombier if((i = doc->addpage(doc, s)) >= 0) { 6937dd7cddfSDavid du Colombier page = i; 6949a747e4fSDavid du Colombier unhide(); 6957dd7cddfSDavid du Colombier showpage(page, &menu); 6967dd7cddfSDavid du Colombier } 6977dd7cddfSDavid du Colombier free(s); 6987dd7cddfSDavid du Colombier plumbfree(pm); 6997dd7cddfSDavid du Colombier break; 7007dd7cddfSDavid du Colombier } 7017dd7cddfSDavid du Colombier } 7027dd7cddfSDavid du Colombier } 7037dd7cddfSDavid du Colombier 7047dd7cddfSDavid du Colombier Image *gray; 7057dd7cddfSDavid du Colombier 7067dd7cddfSDavid du Colombier /* 7077dd7cddfSDavid du Colombier * A draw operation that touches only the area contained in bot but not in top. 7087dd7cddfSDavid du Colombier * mp and sp get aligned with bot.min. 7097dd7cddfSDavid du Colombier */ 7107dd7cddfSDavid du Colombier static void 7117dd7cddfSDavid du Colombier gendrawdiff(Image *dst, Rectangle bot, Rectangle top, 7126b6b9ac8SDavid du Colombier Image *src, Point sp, Image *mask, Point mp, int op) 7137dd7cddfSDavid du Colombier { 7147dd7cddfSDavid du Colombier Rectangle r; 7157dd7cddfSDavid du Colombier Point origin; 7167dd7cddfSDavid du Colombier Point delta; 7177dd7cddfSDavid du Colombier 71808fd2d13SDavid du Colombier USED(op); 71908fd2d13SDavid du Colombier 7207dd7cddfSDavid du Colombier if(Dx(bot)*Dy(bot) == 0) 7217dd7cddfSDavid du Colombier return; 7227dd7cddfSDavid du Colombier 7237dd7cddfSDavid du Colombier /* no points in bot - top */ 7247dd7cddfSDavid du Colombier if(rectinrect(bot, top)) 7257dd7cddfSDavid du Colombier return; 7267dd7cddfSDavid du Colombier 7277dd7cddfSDavid du Colombier /* bot - top ≡ bot */ 7287dd7cddfSDavid du Colombier if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){ 7296b6b9ac8SDavid du Colombier gendrawop(dst, bot, src, sp, mask, mp, op); 7307dd7cddfSDavid du Colombier return; 7317dd7cddfSDavid du Colombier } 7327dd7cddfSDavid du Colombier 7337dd7cddfSDavid du Colombier origin = bot.min; 7347dd7cddfSDavid du Colombier /* split bot into rectangles that don't intersect top */ 7357dd7cddfSDavid du Colombier /* left side */ 7367dd7cddfSDavid du Colombier if(bot.min.x < top.min.x){ 7377dd7cddfSDavid du Colombier r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y); 7387dd7cddfSDavid du Colombier delta = subpt(r.min, origin); 7396b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 7407dd7cddfSDavid du Colombier bot.min.x = top.min.x; 7417dd7cddfSDavid du Colombier } 7427dd7cddfSDavid du Colombier 7437dd7cddfSDavid du Colombier /* right side */ 7447dd7cddfSDavid du Colombier if(bot.max.x > top.max.x){ 7457dd7cddfSDavid du Colombier r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y); 7467dd7cddfSDavid du Colombier delta = subpt(r.min, origin); 7476b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 7487dd7cddfSDavid du Colombier bot.max.x = top.max.x; 7497dd7cddfSDavid du Colombier } 7507dd7cddfSDavid du Colombier 7517dd7cddfSDavid du Colombier /* top */ 7527dd7cddfSDavid du Colombier if(bot.min.y < top.min.y){ 7537dd7cddfSDavid du Colombier r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y); 7547dd7cddfSDavid du Colombier delta = subpt(r.min, origin); 7556b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 7567dd7cddfSDavid du Colombier bot.min.y = top.min.y; 7577dd7cddfSDavid du Colombier } 7587dd7cddfSDavid du Colombier 7597dd7cddfSDavid du Colombier /* bottom */ 7607dd7cddfSDavid du Colombier if(bot.max.y > top.max.y){ 7617dd7cddfSDavid du Colombier r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y); 7627dd7cddfSDavid du Colombier delta = subpt(r.min, origin); 7636b6b9ac8SDavid du Colombier gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); 7647dd7cddfSDavid du Colombier bot.max.y = top.max.y; 7657dd7cddfSDavid du Colombier } 7667dd7cddfSDavid du Colombier } 7677dd7cddfSDavid du Colombier 7687dd7cddfSDavid du Colombier static void 7696b6b9ac8SDavid du Colombier drawdiff(Image *dst, Rectangle bot, Rectangle top, Image *src, Image *mask, Point p, int op) 7707dd7cddfSDavid du Colombier { 7716b6b9ac8SDavid du Colombier gendrawdiff(dst, bot, top, src, p, mask, p, op); 7727dd7cddfSDavid du Colombier } 7737dd7cddfSDavid du Colombier 7747dd7cddfSDavid du Colombier /* 7757dd7cddfSDavid du Colombier * Translate the image in the window by delta. 7767dd7cddfSDavid du Colombier */ 7777dd7cddfSDavid du Colombier static void 7787dd7cddfSDavid du Colombier translate(Point delta) 7797dd7cddfSDavid du Colombier { 7807dd7cddfSDavid du Colombier Point u; 7817dd7cddfSDavid du Colombier Rectangle r, or; 7827dd7cddfSDavid du Colombier 7837dd7cddfSDavid du Colombier if(im == nil) 7847dd7cddfSDavid du Colombier return; 7857dd7cddfSDavid du Colombier 7867dd7cddfSDavid du Colombier u = pclip(addpt(ul, delta), ulrange); 7877dd7cddfSDavid du Colombier delta = subpt(u, ul); 7887dd7cddfSDavid du Colombier if(delta.x == 0 && delta.y == 0) 7897dd7cddfSDavid du Colombier return; 7907dd7cddfSDavid du Colombier 7917dd7cddfSDavid du Colombier /* 7927dd7cddfSDavid du Colombier * The upper left corner of the image is currently at ul. 7937dd7cddfSDavid du Colombier * We want to move it to u. 7947dd7cddfSDavid du Colombier */ 7957dd7cddfSDavid du Colombier or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul); 7967dd7cddfSDavid du Colombier r = rectaddpt(or, delta); 7977dd7cddfSDavid du Colombier 7986b6b9ac8SDavid du Colombier drawop(screen, r, screen, nil, ul, S); 7997dd7cddfSDavid du Colombier ul = u; 8007dd7cddfSDavid du Colombier 8017dd7cddfSDavid du Colombier /* fill in gray where image used to be but isn't. */ 8026b6b9ac8SDavid du Colombier drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP, S); 8037dd7cddfSDavid du Colombier 8047dd7cddfSDavid du Colombier /* fill in black border */ 8056b6b9ac8SDavid du Colombier drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S); 8067dd7cddfSDavid du Colombier 8077dd7cddfSDavid du Colombier /* fill in image where it used to be off the screen. */ 8086b6b9ac8SDavid du Colombier if(rectclip(&or, screen->r)) 8096b6b9ac8SDavid du Colombier drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min, S); 8106b6b9ac8SDavid du Colombier else 8116b6b9ac8SDavid du Colombier drawop(screen, r, im, nil, im->r.min, S); 8127dd7cddfSDavid du Colombier flushimage(display, 1); 8137dd7cddfSDavid du Colombier } 8147dd7cddfSDavid du Colombier 8157dd7cddfSDavid du Colombier void 8167dd7cddfSDavid du Colombier redraw(Image *screen) 8177dd7cddfSDavid du Colombier { 8187dd7cddfSDavid du Colombier Rectangle r; 8197dd7cddfSDavid du Colombier 8207dd7cddfSDavid du Colombier if(im == nil) 8217dd7cddfSDavid du Colombier return; 8227dd7cddfSDavid du Colombier 8237dd7cddfSDavid du Colombier ulrange.max = screen->r.max; 8247dd7cddfSDavid du Colombier ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r))); 8257dd7cddfSDavid du Colombier 8267dd7cddfSDavid du Colombier ul = pclip(ul, ulrange); 8276b6b9ac8SDavid du Colombier drawop(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min)), S); 8287dd7cddfSDavid du Colombier 8297dd7cddfSDavid du Colombier if(im->repl) 8307dd7cddfSDavid du Colombier return; 8317dd7cddfSDavid du Colombier 8327dd7cddfSDavid du Colombier /* fill in any outer edges */ 8337dd7cddfSDavid du Colombier /* black border */ 8347dd7cddfSDavid du Colombier r = rectaddpt(im->r, subpt(ul, im->r.min)); 8357dd7cddfSDavid du Colombier border(screen, r, -2, display->black, ZP); 8367dd7cddfSDavid du Colombier r.min = subpt(r.min, Pt(2,2)); 8377dd7cddfSDavid du Colombier r.max = addpt(r.max, Pt(2,2)); 8387dd7cddfSDavid du Colombier 8397dd7cddfSDavid du Colombier /* gray for the rest */ 8407dd7cddfSDavid du Colombier if(gray == nil) { 8417dd7cddfSDavid du Colombier gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF); 8427dd7cddfSDavid du Colombier if(gray == nil) { 8437dd7cddfSDavid du Colombier fprint(2, "g out of memory: %r\n"); 8447dd7cddfSDavid du Colombier wexits("mem"); 8457dd7cddfSDavid du Colombier } 8467dd7cddfSDavid du Colombier } 8477dd7cddfSDavid du Colombier border(screen, r, -4000, gray, ZP); 8487dd7cddfSDavid du Colombier // flushimage(display, 0); 8497dd7cddfSDavid du Colombier } 8507dd7cddfSDavid du Colombier 8517dd7cddfSDavid du Colombier void 8527dd7cddfSDavid du Colombier eresized(int new) 8537dd7cddfSDavid du Colombier { 8547dd7cddfSDavid du Colombier Rectangle r; 8557dd7cddfSDavid du Colombier r = screen->r; 8567dd7cddfSDavid du Colombier if(new && getwindow(display, Refnone) < 0) 8577dd7cddfSDavid du Colombier fprint(2,"can't reattach to window"); 8587dd7cddfSDavid du Colombier ul = addpt(ul, subpt(screen->r.min, r.min)); 8597dd7cddfSDavid du Colombier redraw(screen); 8607dd7cddfSDavid du Colombier } 8617dd7cddfSDavid du Colombier 8627dd7cddfSDavid du Colombier /* clip p to be in r */ 8637dd7cddfSDavid du Colombier Point 8647dd7cddfSDavid du Colombier pclip(Point p, Rectangle r) 8657dd7cddfSDavid du Colombier { 8667dd7cddfSDavid du Colombier if(p.x < r.min.x) 8677dd7cddfSDavid du Colombier p.x = r.min.x; 8687dd7cddfSDavid du Colombier else if(p.x >= r.max.x) 8697dd7cddfSDavid du Colombier p.x = r.max.x-1; 8707dd7cddfSDavid du Colombier 8717dd7cddfSDavid du Colombier if(p.y < r.min.y) 8727dd7cddfSDavid du Colombier p.y = r.min.y; 8737dd7cddfSDavid du Colombier else if(p.y >= r.max.y) 8747dd7cddfSDavid du Colombier p.y = r.max.y-1; 8757dd7cddfSDavid du Colombier 8767dd7cddfSDavid du Colombier return p; 8777dd7cddfSDavid du Colombier } 8787dd7cddfSDavid du Colombier 8797dd7cddfSDavid du Colombier /* 8807dd7cddfSDavid du Colombier * resize is perhaps a misnomer. 8817dd7cddfSDavid du Colombier * this really just grows the window to be at least dx across 8827dd7cddfSDavid du Colombier * and dy high. if the window hits the bottom or right edge, 8837dd7cddfSDavid du Colombier * it is backed up until it hits the top or left edge. 8847dd7cddfSDavid du Colombier */ 8857dd7cddfSDavid du Colombier void 8867dd7cddfSDavid du Colombier resize(int dx, int dy) 8877dd7cddfSDavid du Colombier { 8887dd7cddfSDavid du Colombier static Rectangle sr; 8897dd7cddfSDavid du Colombier Rectangle r, or; 8907dd7cddfSDavid du Colombier 8917dd7cddfSDavid du Colombier dx += 2*Borderwidth; 8927dd7cddfSDavid du Colombier dy += 2*Borderwidth; 8937dd7cddfSDavid du Colombier if(wctlfd < 0){ 8947dd7cddfSDavid du Colombier wctlfd = open("/dev/wctl", OWRITE); 8957dd7cddfSDavid du Colombier if(wctlfd < 0) 8967dd7cddfSDavid du Colombier return; 8977dd7cddfSDavid du Colombier } 8987dd7cddfSDavid du Colombier 8997dd7cddfSDavid du Colombier r = insetrect(screen->r, -Borderwidth); 9007dd7cddfSDavid du Colombier if(Dx(r) >= dx && Dy(r) >= dy) 9017dd7cddfSDavid du Colombier return; 9027dd7cddfSDavid du Colombier 9037dd7cddfSDavid du Colombier if(Dx(sr)*Dy(sr) == 0) 9047dd7cddfSDavid du Colombier sr = screenrect(); 9057dd7cddfSDavid du Colombier 9067dd7cddfSDavid du Colombier or = r; 9077dd7cddfSDavid du Colombier 9087dd7cddfSDavid du Colombier r.max.x = max(r.min.x+dx, r.max.x); 9097dd7cddfSDavid du Colombier r.max.y = max(r.min.y+dy, r.max.y); 9107dd7cddfSDavid du Colombier if(r.max.x > sr.max.x){ 9117dd7cddfSDavid du Colombier if(Dx(r) > Dx(sr)){ 9127dd7cddfSDavid du Colombier r.min.x = 0; 9137dd7cddfSDavid du Colombier r.max.x = sr.max.x; 9147dd7cddfSDavid du Colombier }else 9157dd7cddfSDavid du Colombier r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0)); 9167dd7cddfSDavid du Colombier } 9177dd7cddfSDavid du Colombier if(r.max.y > sr.max.y){ 9187dd7cddfSDavid du Colombier if(Dy(r) > Dy(sr)){ 9197dd7cddfSDavid du Colombier r.min.y = 0; 9207dd7cddfSDavid du Colombier r.max.y = sr.max.y; 9217dd7cddfSDavid du Colombier }else 9227dd7cddfSDavid du Colombier r = rectaddpt(r, Pt(0, sr.max.y-r.max.y)); 9237dd7cddfSDavid du Colombier } 9247dd7cddfSDavid du Colombier 9257dd7cddfSDavid du Colombier /* 9267dd7cddfSDavid du Colombier * Sometimes we can't actually grow the window big enough, 9277dd7cddfSDavid du Colombier * and resizing it to the same shape makes it flash. 9287dd7cddfSDavid du Colombier */ 9297dd7cddfSDavid du Colombier if(Dx(r) == Dx(or) && Dy(r) == Dy(or)) 9307dd7cddfSDavid du Colombier return; 9317dd7cddfSDavid du Colombier 9327dd7cddfSDavid du Colombier fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n", 9337dd7cddfSDavid du Colombier r.min.x, r.min.y, r.max.x, r.max.y); 9347dd7cddfSDavid du Colombier } 9357dd7cddfSDavid du Colombier 9367dd7cddfSDavid du Colombier /* 9377dd7cddfSDavid du Colombier * If we allocimage after a resize but before flushing the draw buffer, 9387dd7cddfSDavid du Colombier * we won't have seen the reshape event, and we won't have called 9397dd7cddfSDavid du Colombier * getwindow, and allocimage will fail. So we flushimage before every alloc. 9407dd7cddfSDavid du Colombier */ 9417dd7cddfSDavid du Colombier Image* 9427dd7cddfSDavid du Colombier xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) 9437dd7cddfSDavid du Colombier { 9447dd7cddfSDavid du Colombier flushimage(display, 0); 9457dd7cddfSDavid du Colombier return allocimage(d, r, chan, repl, val); 9467dd7cddfSDavid du Colombier } 9477dd7cddfSDavid du Colombier 9487dd7cddfSDavid du Colombier /* all code below this line should be in the library, but is stolen from colors instead */ 9497dd7cddfSDavid du Colombier static char* 9507dd7cddfSDavid du Colombier rdenv(char *name) 9517dd7cddfSDavid du Colombier { 9527dd7cddfSDavid du Colombier char *v; 9537dd7cddfSDavid du Colombier int fd, size; 9547dd7cddfSDavid du Colombier 9557dd7cddfSDavid du Colombier fd = open(name, OREAD); 9567dd7cddfSDavid du Colombier if(fd < 0) 9577dd7cddfSDavid du Colombier return 0; 9587dd7cddfSDavid du Colombier size = seek(fd, 0, 2); 9597dd7cddfSDavid du Colombier v = malloc(size+1); 9607dd7cddfSDavid du Colombier if(v == 0){ 9617dd7cddfSDavid du Colombier fprint(2, "page: can't malloc: %r\n"); 9627dd7cddfSDavid du Colombier wexits("no mem"); 9637dd7cddfSDavid du Colombier } 9647dd7cddfSDavid du Colombier seek(fd, 0, 0); 9657dd7cddfSDavid du Colombier read(fd, v, size); 9667dd7cddfSDavid du Colombier v[size] = 0; 9677dd7cddfSDavid du Colombier close(fd); 9687dd7cddfSDavid du Colombier return v; 9697dd7cddfSDavid du Colombier } 9707dd7cddfSDavid du Colombier 9717dd7cddfSDavid du Colombier void 9727dd7cddfSDavid du Colombier newwin(void) 9737dd7cddfSDavid du Colombier { 9747dd7cddfSDavid du Colombier char *srv, *mntsrv; 9757dd7cddfSDavid du Colombier char spec[100]; 9767dd7cddfSDavid du Colombier int srvfd, cons, pid; 9777dd7cddfSDavid du Colombier 9787dd7cddfSDavid du Colombier switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ 9797dd7cddfSDavid du Colombier case -1: 9807dd7cddfSDavid du Colombier fprint(2, "page: can't fork: %r\n"); 9817dd7cddfSDavid du Colombier wexits("no fork"); 9827dd7cddfSDavid du Colombier case 0: 9837dd7cddfSDavid du Colombier break; 9847dd7cddfSDavid du Colombier default: 9857dd7cddfSDavid du Colombier wexits(0); 9867dd7cddfSDavid du Colombier } 9877dd7cddfSDavid du Colombier 9887dd7cddfSDavid du Colombier srv = rdenv("/env/wsys"); 9897dd7cddfSDavid du Colombier if(srv == 0){ 9907dd7cddfSDavid du Colombier mntsrv = rdenv("/mnt/term/env/wsys"); 9917dd7cddfSDavid du Colombier if(mntsrv == 0){ 9927dd7cddfSDavid du Colombier fprint(2, "page: can't find $wsys\n"); 9937dd7cddfSDavid du Colombier wexits("srv"); 9947dd7cddfSDavid du Colombier } 9957dd7cddfSDavid du Colombier srv = malloc(strlen(mntsrv)+10); 9967dd7cddfSDavid du Colombier sprint(srv, "/mnt/term%s", mntsrv); 9977dd7cddfSDavid du Colombier free(mntsrv); 9987dd7cddfSDavid du Colombier pid = 0; /* can't send notes to remote processes! */ 9997dd7cddfSDavid du Colombier }else 10007dd7cddfSDavid du Colombier pid = getpid(); 10017dd7cddfSDavid du Colombier srvfd = open(srv, ORDWR); 10027dd7cddfSDavid du Colombier if(srvfd == -1){ 10037dd7cddfSDavid du Colombier fprint(2, "page: can't open %s: %r\n", srv); 10047dd7cddfSDavid du Colombier wexits("no srv"); 10057dd7cddfSDavid du Colombier } 1006fae06aafSDavid du Colombier free(srv); 10077dd7cddfSDavid du Colombier sprint(spec, "new -pid %d", pid); 10089a747e4fSDavid du Colombier if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){ 10097dd7cddfSDavid du Colombier fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec); 10107dd7cddfSDavid du Colombier wexits("no mount"); 10117dd7cddfSDavid du Colombier } 10127dd7cddfSDavid du Colombier close(srvfd); 10137dd7cddfSDavid du Colombier unmount("/mnt/acme", "/dev"); 10147dd7cddfSDavid du Colombier bind("/mnt/wsys", "/dev", MBEFORE); 10157dd7cddfSDavid du Colombier cons = open("/dev/cons", OREAD); 10167dd7cddfSDavid du Colombier if(cons==-1){ 10177dd7cddfSDavid du Colombier NoCons: 10187dd7cddfSDavid du Colombier fprint(2, "page: can't open /dev/cons: %r"); 10197dd7cddfSDavid du Colombier wexits("no cons"); 10207dd7cddfSDavid du Colombier } 10217dd7cddfSDavid du Colombier dup(cons, 0); 10227dd7cddfSDavid du Colombier close(cons); 10237dd7cddfSDavid du Colombier cons = open("/dev/cons", OWRITE); 10247dd7cddfSDavid du Colombier if(cons==-1) 10257dd7cddfSDavid du Colombier goto NoCons; 10267dd7cddfSDavid du Colombier dup(cons, 1); 10277dd7cddfSDavid du Colombier dup(cons, 2); 10287dd7cddfSDavid du Colombier close(cons); 10297dd7cddfSDavid du Colombier // wctlfd = open("/dev/wctl", OWRITE); 10307dd7cddfSDavid du Colombier } 10317dd7cddfSDavid du Colombier 10327dd7cddfSDavid du Colombier Rectangle 10337dd7cddfSDavid du Colombier screenrect(void) 10347dd7cddfSDavid du Colombier { 10357dd7cddfSDavid du Colombier int fd; 10367dd7cddfSDavid du Colombier char buf[12*5]; 10377dd7cddfSDavid du Colombier 10387dd7cddfSDavid du Colombier fd = open("/dev/screen", OREAD); 10397dd7cddfSDavid du Colombier if(fd == -1) 10407dd7cddfSDavid du Colombier fd=open("/mnt/term/dev/screen", OREAD); 10417dd7cddfSDavid du Colombier if(fd == -1){ 10427dd7cddfSDavid du Colombier fprint(2, "page: can't open /dev/screen: %r\n"); 10437dd7cddfSDavid du Colombier wexits("window read"); 10447dd7cddfSDavid du Colombier } 10457dd7cddfSDavid du Colombier if(read(fd, buf, sizeof buf) != sizeof buf){ 10467dd7cddfSDavid du Colombier fprint(2, "page: can't read /dev/screen: %r\n"); 10477dd7cddfSDavid du Colombier wexits("screen read"); 10487dd7cddfSDavid du Colombier } 10497dd7cddfSDavid du Colombier close(fd); 10507dd7cddfSDavid du Colombier return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); 10517dd7cddfSDavid du Colombier } 10527dd7cddfSDavid du Colombier 10537def40e1SDavid du Colombier void 10547def40e1SDavid du Colombier zerox(void) 10557def40e1SDavid du Colombier { 10567def40e1SDavid du Colombier int pfd[2]; 10577def40e1SDavid du Colombier 10587def40e1SDavid du Colombier pipe(pfd); 10597def40e1SDavid du Colombier switch(rfork(RFFDG|RFREND|RFPROC)) { 10607def40e1SDavid du Colombier case -1: 10617def40e1SDavid du Colombier wexits("cannot fork in zerox: %r"); 10627def40e1SDavid du Colombier case 0: 10637def40e1SDavid du Colombier dup(pfd[1], 0); 10647def40e1SDavid du Colombier close(pfd[0]); 1065f19e7b74SDavid du Colombier execl("/bin/page", "page", "-w", nil); 10667def40e1SDavid du Colombier wexits("cannot exec in zerox: %r\n"); 10677def40e1SDavid du Colombier default: 10687def40e1SDavid du Colombier close(pfd[1]); 10697def40e1SDavid du Colombier writeimage(pfd[0], im, 0); 10707def40e1SDavid du Colombier close(pfd[0]); 10717def40e1SDavid du Colombier break; 10727def40e1SDavid du Colombier } 10737def40e1SDavid du Colombier } 1074