summaryrefslogtreecommitdiff
path: root/dviware/umddvi/previewers/texx.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/umddvi/previewers/texx.c')
-rw-r--r--dviware/umddvi/previewers/texx.c1382
1 files changed, 1382 insertions, 0 deletions
diff --git a/dviware/umddvi/previewers/texx.c b/dviware/umddvi/previewers/texx.c
new file mode 100644
index 0000000000..feaf524b29
--- /dev/null
+++ b/dviware/umddvi/previewers/texx.c
@@ -0,0 +1,1382 @@
+/*
+ * 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 <sys/types.h>
+#include <X/Xlib.h>
+#include <X/Xutil.h>
+#include <X/cursorfont.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#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 <shrink>] [-l <leaves>] [-rv] [-fg <color>] [-bg <color>] [-hl <color>] [-bd <color>] [-ms <color>] [=<geometry>] [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);
+ }
+}
+
+