home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / dv_x / dvix.zip / XBMDVI.C < prev   
C/C++ Source or Header  |  1992-11-01  |  29KB  |  1,045 lines

  1. /*
  2.  * DVI previewer for X11.  (X11 specific code)
  3.  *
  4.  * Eric Cooper, CMU, September 1985.
  5.  *
  6.  * Code derived from dvi-imagen.c.
  7.  *
  8.  * Modified for X.10 by Bob Scheifler, MIT LCS, January 1986.
  9.  *
  10.  * Modified for X.10.3 (Sun) by Jeff Lee, UWO CSD, February 1987.
  11.  *    -fixed bitmap manipulation to use (short*) for portability
  12.  *    -added [G] for grid and [LRUD] for 1/4 screen motion
  13.  *    -added absolute [LRUD] and relative [lrud] positioning
  14.  *     in 1/10 inch increments.
  15.  *
  16.  * Modified (again) by Jeff Lee, UWO CSD, April 1987.
  17.  *    -added an [i] command to re-init the file
  18.  *
  19.  * Modified by Jeff Lee, UofT DCS, Oct 1988.
  20.  *    - use .pxl or .pk fonts
  21.  *    - add tpic support
  22.  *    - add .XDefaults options
  23.  *    - add ``clipping'' on start-up
  24.  *
  25.  * Modified by Jeff Lee, UofT DCS, April 1989.
  26.  *    - add bitLine() to do tpic in client
  27.  *    - make backing pixmap optional
  28.  *    - added ``-nopixmap'' ``-ps'' and ``pixmapSize''
  29.  *
  30.  */
  31.  
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <X11/Xlib.h>
  35. #include <X11/Xutil.h>
  36. #include <X11/cursorfont.h>
  37. #include <stdio.h>
  38. #include <ctype.h>
  39. #include "dvi.h"
  40. #include "pxl.h"
  41. #include "general.h"
  42. #include "local.h"
  43. #include "bitorder.h"
  44.  
  45. char *getenv();
  46.  
  47. extern struct bitmap *bitCreate();
  48. extern XImage *imageFromBitMap();
  49.  
  50. struct frame {
  51.     long pxl_h, dvi_h, pxl_v, dvi_v, w, x, y, z;
  52. };
  53.  
  54. extern struct frame *stack;
  55. extern int stackp;
  56.  
  57. #define PXL_H   stack[stackp].pxl_h
  58. #define PXL_V   stack[stackp].pxl_v
  59. #define DVI_H   stack[stackp].dvi_h
  60. #define DVI_V   stack[stackp].dvi_v
  61. #define WW      stack[stackp].w
  62. #define XX      stack[stackp].x
  63. #define YY      stack[stackp].y
  64. #define ZZ      stack[stackp].z
  65.  
  66. /*
  67.  * Command line flags.
  68.  */
  69. extern int debug;
  70. extern int list_fonts;
  71. int show_grid;
  72. char *prog;
  73.  
  74. extern int pixels_per_inch;
  75. extern int shrink_factor;
  76. extern int density_factor;
  77.  
  78. extern char *dvi_filename;        /* name of user's file */
  79. static char *tmp_name="dvix_tmp.$$$";     /* mod for DV/X, MS-DOS (GBP) */
  80. extern char *tmp_dviname;        /* mod for DV/X, MS-DOS (GBP) */
  81.  
  82. extern FILE *dvi_file;            /* user's file */
  83. extern time_t best_before;              /* stale date for file */
  84.  
  85. extern struct font *current_font;    /* ptr into circular list of fonts */
  86. extern char *font_path;            /* where to find fonts */
  87.  
  88. /*
  89.  * DVI preamble and postamble information.
  90.  */
  91. extern int total_pages;
  92. extern int current_page;
  93.  
  94. /*
  95.  * Table of page offsets in DVI file, indexed by page number - 1.
  96.  * Initialized in prepare_pages().
  97.  */
  98. extern long *page_offset;
  99.  
  100. Display *dsp;
  101. Screen *scr;
  102. int screenNo;
  103. Window root;
  104. Window win;
  105. Pixmap canvas;
  106. XSizeHints hints;
  107. GC gc;
  108. GC gcc;
  109. GC gcclear;
  110. Cursor normalCursor;
  111. Cursor waitCursor;
  112. int forepix, backpix, highpix, bdrpix, mouspix;
  113. /* int bigCanvas = 8192*8192; */ /* don't use a canvas bigger than this */
  114. int bigCanvas = 1024*1024;  /*mod for DV/X, MS-DOS, (GBP) */
  115.                    /*large pixmaps cause problems for DV/X (Why...?) */
  116.                    /*bigCanvas=-1 is equivalent to -nopixmap on the cmd line*/
  117.                    /*it can be overruled with -ps xxxx */
  118.                    /*1024*1024 seems to work fine and is faster than -1*/
  119. #include "icon.bit"        /* GBP icon stuff */
  120. #include "mask.bit"        /* GBP icon stuff */
  121. Pixmap      icon_bmp, icon_mask_bmp; /* GBP icon stuff */
  122. XWMHints xwmh;              /* GBP icon stuff */
  123.  
  124. extern long win_w, win_h, page_w, page_h;
  125. extern long min_x, max_x, min_y, max_y;
  126. extern long smin_x, smax_x, smin_y, smax_y;
  127. extern int redisplay;
  128. extern int new_file;
  129.  
  130. struct bitmap *page_bm;
  131.  
  132. unsigned long num();
  133. long snum();
  134.  
  135. extern unsigned char reverse_byte[];
  136. char *index();
  137. char *rindex();
  138.  
  139. main(argc, argv)
  140.     int argc;
  141.     char **argv;
  142. {
  143.     int xargc;
  144.     char **xargv;
  145.     char *file;
  146.     char *display = NULL;
  147.     int reverse = -1;
  148.     int bwidth = -1;
  149.     char *option;
  150.     char *fore_color = (char*)0;
  151.         char *back_color = (char*)0;
  152.         char *brdr_color = (char*)0;
  153.         char *mous_color = (char*)0;
  154.         char *geometry = NULL;
  155.         int gflag;
  156.         char *clip = NULL;
  157.     int clip_w, clip_h;
  158.         int bdrpix, mouspix;
  159.         XColor cdef;
  160.         XSizeHints hints;
  161.  
  162.     /* some flags to remember what's on the command line */
  163.     int seen_pixels = 0;
  164.     int seen_shrink = 0;
  165.     int seen_density = 0;
  166.     int seen_pmsize = 0;
  167.  
  168.         /* setup a tmp file name for DV/X, MS-DOS Mod (GBP) */
  169.         /* This mod copies the dvi file to a tmp file, in the
  170.            directory pointed to by the environment variable "TMP",
  171.            and uses this until the time on the original dvi file
  172.            changes. Then the new file is copied to tmp. See generic.c
  173.            for other mods related to this fix */
  174.         tmp_dviname = getenv("TMP");
  175.         strcat(tmp_dviname,tmp_name,sizeof(tmp_name));
  176.  
  177.     /* make sure we have enough file descriptors available */
  178. /*    { int i;  for (i=3; i<_NFILE ; i++) close(i); } */
  179.  
  180.     xargc = argc; xargv = argv;
  181.     argc--;
  182.     prog = *argv++;
  183.     if (index(prog,'/')) prog = rindex(prog,'/')+1;
  184.     file = NULL;
  185.         while (argc) {
  186.         if (strcmp(*argv, "-l") == 0)
  187.             list_fonts = 1;
  188.         else if (strcmp(*argv, "-s") == 0 && argc > 1) {
  189.             argv++;
  190.             argc--;
  191.             seen_shrink++;
  192.             shrink_factor = atoi(*argv);
  193.             if (shrink_factor <= 0) goto usage;
  194.                 } else if (strcmp(*argv, "-S") == 0 && argc > 1) {
  195.                         argv++;
  196.                         argc--;
  197.             seen_density++;
  198.                         density_factor = atoi(*argv);
  199.                         if (density_factor < 0) goto usage;
  200.         } else if (strcmp(*argv, "-p") == 0 && argc > 1) {
  201.             argv++;
  202.             argc--;
  203.             seen_pixels++;
  204.             pixels_per_inch = atoi(*argv);
  205.             if (pixels_per_inch <= 0) goto usage;
  206.         } else if (strcmp(*argv, "-rv") == 0) {
  207.             reverse = 1;
  208.                 } else if (strcmp(*argv, "-fg") == 0 && argc > 1) {
  209.                         argv++;
  210.                         argc--;
  211.                         fore_color = *argv;
  212.                 } else if (strcmp(*argv, "-bg") == 0 && argc > 1) {
  213.                         argv++;
  214.                         argc--;
  215.                         back_color = *argv;
  216.                 } else if (strcmp(*argv, "-bd") == 0 && argc > 1) {
  217.                         argv++;
  218.                         argc--;
  219.                         brdr_color = *argv;
  220.                 } else if (strcmp(*argv, "-ms") == 0 && argc > 1) {
  221.                         argv++;
  222.                         argc--;
  223.                         mous_color = *argv;
  224.                 } else if (strcmp(*argv, "-clip") == 0 && argc > 1) {
  225.                         argv++;
  226.                         argc--;
  227.                         clip = *argv;
  228.                 } else if (strcmp(*argv, "-geometry") == 0 && argc > 1) {
  229.                         argv++;
  230.                         argc--;
  231.                         geometry = *argv;
  232.                 } else if (strcmp(*argv, "-display") == 0 && argc > 1) {
  233.                         argv++;
  234.                         argc--;
  235.                         display = *argv; /* already set and used */
  236.         } else if (**argv == '=') {
  237.             geometry = *argv;
  238.         } else if (strcmp(*argv, "-nopixmap") == 0) {
  239.             bigCanvas = -1;
  240.             seen_pmsize++;
  241.         } else if (strcmp(*argv, "-ps") == 0 && argc > 1) {
  242.             argv++;
  243.             argc--;
  244.             bigCanvas = atoi(*argv)*8192; /*Kbytes*/
  245.             seen_pmsize++;
  246.         } else if (strcmp(*argv, "-d") == 0) {
  247.             debug = DBG_ALL;
  248.         } else if (strncmp(*argv, "-d", 2) == 0 && argv[0][2] != '\0') {
  249.             char *cp = &argv[0][2];
  250.  
  251.             while (*cp != '\0') {
  252.                 if (isdigit(*cp)) {
  253.                     debug = strtol(cp, &cp, 10);
  254.                     fprintf(stderr, "dvix: debug = 0x%x, cp = %s\n", debug, cp);
  255.                     continue;
  256.                 } else if (*cp == 'f') {
  257.                     debug |= DBG_FONT;
  258.                 } else if (*cp == 'p') {
  259.                     debug |= DBG_PK;
  260.                 } else if (*cp == 'b') {
  261.                     debug |= DBG_BITMAP;
  262.                 } else if (*cp == 'd') {
  263.                     debug |= DBG_DVI;
  264.                 } else {
  265.                     fprintf(stderr, "dvix: Unknown debug flag `%c': must be one of f, p, b, d or a number\n", *cp);
  266.                 }
  267.                 fprintf(stderr, "dvix: debug = 0x%x, cp = %s\n", debug, cp);
  268.                 ++cp;
  269.             }
  270.         } else if (**argv != '-') {
  271.             if (index(*argv, ':') != NULL)
  272.                 display = *argv;
  273.             else
  274.                 file = *argv;
  275.         } else {
  276.             usage:
  277.                         fprintf(stderr, "\
  278. %s: Usage: dvix [-s <shrink>] [-S <density>] [-p <pixels>] [-l] [-rv]\n\
  279.        [-fg <color>] [-bg <color>] [-bd <color>] [-ms <color>]\n\
  280.        [-geometry <geometry> | =<geometry>]\n\
  281.        [-clip <geometry> | -clip off]\n\
  282.        [-display <host:display> | host:display] dvi_file\n", prog);
  283.             exit(1);
  284.         }
  285.         argv++;
  286.         argc--;
  287.     }
  288.         if (file == NULL)
  289.         goto usage;
  290.  
  291.     if ((dsp = XOpenDisplay(display)) == NULL)
  292.     {
  293.         (void) fprintf(stderr, "Can't open display %s!\n", display);
  294.         exit(1);
  295.     }
  296. /*
  297.     printf("byte order=%s\n", ImageByteOrder(dsp)==LSBFirst?"LSB":"MSB");
  298.     printf("bit order=%s\n", BitmapBitOrder(dsp)==LSBFirst?"lsb":"msb");
  299.     printf("bitmap unit=%d\n", BitmapUnit(dsp));
  300.     printf("bitmap pad=%d\n", BitmapPad(dsp));
  301. */
  302.     scr = DefaultScreenOfDisplay(dsp);
  303.     screenNo = DefaultScreen(dsp);
  304.     root = RootWindowOfScreen(scr);
  305.  
  306.     /* check for .Xdefaults */
  307.     if (reverse<0)
  308.         if ((option = XGetDefault(dsp, prog, "reverseVideo")) &&
  309.                 strcmp(option, "on") == 0)
  310.                     reverse = 1;
  311.         else reverse = 0;
  312.     if (bwidth<0)
  313.         if (option = XGetDefault(dsp, prog, "borderWidth"))
  314.                 bwidth = atoi(option);
  315.     if (!seen_density)
  316.         if (option = XGetDefault(dsp, prog, "densityFactor"))
  317.         {
  318.                 density_factor = atoi(option);
  319.         seen_density++;
  320.         }
  321.     if (!seen_shrink)
  322.         if (option = XGetDefault(dsp, prog, "shrinkFactor"))
  323.         {
  324.                 shrink_factor = atoi(option);
  325.         seen_shrink++;
  326.         }
  327.     if (!seen_pixels)
  328.         if (option = XGetDefault(dsp, prog, "pixelsPerInch"))
  329.         {
  330.                 pixels_per_inch = atoi(option);
  331.         seen_pixels++;
  332.         }
  333.     if (!seen_pmsize)
  334.         if (option = XGetDefault(dsp, prog, "pixmapSize"))
  335.         {
  336.                 bigCanvas = atoi(option)*8192;
  337.         seen_pmsize++;
  338.         }
  339.     if (bwidth<0) bwidth = 2;
  340.     if (!fore_color)
  341.             fore_color = XGetDefault(dsp, prog, "foreground");
  342.     if (!back_color)
  343.             back_color = XGetDefault(dsp, prog, "background");
  344.     if (!brdr_color)
  345.             brdr_color = XGetDefault(dsp, prog, "borderColor");
  346.     if (!mous_color)
  347.             mous_color = XGetDefault(dsp, prog, "pointerColor");
  348.     if (!clip)
  349.         clip = XGetDefault(dsp, prog, "clip");
  350.     if (!geometry)
  351.         geometry = XGetDefault(dsp, prog, "geometry");
  352.         if(!(font_path=getenv(FONTPATH)))
  353.           {
  354.             font_path=DEFAULT_FONT_PATH;
  355.           }
  356.  
  357.     /* set monochrome defaults */
  358.     if (reverse) {
  359.         forepix = WhitePixelOfScreen(scr);
  360.         backpix = BlackPixelOfScreen(scr);
  361.     } else {
  362.         forepix = BlackPixelOfScreen(scr);
  363.         backpix = WhitePixelOfScreen(scr);
  364.     }
  365.     highpix = bdrpix = mouspix = forepix;
  366.  
  367.     /* check for clipping information */
  368.     if (!clip) clip = "-0-0";
  369.     if (strcmp(clip, "on") == 0) clip = "-0-0";
  370.     clip_w = clip_h = 0;
  371.     if (strcmp(clip, "off") != 0) {
  372.         int cflags, clip_x, clip_y;
  373.         /* the smallest non-zero value takes precedence */
  374.         cflags = XParseGeometry(clip, &clip_x, &clip_y, &clip_w, &clip_h);
  375.         if (!(cflags & WidthValue)) clip_w = 0;
  376.         if (cflags & XValue) clip_x = WidthOfScreen(scr) + clip_x;
  377.         else clip_x = 0;
  378.         if (clip_x <= 0) clip_x = clip_w;
  379.         if (clip_w <= 0 || clip_x < clip_w) clip_w = clip_x;
  380.         if (clip_w < 0) clip_w = 0;
  381.         if (!(cflags & HeightValue)) clip_h = 0;
  382.         if (cflags & YValue) clip_y = HeightOfScreen(scr) + clip_y;
  383.         else clip_y = 0;
  384.         if (clip_y <= 0) clip_y = clip_h;
  385.         if (clip_h <= 0 || clip_y < clip_h) clip_h = clip_y;
  386.         if (clip_h < 0) clip_h = 0;
  387.     }
  388.  
  389. #define XPC(col, cd) XParseColor(dsp, DefaultColormapOfScreen(scr), col, cd)
  390. #define XGHC(cd) XAllocColor(dsp, DefaultColormapOfScreen(scr), cd)
  391.         if (CellsOfScreen(scr) > 2) {
  392.                 if (fore_color && XPC(fore_color, &cdef) &&
  393.                         XGHC(&cdef))
  394.                         forepix = cdef.pixel;
  395.                 if (back_color && XPC(back_color, &cdef) &&
  396.                         XGHC(&cdef)) {
  397.                         backpix = cdef.pixel;
  398.                 }
  399.                 if (brdr_color && XPC(brdr_color, &cdef) &&
  400.                         XGHC(&cdef))
  401.             bdrpix = cdef.pixel;
  402.                 if (mous_color && XPC(mous_color, &cdef) &&
  403.                         XGHC(&cdef))
  404.                         mouspix = cdef.pixel;
  405.         }
  406.  
  407.     open_dvi_file(file);
  408.     if (seen_shrink || seen_density || seen_pixels) {
  409.         init_page();
  410.         define_conv();
  411.         reset_fonts();
  412.     }
  413.         hints.x = hints.y = 0;
  414.         hints.min_width = hints.min_height = 1;
  415.         hints.width_inc = hints.height_inc = 1;
  416.         hints.width = page_w;
  417.         hints.height = page_h;
  418.         hints.flags = PResizeInc;
  419.         if (geometry) {
  420.         gflag = XParseGeometry(geometry, &hints.x, &hints.y,
  421.                                    &hints.width, &hints.height);
  422.             hints.flags |=
  423.               ((gflag&(XValue|YValue))?(USPosition):0) |
  424.                 ((gflag&(WidthValue|HeightValue))?(USSize):0);
  425.         if (gflag&XNegative) {
  426.         hints.x = WidthOfScreen(scr) - hints.x - hints.width
  427.               - 2*bwidth;
  428.         }
  429.         if (gflag&YNegative) {
  430.         hints.y = HeightOfScreen(scr) - hints.y - hints.height
  431.               - 2*bwidth;
  432.         }
  433.         }
  434.         else {
  435.             hints.flags |= PSize;
  436.         }
  437.     /* clip if required */
  438.     if (hints.height > clip_h && clip_h > 0)
  439.         hints.height = clip_h;
  440.     if (hints.width > clip_w && clip_w > 0)
  441.         hints.width = clip_w;
  442.  
  443.     win = XCreateSimpleWindow(dsp, root, hints.x, hints.y,
  444.                   hints.width, hints.height, bwidth,
  445.                   bdrpix, backpix);
  446.     if (!win) fatal("XCreateSimpleWindow failed");
  447.     XSetStandardProperties(dsp, win, prog, "DVI Previewer",
  448.                    None, xargv, xargc, &hints);
  449.  
  450.     win_h = hints.height;
  451.     win_w = hints.width;
  452.     XSelectInput(dsp, win,
  453.              KeyPressMask|ButtonPressMask|ExposureMask
  454.             |Button2MotionMask|StructureNotifyMask);
  455.     normalCursor = XCreateFontCursor(dsp, XC_crosshair);
  456.     waitCursor = XCreateFontCursor(dsp, XC_watch);
  457.     XDefineCursor(dsp, win, waitCursor);
  458.     gc = XCreateGC(dsp, win, 0, (XGCValues*)0);
  459.     XSetFunction(dsp, gc, GXcopy);
  460.     XSetForeground(dsp, gc, forepix);
  461.     XSetBackground(dsp, gc, backpix);
  462.  
  463. /* GBP mod: add icon */
  464. /* create icon bitmap */    
  465.     if ((icon_bmp=XCreateBitmapFromData(dsp,win,
  466.                                         icon_bits,
  467.                                         icon_width,
  468.                                         icon_height))==None)
  469.         printf("Error on icon creation\n");
  470.  
  471. /* create mask bitmap */
  472.     if ((icon_mask_bmp=XCreateBitmapFromData(dsp,win,
  473.                                         mask_bits,
  474.                                         mask_width,
  475.                                         mask_height))==None)
  476.         printf("Error on icon mask creation\n");
  477.  
  478. /* define the WM attributes */
  479.     xwmh.flags = IconPixmapHint |
  480.                  IconMaskHint;
  481.     xwmh.icon_pixmap = icon_bmp;
  482.     xwmh.icon_mask   = icon_mask_bmp;
  483.  
  484. /* set the Wm attribrutes */
  485.     XSetWMHints(dsp,win,&xwmh);
  486.  
  487. /*-------------------*/
  488.     
  489.     onRescale();
  490.  
  491.     page_bm = bitCreate(page_w,page_h);
  492.  
  493.     XMapWindow(dsp, win);
  494.     do_pages();
  495.     stop_output(0);
  496.     
  497. }
  498.  
  499. set_char(ch)
  500.     ubyte ch;
  501. {
  502.     register struct glyph *g;
  503.  
  504.     g = ¤t_font->glyph[ch];
  505.     if (g->bitmap.bits == NULL)
  506.         read_pxl_bitmap(ch, g);
  507.     put_bitmap(&g->bitmap, (PXL_H - g->x), (PXL_V - g->y));
  508. }
  509.  
  510. set_rule(h, w)
  511.     long h, w;
  512. {
  513.     /* (w,h) specifies lower left corner of rule box */
  514.     put_rectangle(PXL_H, PXL_V - h, w, h);
  515. }
  516.  
  517. #define check_date() \
  518.   (check_if_stale(dvi_filename,best_before) ? open_dvi_file(dvi_filename) : 0)
  519.  
  520. show_canvas(clear)
  521. {
  522.     int w, h;
  523.     w = win_w < page_w-min_x ? win_w : page_w-min_x;
  524.     h = win_h < page_h-min_y ? win_h : page_h-min_y;
  525.  
  526.     if (clear) XClearWindow(dsp, win);
  527.     if (canvas) {
  528.         XCopyPlane(dsp, canvas, win, gc, min_x, min_y, w, h, 0, 0, 1);
  529.         XFlush(dsp);
  530.     }
  531.     else
  532.         show_bitmap(page_bm, clear);
  533. }
  534.  
  535. show_page(clear)
  536. {
  537.     if (canvas) {
  538.         XPutImage(dsp, canvas, gcc, imageFromBitMap(page_bm),
  539.               0, 0, 0, 0, page_w, page_h);
  540.     }
  541.     show_canvas(clear);
  542. }
  543.  
  544. int ref_x, ref_y;    /* last pointer position for scrolling */
  545.  
  546. end_page()
  547. {
  548.     int ch, arg, sign, number, next_page;
  549.     int page_off_x, page_off_y;
  550.     XEvent event;
  551.     char *string = "";
  552.     int nbytes = 0;
  553.     int again = 0;
  554.  
  555. #ifdef lint
  556.     number = 0;
  557. #endif
  558.     if (debug) {
  559.         if (++current_page == total_pages)
  560.             exit(0);
  561.         return;
  562.     }
  563.     if (redisplay) {
  564.         smin_x = min_x;
  565.         smax_x = max_x;
  566.         smin_y = min_y;
  567.         smax_y = max_y;
  568.         redisplay = 0;
  569.     }
  570.     show_page(1);
  571.     XDefineCursor(dsp, win, normalCursor);
  572.     arg = 0;
  573.     for (;;) {
  574.         int x, y;
  575.         XNextEvent (dsp, &event);
  576.         nbytes = 1;
  577.         again = 0;
  578.         switch (event.type) {
  579.         case ConfigureNotify:
  580.             win_w = event.xconfigure.width;
  581.             win_h = event.xconfigure.height;
  582.             max_x = min_x + win_w;
  583.             max_y = min_y + win_h;
  584.             smin_x = min_x;
  585.             smax_x = max_x;
  586.             smin_y = min_y;
  587.             smax_y = max_y;
  588.             continue;
  589.         case Expose:
  590.             if (event.xexpose.count != 0) continue;
  591.             show_canvas(1);
  592.             continue;
  593.         case ButtonPress:
  594.             {
  595.             int button = event.xbutton.button;
  596.             int state = event.xbutton.state;
  597.             switch (button) {
  598.             case Button1:
  599.             if (state & ShiftMask)
  600.                 string = "l";
  601.             else
  602.                 string = "b";
  603.             break;
  604.             case Button2:
  605.             x = event.xbutton.x;
  606.             y = event.xbutton.y;
  607.             ref_x = x + min_x;
  608.             ref_y = y + min_y;
  609.             if (state & ControlMask)
  610.             {
  611.                 page_off_x = (win_w-x)*page_w/win_w - (win_w-x);
  612.                 page_off_y = (win_h-y)*page_h/win_h - (win_h-y);
  613.                 goto scroll_it;
  614.             }
  615.             if (state & ShiftMask)
  616.             {
  617.                 page_off_x = ref_x - win_w/2;
  618.                 page_off_y = ref_y - win_h/2;
  619.                 goto scroll_it;
  620.             }
  621.             continue;
  622.             case Button3:
  623.             if (state & ShiftMask)
  624.                 string = "r";
  625.             else
  626.                 string = "f";
  627.             break;
  628.             }
  629.             }
  630.             break;
  631.         case MotionNotify:
  632.             while (XCheckMaskEvent(dsp, PointerMotionMask, &event))
  633.             ;
  634.             x = event.xmotion.x;
  635.             y = event.xmotion.y;
  636.             if (event.xmotion.state & ShiftMask) continue;
  637.             else if (event.xmotion.state & ControlMask) {
  638.             /* relative scrolling */
  639.             page_off_x = (win_w-x)*page_w/win_w - (win_w-x);
  640.             page_off_y = (win_h-y)*page_h/win_h - (win_h-y);
  641.             } else {
  642.                 /* drag scrolling */
  643.                 page_off_x = ref_x - x;
  644.                 page_off_y = ref_y - y;
  645.             }
  646.           scroll_it:
  647.             if (page_off_x > page_w-win_w) page_off_x = page_w-win_w;
  648.             if (page_off_x < 0) page_off_x = 0;
  649.             if (page_off_y > page_h-win_h) page_off_y = page_h-win_h;
  650.             if (page_off_y < 0) page_off_y = 0;
  651.             if (min_y == page_off_y && min_x == page_off_x)
  652.             continue;
  653.             min_x = page_off_x;
  654.             max_x = min_x + win_w;
  655.             min_y = page_off_y;
  656.             max_y = min_y + win_h;
  657.             next_page = current_page;
  658.             show_canvas(min_x+win_w>page_w || min_y+win_h>page_h);
  659.             XSync(dsp, 0);
  660.             continue;
  661.         case KeyPress:
  662.             {
  663.             static char buf[64];
  664.             KeySym ks;
  665.             XComposeStatus xcs;
  666.             buf[ nbytes=
  667.                          XLookupString(&event.xkey,buf,63,&ks,&xcs) ] = 0;
  668.             string = buf;      /*    ^^^^^ Bug fix (GBP) */
  669.             }
  670.             break;
  671.         default:
  672.             continue;
  673.         }
  674.         if (nbytes == 0) continue;
  675.         if (nbytes > 1) goto bad;
  676.         if (!isdigit(*string)) {
  677.             new_file = 0;
  678.             check_date();
  679.         }
  680.         switch (ch = *string) {
  681.             case 'q':
  682.             case '\003':    /* control-C */
  683.             case '\004':    /* control-D */
  684.                         if (dvi_file) {
  685.                             (void) fclose(dvi_file);
  686.                             (void) remove(tmp_dviname);
  687.                         }
  688.             stop_output(0);
  689.             break;
  690.             case 'n':
  691.             case 'f':
  692.             case ' ':
  693.             /* scroll forward */
  694.             min_x = 0;
  695.             min_y = 0;
  696.             max_x = win_w;
  697.             max_y = win_h;
  698.             next_page = current_page + 1;
  699.             break;
  700.             case 'p':
  701.             case 'b':
  702.             case '\b':
  703.             /* scroll backward */
  704.             min_x = 0;
  705.             min_y = 0;
  706.             max_x = win_w;
  707.             max_y = win_h;
  708.             next_page = current_page - 1;
  709.             break;
  710.             case 'u': case 'U':
  711.             if (! arg) {
  712.                 page_off_y = min_y - win_h/(ch=='U'?4:1);
  713.             }
  714.             else {
  715.                 page_off_y = sign*pixels_per_inch*number
  716.                         /shrink_factor/10;
  717.                 if (ch=='u') page_off_y = min_y - page_off_y;
  718.                 else page_off_y = page_h - win_h
  719.                             - page_off_y;
  720.             }
  721.               check_y:
  722.             if (page_off_y >= page_h-win_h)
  723.                 page_off_y = page_h-win_h;
  724.             if (page_off_y < 0) page_off_y = 0;
  725.             if (page_off_y == min_y) goto bad;
  726.             min_y = page_off_y;
  727.             max_y = min_y + win_h;
  728.             next_page = current_page;
  729.             again=1;
  730.             break;
  731.             case 'd': case 'D':
  732.             if (! arg) {
  733.                 page_off_y = min_y + win_h/(ch=='D'?4:1);
  734.             }
  735.             else {
  736.                 page_off_y = sign*pixels_per_inch*number
  737.                         /shrink_factor/10;
  738.                 if (ch=='d') page_off_y += min_y;
  739.             }
  740.             goto check_y;
  741.             case 'l': case 'L':
  742.             if (! arg) {
  743.                 page_off_x = min_x - win_w/(ch=='L'?4:1);
  744.             }
  745.             else {
  746.                 page_off_x = sign*pixels_per_inch*number
  747.                         /shrink_factor/10;
  748.                 if (ch=='l') page_off_x = min_x - page_off_x;
  749.                 else page_off_x = page_w - win_w
  750.                              - page_off_x;
  751.             }
  752.               check_x:
  753.             if (page_off_x >= page_w-win_w)
  754.                  page_off_x = page_w-win_w;
  755.             if (page_off_x < 0)
  756.                  page_off_x = 0;
  757.             if (page_off_x == min_x) goto bad;
  758.             min_x = page_off_x;
  759.             max_x = min_x + win_w;
  760.             next_page = current_page;
  761.             again=1;
  762.             break;
  763.             case 'r': case 'R':
  764.             if (! arg) {
  765.                 page_off_x = min_x + win_w/(ch=='R'?4:1);
  766.             }
  767.             else {
  768.                 page_off_x = sign*pixels_per_inch*number
  769.                         /shrink_factor/10;
  770.                 if (ch=='r') page_off_x += min_x;
  771.             }
  772.             goto check_x;
  773.             case 's':
  774.             if (!arg) {
  775.                 int shrink = shrink_factor;
  776.                 long fac1, fac2;
  777.                 shrink_factor = 1;
  778.                 fac1 = ROUNDUP(PAPER_WIDTH, win_w);
  779.                 fac2 = ROUNDUP(PAPER_HEIGHT, win_h);
  780.                 if (fac1 < fac2)
  781.                 number = fac2;
  782.                 else
  783.                 number = fac1;
  784.                 shrink_factor = shrink;
  785.             }
  786.             if (number <= 0) goto bad;
  787.             if (number != shrink_factor) {
  788.                 page_off_x = min_x*shrink_factor/number;
  789.                 page_off_y = min_y*shrink_factor/number;
  790.                 shrink_factor = number;
  791.                 min_x = page_off_x;
  792.                 min_y = page_off_y;
  793.                 XDefineCursor(dsp, win, waitCursor);
  794.                 XFlush(dsp);
  795.                 init_page();
  796.                 define_conv();
  797.                 reset_fonts();
  798.                     if (page_bm)
  799.                     {
  800.                     if (page_bm->bits) free(page_bm->bits);
  801.                     free((char*)page_bm);
  802.                     }
  803.                     page_bm = bitCreate(page_w,page_h);
  804.                 onRescale();
  805.                 if (min_x>page_w) min_x=page_w-win_w;
  806.                 if (min_x<0) min_x=0;
  807.                 if (min_y>page_w) min_y=page_h-win_h;
  808.                 if (min_y<0) min_y=0;
  809.                 max_x = min_x + win_w;
  810.                 max_y = min_y + win_h;
  811.                 smin_x = min_x;
  812.                 smax_x = max_x;
  813.                 smin_y = min_y;
  814.                 smax_y = max_y;
  815.             }
  816.                 next_page = current_page;
  817.             if (show_grid) goto fixgrid;
  818.             break;
  819.             case '\f':
  820.             /* redisplay current page */
  821.             next_page = current_page;
  822.             again=1;
  823.             break;
  824.                     case 'S':
  825.                         if (!arg) goto bad;
  826.                         if (number < 0) goto bad;
  827.                         if (number != density_factor) {
  828.                           density_factor = number;
  829.               XDefineCursor(dsp, win, waitCursor);
  830.               XFlush(dsp);
  831.                           init_page();
  832.                           define_conv();
  833.                           reset_fonts();
  834.                         }
  835.                         /* redisplay current page */
  836.                         next_page = current_page;
  837.                         break;
  838.             case 'G':
  839.             /* grid -- toggle */
  840.             next_page = current_page;
  841.             if (show_grid) {
  842.                 show_grid = 0;
  843.                 break;
  844.             }
  845.               fixgrid:
  846.             if (shrink_factor>=8)
  847.                 show_grid = pixels_per_inch;
  848.             else if (shrink_factor>=4)
  849.                 show_grid = pixels_per_inch/2;
  850.             else if (shrink_factor>=2)
  851.                 show_grid = pixels_per_inch/5;
  852.             else
  853.                 show_grid = pixels_per_inch/10;
  854.             break;
  855.             case '\r':
  856.             case '\n':
  857.             /* go to relative page */
  858.             min_x = 0;
  859.             min_y = 0;
  860.             max_x = win_w;
  861.             max_y = win_h;
  862.             next_page = current_page + (arg ? number : 1);
  863.             break;
  864.             case 'g':
  865.             /* go to absolute page */
  866.             min_x = 0;
  867.             min_y = 0;
  868.             max_x = win_w;
  869.             max_y = win_h;
  870.             next_page = (arg ? number : total_pages) - 1;
  871.             break;
  872.             case '0': case '1': case '2': case '3': case '4':
  873.             case '5': case '6': case '7': case '8': case '9':
  874.             if (! arg) {
  875.                 arg = 1;
  876.                 sign = 1;
  877.                 number = 0;
  878.             }
  879.             number = 10*number + sign*(ch - '0');
  880.             continue;
  881.             case '-':
  882.             if (! arg) {
  883.                 arg = 1;
  884.                 sign = -1;
  885.                 number = 0;
  886.                 continue;
  887.             } else
  888.                 goto bad;
  889.             case 'i':        /* re-Initialize the Input */
  890.                    XDefineCursor(dsp, win, waitCursor);
  891.             XFlush(dsp);
  892.             open_dvi_file(dvi_filename);
  893.             break;
  894.             default:
  895.             goto bad;
  896.         }
  897.         if (0 <= next_page && next_page < total_pages) {
  898.             if (current_page == next_page && again && !new_file)
  899.             {
  900.             show_page(1);
  901.             arg = number = sign = 0;
  902.             continue;
  903.             }
  904.             current_page = next_page;
  905.             break;
  906.         }
  907.         else if (new_file) {
  908.             redisplay = 0;
  909.             break;
  910.             }
  911.     bad:
  912.         XBell(dsp, 0);
  913.         arg = 0;        /* throw away numeric argument */
  914.         continue;
  915.     }
  916.     /* make sure that the page number is still valid */
  917.     if (current_page >= total_pages) {
  918.             current_page = (total_pages>0 ? total_pages - 1 : 0);
  919.         redisplay = 0;
  920.     }
  921.     (void) fseek(dvi_file, page_offset[current_page], 0);
  922.     XDefineCursor(dsp, win, waitCursor);
  923.     XFlush(dsp);
  924. }
  925.  
  926. clear_page()
  927. {
  928.     if (canvas)
  929.         XFillRectangle(dsp, canvas, gcclear, 0, 0, page_w, page_h);
  930.     else
  931.     XClearWindow(dsp, win);
  932.     bitClear(page_bm);
  933. }
  934.  
  935. put_border(x, y, w, h, t)
  936.     long x, y, w, h, t;
  937. {
  938.     long p;
  939.  
  940.     if (show_grid>0) {
  941.         for (p=x; p<x+w*shrink_factor ; p += show_grid)
  942.         if ((p-x) % pixels_per_inch)
  943.             put_tiled(p/shrink_factor, y, 1L, h);
  944.         else {
  945.             put_rectangle(p/shrink_factor, y, 1L, h);
  946.         }
  947.         for (p=y; p<y+h*shrink_factor ; p += show_grid)
  948.         if ((p-y) % pixels_per_inch)
  949.             put_tiled(x, p/shrink_factor, w, 1L);
  950.         else {
  951.             put_rectangle(x, p/shrink_factor, w, 1L);
  952.         }
  953.     }
  954.     put_rectangle(x, y, w, t);
  955.     put_rectangle(x, y, t, h);
  956.     put_rectangle(x, y + h - t, w, t);
  957.     put_rectangle(x + w - t, y, t, h);
  958. }
  959.  
  960. put_rectangle(x, y, w, h)
  961.     long x, y, w, h;
  962. {
  963.     bitFillBox(page_bm, x, y, w?w:1, h?h:1);
  964. }
  965.  
  966. put_tiled(x, y, w, h)
  967.     long x, y, w, h;
  968. {
  969.     bitGrayBox(page_bm, x, y, w?w:1, h?h:1, 0);
  970. }
  971.  
  972. /* make sure that we have a pixmap of the right size */
  973. /* don't make a pixmap that will be too big */
  974. onRescale()
  975. {
  976.     if (canvas) XFreePixmap(dsp, canvas);
  977.     if (page_w*page_h <= bigCanvas) {
  978.         canvas = XCreatePixmap(dsp, root, page_w, page_h, 1);
  979.         if (canvas && !gcc) {
  980.         gcc = XCreateGC(dsp, canvas, 0, (XGCValues*)0);
  981.         XSetState(dsp, gcc, 1, 0, GXor, 1);
  982.         gcclear = XCreateGC(dsp, canvas, 0, (XGCValues*)0);
  983.         XSetState(dsp, gcclear, 0, 0, GXcopy, 1);
  984.         }
  985.     }
  986.     else canvas = 0;
  987. }
  988.  
  989. /* this function make an XImage structure from a BitMap; the same XImage
  990. ** structure is re-used by successive calls */
  991. XImage *
  992. imageFromBitMap(bm)
  993.     struct bitmap *bm;
  994. {
  995.     static XImage *image;
  996.     if (!image)
  997.     {
  998.     image = XCreateImage(dsp, (Visual*)0, 1, XYBitmap, 0,
  999.                  bm->bits, bm->w, bm->h, BYTESIZE, 0);
  1000.     image->byte_order = BYTEORDER;
  1001.     image->bitmap_bit_order = BITORDER;
  1002.     }
  1003.     else
  1004.     {
  1005.     /* re-use the XImage structure */
  1006.     image->data = bm->bits;
  1007.     image->width = bm->w;
  1008.     image->height = bm->h;
  1009.     image->bytes_per_line = bm->bytes_wide;
  1010.     }
  1011.     return image;
  1012. }
  1013.  
  1014. put_bitmap(bitmap, x, y)
  1015.     register struct bitmap *bitmap;
  1016.     register long x, y;
  1017. {
  1018.     bitOr(page_bm, x, y, bitmap->w, bitmap->h, bitmap, 0, 0);
  1019. }
  1020.  
  1021. show_bitmap(bitmap, clear)
  1022.     register struct bitmap *bitmap;
  1023. {
  1024.     int w, h;
  1025.     w = win_w < bitmap->w-min_x ? win_w : bitmap->w-min_x;
  1026.     h = win_h < bitmap->h-min_y ? win_h : bitmap->h-min_y;
  1027.  
  1028.     if (clear) XClearWindow(dsp, win);
  1029.     XPutImage(dsp, win, gc, imageFromBitMap(bitmap),
  1030.           min_x, min_y, 0, 0, w, h);
  1031.     XFlush(dsp);    /* get it to the window first */
  1032.     if (canvas) {
  1033.         XPutImage(dsp, canvas, gcc, imageFromBitMap(bitmap),
  1034.               0, 0, 0, 0, page_w, page_h);
  1035.         XFlush(dsp);    /* then put it to the canvas */
  1036.     }
  1037. }
  1038.  
  1039. fatal(s)
  1040.     char *s;
  1041. {
  1042.     (void) fprintf(stderr, "%s: fatal: %s\n", prog, s);
  1043.     exit(1);
  1044. }
  1045.