henesyinit from p9fd787fda5 years agoHistory
863 lines · 17.7 KB · C
RawDownload
/* * the actual viewer that handles screen stuff */ #include <u.h>#include <libc.h>#include <draw.h>#include <cursor.h>#include <event.h>#include <bio.h>#include <plumb.h>#include <ctype.h>#include <keyboard.h>#include "page.h" Document *doc;Image *im;int page;int upside = 0;int showbottom = 0;		/* on the next showpage, move the image so the bottom is visible. */ Rectangle ulrange;	/* the upper left corner of the image must be in this rectangle */Point ul;			/* the upper left corner of the image is at this point on the screen */ Point pclip(Point, Rectangle);Rectangle mkrange(Rectangle screenr, Rectangle imr);void redraw(Image*); Cursor reading={	{-1, -1},	{0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, 	 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0, 	 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0, 	 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, },	{0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00, 	 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0, 	 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40, 	 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, }}; Cursor query = {	{-7,-7},	{0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 	 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, 	 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, 	 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, },	{0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, 	 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, 	 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, 	 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }}; enum {	Left = 1,	Middle = 2,	Right = 4, 	RMenu = 3,}; voidunhide(void){	static int wctl = -1; 	if(wctl < 0)		wctl = open("/dev/wctl", OWRITE);	if(wctl < 0)		return; 	write(wctl, "unhide", 6);} int max(int a, int b){	return a > b ? a : b;} int min(int a, int b){	return a < b ? a : b;}  char*menugen(int n){	static char menustr[32];	char *p;	int len; 	if(n == doc->npage)		return "exit";	if(n > doc->npage)		return nil; 	if(reverse)		n = doc->npage-1-n; 	p = doc->pagename(doc, n);	len = (sizeof menustr)-2; 	if(strlen(p) > len && strrchr(p, '/'))		p = strrchr(p, '/')+1;	if(strlen(p) > len)		p = p+strlen(p)-len; 	strcpy(menustr+1, p);	if(page == n)		menustr[0] = '>';	else		menustr[0] = ' ';	return menustr;} voidshowpage(int page, Menu *m){	if(doc->fwdonly)		m->lasthit = 0;	/* this page */	else		m->lasthit = reverse ? doc->npage-1-page : page;		esetcursor(&reading);	freeimage(im);	if((page < 0 || page >= doc->npage) && !doc->fwdonly){		im = nil;		return;	}	im = doc->drawpage(doc, page);	if(im == nil) {		if(doc->fwdonly)	/* this is how we know we're out of pages */			wexits(0); 		im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack);		if(im == nil) {			fprint(2, "out of memory: %r\n");			wexits("memory");		}		string(im, ZP, display->white, ZP, display->defaultfont, "?");	}else if(resizing){		resize(Dx(im->r), Dy(im->r));	}	if(upside)		rot180(im); 	esetcursor(nil);	if(showbottom){		ul.y = screen->r.max.y - Dy(im->r);		showbottom = 0;	} 	redraw(screen);	flushimage(display, 1);} char*writebitmap(void){	char basename[64];	char name[64+30];	static char result[200];	char *p, *q;	int fd; 	if(im == nil)		return "no image"; 	memset(basename, 0, sizeof basename);	if(doc->docname)		strncpy(basename, doc->docname, sizeof(basename)-1);	else if((p = menugen(page)) && p[0] != '\0')		strncpy(basename, p+1, sizeof(basename)-1); 	if(basename[0]) {		if(q = strrchr(basename, '/'))			q++;		else			q = basename;		if(p = strchr(q, '.'))			*p = 0;				memset(name, 0, sizeof name);		snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1);		if(access(name, 0) >= 0) {			strcat(name, "XXXX");			mktemp(name);		}		if(access(name, 0) >= 0)			return "couldn't think of a name for bitmap";	} else {		strcpy(name, "bitXXXX");		mktemp(name);		if(access(name, 0) >= 0) 			return "couldn't think of a name for bitmap";	} 	if((fd = create(name, OWRITE, 0666)) < 0) {		snprint(result, sizeof result, "cannot create %s: %r", name);		return result;	} 	if(writeimage(fd, im, 0) < 0) {		snprint(result, sizeof result, "cannot writeimage: %r");		close(fd);		return result;	}	close(fd); 	snprint(result, sizeof result, "wrote %s", name);	return result;} static void translate(Point); static intshowdata(Plumbmsg *msg){	char *s; 	s = plumblookup(msg->attr, "action");	return s && strcmp(s, "showdata")==0;} voidviewer(Document *dd){	int i, fd, n, oldpage;	int nxt;	Menu menu;	Mouse m;	Event e;	Point dxy, oxy, xy0;	Rectangle r;	char *fwditems[] = { "this page", "next page", "exit", 0 };	char *s;	enum { Eplumb = 4 };	Plumbmsg *pm; 	doc = dd;    /* save global for menuhit */	ul = screen->r.min;	einit(Emouse|Ekeyboard);	if(doc->addpage != nil)		eplumb(Eplumb, "image"); 	esetcursor(&reading);	r.min = ZP; 	/*	 * im is a global pointer to the current image.	 * eventually, i think we will have a layer between	 * the display routines and the ps/pdf/whatever routines	 * to perhaps cache and handle images of different	 * sizes, etc.	 */	im = 0;	page = reverse ? doc->npage-1 : 0; 	if(doc->fwdonly) {		menu.item = fwditems;		menu.gen = 0;		menu.lasthit = 0;	} else {		menu.item = 0;		menu.gen = menugen;		menu.lasthit = 0;	} 	showpage(page, &menu);	esetcursor(nil); 	nxt = 0;	for(;;) {		/*		 * throughout, if doc->fwdonly is set, we restrict the functionality		 * a fair amount.  we don't care about doc->npage anymore, and		 * all that can be done is select the next page.		 */		switch(eread(Emouse|Ekeyboard|Eplumb, &e)){		case Ekeyboard:			if(e.kbdc <= 0xFF && isdigit(e.kbdc)) {				nxt = nxt*10+e.kbdc-'0';				break;			} else if(e.kbdc != '\n')				nxt = 0;			switch(e.kbdc) {			case 'r':	/* reverse page order */				if(doc->fwdonly)					break;				reverse = !reverse;				menu.lasthit = doc->npage-1-menu.lasthit; 				/*				 * the theory is that if we are reversing the				 * document order and are on the first or last				 * page then we're just starting and really want		 	 	 * to view the other end.  maybe the if				 * should be dropped and this should happen always.				 */				if(page == 0 || page == doc->npage-1) {					page = doc->npage-1-page;					showpage(page, &menu);				}				break;			case 'w':	/* write bitmap of current screen */				esetcursor(&reading);				s = writebitmap();				if(s)					string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP,						display->defaultfont, s);				esetcursor(nil);				flushimage(display, 1);				break;			case 'd':	/* remove image from working set */				if(doc->rmpage && page < doc->npage) {					if(doc->rmpage(doc, page) >= 0) {						if(doc->npage < 0)							wexits(0);						if(page >= doc->npage)							page = doc->npage-1;						showpage(page, &menu);					}				}				break;			case 'q':			case 0x04: /* ctrl-d */				wexits(0);			case 'u':				if(im==nil)					break;				esetcursor(&reading);				rot180(im);				esetcursor(nil);				upside = !upside;				redraw(screen);				flushimage(display, 1);				break;			case '-':			case '\b':			case Kleft:				if(page > 0 && !doc->fwdonly) {					--page;					showpage(page, &menu);				}				break;			case '\n':				if(nxt) {					nxt--;					if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly)						showpage(page=nxt, &menu);					nxt = 0;					break;				}				goto Gotonext;			case Kright:			case ' ':			Gotonext:				if(doc->npage && ++page >= doc->npage && !doc->fwdonly)					wexits(0);				showpage(page, &menu);				break; 			/*			 * The upper y coordinate of the image is at ul.y in screen->r.			 * Panning up means moving the upper left corner down.  If the			 * upper left corner is currently visible, we need to go back a page.			 */			case Kup:				if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){					if(page > 0 && !doc->fwdonly){						--page;						showbottom = 1;						showpage(page, &menu);					}				} else {					i = Dy(screen->r)/2;					if(i > 10)						i -= 10;					if(i+ul.y > screen->r.min.y)						i = screen->r.min.y - ul.y;					translate(Pt(0, i));				}				break; 			/*			 * If the lower y coordinate is on the screen, we go to the next page.			 * The lower y coordinate is at ul.y + Dy(im->r).			 */			case Kdown:				i = ul.y + Dy(im->r);				if(screen->r.min.y <= i && i <= screen->r.max.y){					ul.y = screen->r.min.y;					goto Gotonext;				} else {					i = -Dy(screen->r)/2;					if(i < -10)						i += 10;					if(i+ul.y+Dy(im->r) <= screen->r.max.y)						i = screen->r.max.y - Dy(im->r) - ul.y - 1;					translate(Pt(0, i));				}				break;			default:				esetcursor(&query);				sleep(1000);				esetcursor(nil);				break;				}			break; 		case Emouse:			m = e.mouse;			switch(m.buttons){			case Left:				oxy = m.xy;				xy0 = oxy;				do {					dxy = subpt(m.xy, oxy);					oxy = m.xy;						translate(dxy);					m = emouse();				} while(m.buttons == Left);				if(m.buttons) {					dxy = subpt(xy0, oxy);					translate(dxy);				}				break;				case Middle:				do					m = emouse();				while(m.buttons == Middle);				if(m.buttons)					break;					if(doc->npage == 0)					break; 				if(reverse)					page--;				else					page++;					if((page >= doc->npage || page < 0) && !doc->fwdonly)					return;					showpage(page, &menu);				nxt = 0;				break;				case Right:				if(doc->npage == 0)					break; 				oldpage = page;				n = emenuhit(RMenu, &m, &menu);				if(n == -1)					break;					if(doc->fwdonly) {					switch(n){					case 0:	/* this page */						break;					case 1:	/* next page */						showpage(++page, &menu);						break;					case 2:	/* exit */						return;					}					break;				}					if(n == doc->npage)					return;				else					page = reverse ? doc->npage-1-n : n;					if(oldpage != page)					showpage(page, &menu);				nxt = 0;				break;			}			break; 		case Eplumb:			pm = e.v;			if(pm->ndata <= 0){				plumbfree(pm);				break;			}			if(showdata(pm)) {				s = estrdup("/tmp/pageplumbXXXXXXX");				fd = opentemp(s);				write(fd, pm->data, pm->ndata);				/* lose fd reference on purpose; the file is open ORCLOSE */			} else if(pm->data[0] == '/') {				s = estrdup(pm->data);			} else {

Lines 1–500 of 863.