/* * This program is Copyright (C) 1987 by the Board of Trustees of the * University of Illinois, and by the author Dirk Grunwald. * * This program may be freely copied, as long as this copyright * message remaines affixed. It may not be sold, altough it may * be distributed with other software which is sold. If the * software is distributed, the source code must be made available. * * No warrenty, expressed or implied, is given with this software. * It is presented in the hope that it will prove useful. */ #include #include #include #include #include #include #include "dvistuff.h" /* * These constants may need to be changed on your implementation */ #define BitsPerByte 8 #define BitsPerShort 16 #define BytesPerShort (sizeof(short)) #define BitsPerByteMask 0x7 #define BitsPerByteShift 3 #define BytesPerShot 2 /* * Note that ROUNDUP evaluates Y twice. */ #define ROUNDUP(x,y) (((x)+(y)-1) / (y)) int debug = 0; static int obscured = 1; /* * X-11 related variables */ Display *DISP; static Window win; static int backpix; static GC highpix, forepix; static GC specialGC; static int defaultScreen; static Cursor workingCursor; static Cursor readyCursor; /* * TeX-Dvi related variables */ static int rawDviHeight; static int rawDviWidth; /* part of X interface, not dvistuff */ static int maxHeight; static int maxWidth; static int screenWidth, screenHeight; #define MAX_LEAVES 2 #define LEAF_LEFT 0 #define LEAF_RIGHT 1 static int Leaves; static int currentLeaf = 0; static int pageOnLeaf[MAX_LEAVES] = {-1,-1}; static int haveLargePage[MAX_LEAVES] = {-1, -1}; #define SHRINK_NORMAL 0 #define SHRINK_LARGE 1 #define MAX_SHRINKS 2 static int page_w[MAX_SHRINKS], page_h[MAX_SHRINKS]; static int leaf_w[MAX_SHRINKS]; static int shrinkFactor[MAX_SHRINKS]; static int currentShrink; static struct glyph **shrunkenGlyphs[MAX_SHRINKS][MAX_FONTFAMILY]; static XImage **shrunkenImages[MAX_SHRINKS][MAX_FONTFAMILY]; static int reverse = 0; static double specialConv; char *malloc(), *calloc(), *index(); #define MAX(a,b) ((a) < (b)) ? (b) : (a) #define MIN(a,b) ((a) < (b)) ? (a) : (b) /* * I don't know why this is needed, but our sun seems to thing * and is or & vice versa */ #ifdef mc68000 #define GXAND GXand #define GXOR GXor #else #define GXAND GXor #define GXOR GXand #endif main(argc, argv) int argc; char **argv; { int xargc=argc; char **xargv=argv; char *file; char *display = NULL; char *option; int bwidth = 2; char *fore_color; char *back_color; char *high_color; char *brdr_color; char *mous_color; char *geometry = NULL, def[32]; int bdrpix, mouspix; XColor cdef; XSizeHints hints; XSetWindowAttributes xswattrs; unsigned long xswattrs_mask; double atof(); char *getenv(); ProgName = *argv; argv++; argc--; if ((DISP = XOpenDisplay(display)) == NULL) { fprintf(stderr, "[%s] Can't open display '%s'\n", ProgName, XDisplayName(display)); exit(1); } if ((option = XGetDefault(DISP, ProgName, "ReverseVideo")) && strcmp(option, "on") == 0) reverse = 1; if (option = XGetDefault(DISP, ProgName, "BorderWidth")) bwidth = atoi(option); fore_color = XGetDefault(DISP, ProgName, "ForeGround"); back_color = XGetDefault(DISP, ProgName, "BackGround"); high_color = XGetDefault(DISP, ProgName, "Highlight"); brdr_color = XGetDefault(DISP, ProgName, "Border"); mous_color = XGetDefault(DISP, ProgName, "Mouse"); option = XGetDefault(DISP, ProgName, "NormalShrink"); shrinkFactor[SHRINK_NORMAL] = (option == 0) ? 0 : atoi(option); option = XGetDefault(DISP, ProgName, "LargeShrink"); shrinkFactor[SHRINK_LARGE] = (option == 0) ? 0 : atoi(option); option = XGetDefault(DISP, ProgName, "Blackness"); dviBlackness = (option == 0) ? DEFAULT_BLACKNESS : atoi(option); option = XGetDefault(DISP, ProgName, "Leaves"); Leaves = (option == 0) ? 0 : atoi(option); option = XGetDefault(DISP, ProgName, "Dpi"); dviDPI = (option == 0) ? DEFAULT_DPI : atoi(option); option = XGetDefault(DISP, ProgName, "TopMargin"); dviVVMargin = (option == 0) ? DEFAULT_VVMARGIN : atof(option) * dviDPI; option = XGetDefault(DISP, ProgName, "SideMargin"); dviHHMargin = (option == 0) ? DEFAULT_HHMARGIN : atof(option) * dviDPI; file = NULL; while (argc) { if (strcmp(*argv, "-p") == 0 && argc > 1) { argv++; argc--; dviDPI = atoi(*argv); if (dviDPI <= 0) goto usage; } else if (strcmp(*argv, "-rv") == 0) { reverse = !reverse; } else if (strcmp(*argv, "-bw") == 0 && argc > 1) { argv++; argc--; bwidth = atoi(*argv); } else if (strcmp(*argv, "-fg") == 0 && argc > 1) { argv++; argc--; fore_color = *argv; } else if (strcmp(*argv, "-bg") == 0 && argc > 1) { argv++; argc--; back_color = *argv; } else if (strcmp(*argv, "-hl") == 0 && argc > 1) { argv++; argc--; high_color = *argv; } else if (strcmp(*argv, "-bd") == 0 && argc > 1) { argv++; argc--; brdr_color = *argv; } else if (strcmp(*argv, "-ms") == 0 && argc > 1) { argv++; argc--; mous_color = *argv; } else if (strcmp(*argv,"-l") == 0 && argc > 1) { argv++; argc--; Leaves = atoi(*argv); if( Leaves < 1 || Leaves > MAX_LEAVES) { fprintf(stderr,"[%s] Bad number of leaves(%d), using %d\n", ProgName, Leaves, MAX_LEAVES); Leaves = MAX_LEAVES; } } else if (strcmp(*argv,"-ns") == 0 && argc > 1) { argv++; argc--; shrinkFactor[SHRINK_NORMAL] = atoi(*argv); } else if (strcmp(*argv,"-ls") == 0 && argc > 1) { argv++; argc--; shrinkFactor[SHRINK_LARGE] = atoi(*argv); } else if (strcmp(*argv,"-bl") == 0 && argc > 1) { argv++; argc--; dviBlackness = atoi(*argv); } else if (strcmp(*argv,"-dpi") == 0 && argc > 1) { argv++; argc--; dviDPI = atoi(*argv); } else if (strcmp(*argv,"-tm") == 0 && argc > 1) { argv++; argc--; dviVVMargin = dviDPI * atof(*argv); } else if (strcmp(*argv,"-sm") == 0 && argc > 1) { argv++; argc--; dviHHMargin = dviDPI * atof(*argv); } else if (**argv == '=') { geometry = *argv; } else if (**argv != '-') { if (index(*argv, ':') != NULL) display = *argv; else file = *argv; } else { usage: fprintf(stderr, "Usage: %s [-s ] [-l ] [-rv] [-fg ] [-bg ] [-hl ] [-bd ] [-ms ] [=] [host:display] dviFile\n", ProgName); exit(1); } argv++; argc--; } if (file == NULL) goto usage; if ((dviFile = fopen(file, "r")) == NULL) { int n = strlen(file); char *dvi_name; if (strcmp(file + n - sizeof(".dvi") + 1, ".dvi") == 0) { perror(file); exit(1); } dvi_name = malloc((unsigned) n + sizeof(".dvi")); sprintf(dvi_name, "%s.dvi", file); if ((dviFile = fopen(dvi_name, "r")) == NULL) { perror(dvi_name); exit(1); } } dviInit(); specialConv = (float) dviDPI / 1000.0; /* * If no shrink factor was chosen, pick one which will work out nicely * on their display */ defaultScreen = XDefaultScreen(DISP); maxHeight = XDisplayHeight(DISP, defaultScreen) - 2 * bwidth; maxWidth = XDisplayWidth(DISP, defaultScreen) - 2 * bwidth; rawDviHeight = dviTallestPage + 2 * dviVVMargin; rawDviWidth = dviWidestPage + 2 * dviHHMargin; if (Leaves == 0) { if (dviTotalPages == 1) { Leaves = 1; } else { Leaves = 2; } } if (shrinkFactor[SHRINK_NORMAL] == 0) { int sH; int sW; int sH2; int sW2; int shrink2; sH = (rawDviHeight + maxHeight - 1) / maxHeight; sW = (Leaves * rawDviWidth + maxWidth - 1) / maxWidth; shrinkFactor[SHRINK_NORMAL] = MAX(sW, sH); shrinkFactor[SHRINK_NORMAL] = MAX(shrinkFactor[SHRINK_NORMAL], 1); /* * Check to see if we can get another shrink size bigger display * if we cut the margins. */ sH2 = (dviTallestPage + (dviHHMargin/32) + maxHeight - 1) / maxHeight; sW2 = ( Leaves * (dviWidestPage + (dviVVMargin/32)) + maxHeight - 1) / maxHeight; shrink2 = MAX(sH2, sW2); shrink2 = MAX(shrink2, 1); if (shrink2 < shrinkFactor[SHRINK_NORMAL]) { dviVVMargin /= 32; dviHHMargin /= 32; rawDviHeight = dviTallestPage + 2 * dviVVMargin; rawDviWidth = dviWidestPage + 2 * dviHHMargin; shrinkFactor[SHRINK_NORMAL] = shrink2; } } page_h[SHRINK_NORMAL]=(rawDviHeight + shrinkFactor[SHRINK_NORMAL] - 1) / shrinkFactor[SHRINK_NORMAL]; leaf_w[SHRINK_NORMAL]=(rawDviWidth + shrinkFactor[SHRINK_NORMAL] - 1) / shrinkFactor[SHRINK_NORMAL]; /* * Based on the shrink factor, choose a shrink factor for the enlarged * display */ if (shrinkFactor[SHRINK_LARGE] == 0) { shrinkFactor[SHRINK_LARGE] = shrinkFactor[SHRINK_NORMAL] / 2; } shrinkFactor[SHRINK_LARGE] = MIN(shrinkFactor[SHRINK_LARGE], shrinkFactor[SHRINK_NORMAL]-1); shrinkFactor[SHRINK_LARGE] = MAX(shrinkFactor[SHRINK_LARGE], 1); page_h[SHRINK_LARGE]=(rawDviHeight + shrinkFactor[SHRINK_LARGE] - 1) / shrinkFactor[SHRINK_LARGE]; leaf_w[SHRINK_LARGE]=(rawDviWidth + shrinkFactor[SHRINK_LARGE] - 1) / shrinkFactor[SHRINK_LARGE]; /* * Compute the page size given the number of leaves. We may have * to scale back if everything can't fit. */ if (leaf_w[SHRINK_NORMAL] * Leaves <= maxWidth) { page_w[SHRINK_NORMAL] = leaf_w[SHRINK_NORMAL] * Leaves; } else { page_w[SHRINK_NORMAL] = leaf_w[SHRINK_NORMAL]; Leaves = 1; } screenWidth = (page_w[SHRINK_NORMAL] > maxWidth) ? maxWidth : page_w[SHRINK_NORMAL]; screenHeight = (page_h[SHRINK_NORMAL] > maxHeight) ? maxHeight : page_h[SHRINK_NORMAL]; highpix = XCreateGC(DISP, RootWindow(DISP, defaultScreen), 0, NULL); forepix = XCreateGC(DISP, RootWindow(DISP, defaultScreen), 0, NULL); XCopyGC(DISP, DefaultGC(DISP, 0), (1L<<(GCLastBit+1))-1, highpix); XCopyGC(DISP, highpix, (1L<<(GCLastBit+1))-1, forepix); if (reverse) { XSetForeground(DISP, forepix, WhitePixel(DISP, defaultScreen)); XSetForeground(DISP, highpix, WhitePixel(DISP, defaultScreen)); backpix = BlackPixel(DISP, defaultScreen); bdrpix = WhitePixel(DISP, defaultScreen); mouspix = WhitePixel(DISP, defaultScreen); XSetFunction(DISP, forepix, GXAND); /* or */ XSetFunction(DISP, highpix, GXAND); } else { XSetForeground(DISP, forepix, BlackPixel(DISP, defaultScreen)); XSetForeground(DISP, highpix, BlackPixel(DISP, defaultScreen)); backpix = WhitePixel(DISP, defaultScreen); bdrpix = BlackPixel(DISP, defaultScreen); mouspix = BlackPixel(DISP, defaultScreen); XSetFunction(DISP, forepix, GXOR); /* and */ XSetFunction(DISP, highpix, GXOR); } if (DisplayCells(DISP, 0) > 2) { Colormap dcm = DefaultColormap(DISP, defaultScreen); if (fore_color && XParseColor(DISP, dcm, fore_color, &cdef) && XAllocColor(DISP, dcm, &cdef)) { XSetForeground(DISP, forepix, cdef.pixel); } if (back_color && XParseColor(DISP, dcm, back_color, &cdef) && XAllocColor(DISP, dcm, &cdef)) { backpix = cdef.pixel; } if (high_color && XParseColor(DISP, dcm, high_color, &cdef) && XAllocColor(DISP, dcm, &cdef)) { XSetForeground(DISP, highpix, cdef.pixel); } if (brdr_color && XParseColor(DISP, dcm, brdr_color, &cdef) && XAllocColor(DISP, dcm, &cdef)) { /* null statement? */ } if (mous_color && XParseColor(DISP, dcm, mous_color, &cdef) && XAllocColor(DISP, dcm, &cdef)) { mouspix = cdef.pixel; } } XSetBackground(DISP, forepix, backpix); XSetBackground(DISP, highpix, backpix); sprintf(def, "=%dx%d+0+0", screenWidth, screenHeight); hints.width = page_w[SHRINK_NORMAL]; hints.height = page_h[SHRINK_NORMAL]; hints.x = 0; hints.y = 0; hints.flags = (PSize | PPosition); xswattrs.border_pixel = bdrpix; xswattrs.background_pixel = backpix; xswattrs_mask = (CWBackPixel|CWBorderPixel); win = XCreateWindow(DISP, RootWindow(DISP, defaultScreen), 0, 0, screenWidth, screenHeight, bdrpix, 0, /* depth from parent */ InputOutput, CopyFromParent, xswattrs_mask, &xswattrs); XSetStandardProperties(DISP, win, ProgName, "DVI Previewer", None, argv, argc, &hints); XMapRaised(DISP, win); XSelectInput(DISP, win, KeyPressMask|ButtonPressMask | ButtonReleaseMask |ExposureMask | VisibilityChangeMask); workingCursor = XCreateFontCursor(DISP, XC_watch); readyCursor = XCreateFontCursor(DISP, XC_spraycan); XDefineCursor(DISP, win, workingCursor); XFlush(DISP); specialGC = XCreateGC(DISP, RootWindow(DISP, defaultScreen), 0, NULL); XCopyGC(DISP, forepix, (1L<<(GCLastBit+1))-1, specialGC); mainLoop(); stop_output(0); } /* * Pixmap manipulation routines */ static Pixmap pasteUpPixmap[MAX_SHRINKS][MAX_LEAVES]; static GC pasteFillGC; static GC pasteCopyGC; static int largePixmapsAllocated = 0; /* * Ideally, we'd like to paint up a local pixmap & then transmit the * entire pixmap. However, it looks like pixmaps require interaction * with the server. * * So, if the entire page fits on the screen, we'll paint the screen * and when we're done, we'll copy the screen to the pixmap. This * gives the illusion of progress, but allows us to do fast re-paints. * * If we're *not* on the display, we'll just draw to the pixmap and * update it at the end */ static int buildToPixmap = 1; static void clearPixmap(leaf, shrinkSize) int leaf; int shrinkSize; { if (leaf< 0 || leaf >= Leaves) { fprintf(stderr,"[%s] Reference to bogus leaf in clearPixmap: %d\n", ProgName, leaf); exit(1); } if (shrinkSize < 0 || shrinkSize >= MAX_SHRINKS ) { fprintf(stderr,"[%s] reference to bogus shrink %d\n", ProgName, shrinkSize); exit(1); } XFillRectangle(DISP, pasteUpPixmap[shrinkSize][leaf], pasteFillGC, 0, 0, leaf_w[shrinkSize], page_h[shrinkSize]); } static void clearWindow(leaf) int leaf; { XFillRectangle(DISP, win, pasteFillGC, leaf * leaf_w[SHRINK_NORMAL], 0, leaf_w[SHRINK_NORMAL], page_h[SHRINK_NORMAL]); } allocatePixmaps() { int i; for (i = 0; i < Leaves; i++ ) { pasteUpPixmap[SHRINK_NORMAL][i] = XCreatePixmap(DISP, win, leaf_w[SHRINK_NORMAL], page_h[SHRINK_NORMAL], 1); if (pasteUpPixmap[SHRINK_NORMAL][i] == 0) { fprintf(stderr,"[%s] erp! out of PIXMAP memory!\n", ProgName); exit(1); } } largePixmapsAllocated = 0; if (pasteFillGC == 0) { pasteFillGC = XCreateGC(DISP, RootWindow(DISP, defaultScreen),0,NULL); pasteCopyGC = XCreateGC(DISP, RootWindow(DISP, defaultScreen),0,NULL); XCopyGC(DISP, forepix, (1L<<(GCLastBit+1))-1, pasteFillGC); XCopyGC(DISP, forepix, (1L<<(GCLastBit+1))-1, pasteCopyGC); if (reverse) { XSetForeground(DISP, pasteFillGC, BlackPixel(DISP, defaultScreen)); } else { XSetForeground(DISP, pasteFillGC, WhitePixel(DISP, defaultScreen)); } XSetFunction(DISP, pasteFillGC, GXcopy); XSetFunction(DISP, pasteCopyGC, GXcopy); } /* * Clear the pixmap */ for (i = 0; i < Leaves; i++) { clearPixmap(i, SHRINK_NORMAL); } } allocateLargePixmaps() { int i; for (i = 0; i < Leaves; i++) { pasteUpPixmap[SHRINK_LARGE][i] = XCreatePixmap(DISP, win, leaf_w[SHRINK_LARGE], page_h[SHRINK_LARGE], 1); clearPixmap(i, SHRINK_LARGE); } largePixmapsAllocated = 1; } /* * display the normal sized leaf */ static void displayLeaves() { int leaf; XClearWindow(DISP,win); for (leaf = 0; leaf < Leaves; leaf++) { XCopyArea(DISP, pasteUpPixmap[SHRINK_NORMAL][leaf], win, forepix, 0, 0, leaf_w[SHRINK_NORMAL], page_h[SHRINK_NORMAL], leaf_w[SHRINK_NORMAL] * leaf, 0); } } static void displayLeaf(leaf) int leaf; { clearWindow(leaf); XCopyArea(DISP, pasteUpPixmap[SHRINK_NORMAL][leaf], win, forepix, 0, 0, leaf_w[SHRINK_NORMAL], page_h[SHRINK_NORMAL], leaf_w[SHRINK_NORMAL] * leaf, 0); } static void swapLeaf(from, to) int from; int to; { Pixmap tempPix; int tempNum; if (to < 0 || to >= Leaves) { fprintf(stderr,"[%s] bogus to leaf %d in swapLeaf\n", ProgName, to); exit(1); } if (from < 0 || from >= Leaves) { fprintf(stderr,"[%s] bogus from leaf %d in swapLeaf\n", ProgName, from); exit(1); } tempPix = pasteUpPixmap[SHRINK_NORMAL][to]; pasteUpPixmap[SHRINK_NORMAL][to] = pasteUpPixmap[SHRINK_NORMAL][from]; pasteUpPixmap[SHRINK_NORMAL][from] = tempPix; tempPix = pasteUpPixmap[SHRINK_LARGE][to]; pasteUpPixmap[SHRINK_LARGE][to] = pasteUpPixmap[SHRINK_LARGE][from]; pasteUpPixmap[SHRINK_LARGE][from] = tempPix; tempNum = pageOnLeaf[to]; pageOnLeaf[to] = pageOnLeaf[from]; pageOnLeaf[from] = tempNum; tempNum = haveLargePage[to]; haveLargePage[to] = haveLargePage[from]; haveLargePage[from] = tempNum; } static void buildLeaf(leaf, page, shrinkSize) int leaf; int page; int shrinkSize; { XDefineCursor(DISP, win, workingCursor); if (leaf < 0 || leaf >= Leaves) { fprintf(stderr,"[%s] bogus leaf %d in buildLeaf\n", ProgName, leaf); exit(1); } if (shrinkSize < 0 || shrinkSize >= MAX_SHRINKS ) { fprintf(stderr,"[%s] Bogus shrink size %d in buildLeaf\n", ProgName, shrinkSize); exit(1); } if (shrinkSize == SHRINK_LARGE && !largePixmapsAllocated) { allocateLargePixmaps(); } /* * If this is a normal size page, kill the information * for the large version. */ if (shrinkSize == SHRINK_NORMAL) { haveLargePage[leaf] = -1; } /* * Determine if this is a valid page. If it's not, we'll just clear * the particular leaf. */ if (page < 0 || page >= dviTotalPages) { clearPixmap(leaf, shrinkSize); if (shrinkSize == SHRINK_NORMAL) { clearWindow(leaf); } } else { if (obscured || shrinkSize == SHRINK_LARGE) { buildToPixmap = 1; } else { buildToPixmap = 0; } if (buildToPixmap) { clearPixmap(leaf, shrinkSize); } else { clearPixmap(leaf, shrinkSize); if (shrinkSize == SHRINK_NORMAL) { clearWindow(leaf); } } /* * Note that dviPreparePage may change dviCurrentPage */ currentLeaf = leaf; currentShrink = shrinkSize; dviPreparePage(page); page = dviCurrentPage; /* * Save the constructed page if we were painting it to the screen */ put_border(0, 0, leaf_w[currentShrink], page_h[currentShrink], 1); if (! buildToPixmap && shrinkSize == SHRINK_NORMAL) { XCopyArea(DISP, win, pasteUpPixmap[SHRINK_NORMAL][leaf], forepix, leaf * leaf_w[currentShrink], 0, screenWidth, screenHeight, 0,0); } else if (shrinkSize == SHRINK_NORMAL) { displayLeaf(leaf); } } pageOnLeaf[leaf] = dviCurrentPage; XDefineCursor(DISP, win, readyCursor); XFlush(DISP); } /* * interfaces to dvistuff */ /* * Whenever a new font is registers, we create a shrunken Glyph * table for it. However, we don't shrink the glyphs -- that's * done on the fly by the putChar routine. */ DviFont * applicationNewFont(f, key) struct font *f; int key; { int shrink; if (key < 0 || key > MAX_FONTFAMILY) { fprintf(stderr,"[%s] bogus key in Newfont = %d\n", ProgName, key); exit(1); } for (shrink = SHRINK_NORMAL; shrink <= SHRINK_LARGE; shrink++) { if (shrunkenGlyphs[shrink][key] == 0) { int lth = sizeof(struct glyph *) * MAX_GLYPH; struct glyph **g; g = (struct glyph **) malloc( lth ); bzero(g, lth); shrunkenGlyphs[shrink][key] = g; } if (shrunkenImages[shrink][key] == 0) { int lth = sizeof(XImage *) * MAX_GLYPH; XImage **image; image = (XImage **) malloc(lth); bzero(image, lth); shrunkenImages[shrink][key] = image; } } return(f); } /* * When we reset a font, we only need to free the storage for the * shrunken glyphs. We keep the glyph table available because we're * very likely to fill it in again. */ void applicationResetFont(fi, key) struct fontinfo *fi; int key; { int i; struct glyph **theseGlyphs; XImage **theseImages; int shrink; for (shrink = SHRINK_NORMAL; shrink <= SHRINK_LARGE; shrink++) { theseGlyphs = shrunkenGlyphs[shrink][key]; if (theseGlyphs != 0) { for (i = 0; i < MAX_GLYPH; i++) { struct glyph *g; g = theseGlyphs[i]; if (g != 0) { if ( g -> g_raster != 0) { free(g -> g_raster); } free(g); theseGlyphs[i] = 0; } } } theseImages = shrunkenImages[shrink][key]; if (theseImages != 0) { for (i = 0; i < MAX_GLYPH; i++) { if (theseImages[i] != 0) { XDestroyImage(theseImages[i]); } theseImages[i] = 0; } } } } void applicationPutChar(hh, vv, charCode) int hh; int vv; int charCode; { register struct glyph *g; int x,y; XImage *image; int key; key = dviCurrentFont -> family; g = shrunkenGlyphs[currentShrink][key][charCode]; if (g == 0) { g = dviShrinkGlyph(dviCurrentFont -> f -> f_gly[charCode], shrinkFactor[currentShrink], shrinkFactor[currentShrink]); shrunkenGlyphs[currentShrink][key][charCode] = g; } if (g == 0 || !HASRASTER(g)) return; hh /= shrinkFactor[currentShrink]; vv /= shrinkFactor[currentShrink]; x = hh - g -> g_xorigin; y = vv - g -> g_yorigin; image = shrunkenImages[currentShrink][key][charCode]; if (image == 0 ) { image = XCreateImage(DISP, DefaultVisual(DISP, defaultScreen), 1, XYBitmap, 0, g->g_raster, g->g_width, g->g_height, 16, 0); shrunkenImages[currentShrink][key][charCode] = image; } if (buildToPixmap) { XPutImage(DISP, pasteUpPixmap[currentShrink][currentLeaf], forepix, image, 0, 0, x, y, g->g_width, g->g_height); } else { XPutImage(DISP, win, forepix, image, 0, 0, x + currentLeaf * leaf_w[currentShrink], y, g->g_width, g->g_height); } } void applicationSetRule(hh, vv, h, w) int hh, vv; int h, w; { /* (w,h) specifies lower left corner of rule box */ int nh, nw; hh /= shrinkFactor[currentShrink]; vv /= shrinkFactor[currentShrink]; nh = h / shrinkFactor[currentShrink]; nw = w / shrinkFactor[currentShrink]; if (nh == 0 && h != 0) { nh = 1; } if (nw == 0 && w != 0) { nw = 1 ; } put_rectangle(hh, vv - nh, nw, nh, forepix); } /* * This code attempts to support the same set of specials * as imagen1 */ static char * skipWhite(c) char *c; { while (c != 0 && *c != 0 && isspace(*c)) c++; return(c); } static char * skipNonWhite(c) char *c; { while (c != 0 && *c != 0 && ! isspace(*c)) c++; return(c); } #define MAX_POINTS 128 static int pointListCount = 0; static XPoint pointList[MAX_POINTS]; void applicationDoSpecial(command) char *command; { char com[20]; int x,y; char *c, *oc; c = skipWhite(command); if (*c == 0) return; oc = c; c = skipNonWhite(c); x = *c; *c = '\000'; strncpy(com, oc, 20); *c = x; c++; if (strcmp(com, "pa") == 0) { sscanf(c, " %d %d ", &x, &y); pointList[pointListCount].x = (specialConv * x + dviHH) / shrinkFactor[currentShrink]; pointList[pointListCount].y = (specialConv * y + dviVV) / shrinkFactor[currentShrink]; if (! buildToPixmap) { pointList[pointListCount].x += currentLeaf * leaf_w[currentShrink]; } pointListCount++; /* * Make all lines styles come out as a simple line. * Crude, but effective. */ } else if (strcmp(com, "fp") == 0 || strcmp(com,"da") == 0 || strcmp(com,"dt") == 0) { if (pointListCount > 0) { if (buildToPixmap) { XDrawLines(DISP, pasteUpPixmap[currentShrink][currentLeaf], specialGC, pointList, pointListCount, CoordModeOrigin); } else { XDrawLines(DISP, win, specialGC, pointList, pointListCount, CoordModeOrigin); } } pointListCount = 0; } else if (strcmp(com, "pn") == 0) { int penSize; sscanf(c," %d ", &penSize); penSize /= (shrinkFactor[currentShrink] * 2); /* looks good */ penSize = MAX(penSize,1); penSize = MIN(penSize,99); XSetLineAttributes(DISP, specialGC, penSize, LineSolid, CapButt, JoinMiter); } else { /* * For now, lets just flush the special */ fprintf(stderr, "[%s] special \"%s\" not implemented\n", ProgName, command); } } int mainLoop() { int ch, arg, sign, number; XEvent event; XWindowAttributes query; char trbuf[100]; char *string; int nbytes=0; int repaint; int rebuild; #define BOGUSDIR -1 #define FOREWARD 0 #define BACKWARD 1 #define ABSOLUTE 2 int direction; /* * * We need to initialized 'obscured'. * Ideally, we would like to know if we are covered at all, but * the best I can come up with is a way to determine if we're * mapped. This works well for wm, uwm & no window manager at all. */ XClearWindow(DISP,win); XSync(DISP, 0); XGetWindowAttributes(DISP, win, &query); obscured = ! (query.map_state == IsViewable); allocatePixmaps(); dviCurrentPage = 0; buildLeaf(LEAF_LEFT, 0, SHRINK_NORMAL); if (Leaves == 2) { XGetWindowAttributes(DISP, win, &query); /* status changed? */ obscured = ! (query.map_state == IsViewable); buildLeaf(LEAF_RIGHT, 1, SHRINK_NORMAL); } arg = 0; number = 0; for (;;) { repaint = 1; rebuild = 0; direction = BOGUSDIR; XDefineCursor(DISP, win, readyCursor); bzero(&event, sizeof(event)); XNextEvent (DISP, &event); string = ""; switch (event.type) { /* * If were painting to the display, and were not completely * visible, wed better really paint to the pixmap, otherwise, * all the stuff painted in an obscured region wont be in the pixmap. */ case VisibilityNotify: obscured = (event.xvisibility.state != VisibilityUnobscured); continue; case Expose: string = "\f"; nbytes = 1; break; case ButtonPress: { int leaf; int otherLeaf; int normalLeafW = leaf_w[SHRINK_NORMAL]; int leafX; int leafY; int lastLeaf = -1; int x = event.xbutton.x; int y = event.xbutton.y; int lastButton = event.xbutton.button; /* * Determine which leaf was pointed to & where we will display it */ leaf = x / normalLeafW; if (leaf < 0 || leaf >= Leaves) { fprintf(stderr,"[%s] error in button press, leaf = %d\n", ProgName, leaf); exit(1); } if (leaf != lastLeaf && lastLeaf != -1) { displayLeaf(lastLeaf); } lastLeaf = leaf; if (Leaves == 1) { otherLeaf = leaf; } else { otherLeaf = 1 - leaf; } /* * Build the enlarged page if its not already there */ if (haveLargePage[leaf] != pageOnLeaf[leaf]) { buildLeaf(leaf, pageOnLeaf[leaf], SHRINK_LARGE); haveLargePage[leaf] = pageOnLeaf[leaf]; } /* * Determine where he was looking, build a (x,y) such that * the thing he was pointing at will be on the screen, as close to * center as possible. */ leafX = (x - (leaf * normalLeafW)); leafX = (leafX * shrinkFactor[SHRINK_NORMAL]) / shrinkFactor[SHRINK_LARGE]; leafX -= (leaf_w[SHRINK_NORMAL] / 2); leafX = MAX(leafX, 0); leafX = MIN(leafX, leaf_w[SHRINK_LARGE]); leafY = (y * shrinkFactor[SHRINK_NORMAL]) / shrinkFactor[SHRINK_LARGE]; leafY -= (page_h[SHRINK_NORMAL] / 2); leafY = MAX(leafY, 0); leafY = MIN(leafY, page_h[SHRINK_LARGE]); /* * Display the enlarged image on the leaf, wait for another * button event (the release, we hope)& then restore the image as it was */ clearWindow(otherLeaf); XCopyArea(DISP, pasteUpPixmap[SHRINK_LARGE][leaf], win, forepix, leafX, leafY, leaf_w[SHRINK_NORMAL], page_h[SHRINK_NORMAL], leaf_w[SHRINK_NORMAL] * otherLeaf, 0); bzero(&event, sizeof(event)); for(;;) { XNextEvent(DISP, &event); if (event.type == ButtonRelease && event.xbutton.button == lastButton) { break; } } displayLeaf(otherLeaf); break; } case ButtonRelease: break; case KeyPress: string = trbuf; nbytes = XLookupString(&event, string, 100, NULL, NULL); break; } if (nbytes == 0) continue; if (nbytes > 1) goto bad; switch (ch = *string) { case 'q': case '\003': /* control-C */ case '\004': /* control-D */ stop_output(0); break; case 'n': case 'f': case ' ': case '\n' : case '\r' : /* scroll forward */ direction = FOREWARD; rebuild = 1; break; case 'p': case 'b': case '\b': case 0177 : /* DEL */ /* scroll backward */ direction = BACKWARD; rebuild = 1; break; case '\f': case 'r' : /* repaint current page */ repaint = 1; break; case 'g': /* go to absolute page */ direction = ABSOLUTE; /* may not be, but tough */ rebuild = 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (! arg) { arg = 1; sign = 1; number = 0; } number = 10*number + sign*(ch - '0'); repaint = 0; continue; case '-': if (! arg) { arg = 1; sign = -1; number = 0; repaint = 0; continue; } else goto bad; default: goto bad; } if (rebuild && direction != BOGUSDIR) { int newLeft; int newRight; /* * canonicalize the request. arg is always > 0, were moving in * some direction. */ if (!arg || number == 0) { number = 1; } if (number < 0) { if (direction == FOREWARD) { direction = BACKWARD; } else if (direction == BACKWARD){ direction = FOREWARD; } number = -number; } /* * Turn pages back */ if (direction == BACKWARD) { newLeft = pageOnLeaf[LEAF_LEFT] - number; } else if (direction == FOREWARD) { newLeft = pageOnLeaf[LEAF_LEFT] + number; } else { newLeft = number - 1; /* pages numbered at 0 */ } newLeft = MIN(newLeft, dviTotalPages-1); newLeft = MAX(newLeft, 0); if (Leaves == 1) { if (newLeft != pageOnLeaf[LEAF_LEFT]) { buildLeaf(LEAF_LEFT, newLeft, SHRINK_NORMAL); } } else { newRight = newLeft + 1; if (pageOnLeaf[LEAF_LEFT] != newLeft) { if (newLeft == pageOnLeaf[LEAF_RIGHT]) { swapLeaf(LEAF_RIGHT, LEAF_LEFT); displayLeaf(LEAF_LEFT); } else if (newRight == pageOnLeaf[LEAF_LEFT]) { swapLeaf(LEAF_LEFT, LEAF_RIGHT); displayLeaf(LEAF_RIGHT); } if (pageOnLeaf[LEAF_LEFT] != newLeft) { buildLeaf(LEAF_LEFT, newLeft, SHRINK_NORMAL); } if (pageOnLeaf[LEAF_RIGHT] != newRight) { buildLeaf(LEAF_RIGHT, newRight, SHRINK_NORMAL); } } } repaint = 0; rebuild = 0; arg = 0; /* * Only repaint it if we need to */ } if (repaint){ displayLeaves(); repaint = 0; } continue; bad: arg = 0; /* throw away numeric argument */ continue; } } stop_output(sig) { exit(sig); } put_border(x, y, w, h, t) int x, y, w, h, t; { put_rectangle(x, y, w, t, highpix); put_rectangle(x, y, t, h, highpix); put_rectangle(x, y + h - t, w, t, highpix); put_rectangle(x + w - t, y, t, h, highpix); } put_rectangle(x, y, w, h, pix) int x, y, w, h; GC pix; { if (buildToPixmap) { XFillRectangle(DISP, pasteUpPixmap[currentShrink][currentLeaf], pix, x, y, w, h); } else { XFillRectangle(DISP, win, pix, x + currentLeaf * leaf_w[currentShrink], y, w, h); } }