home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / unixtex-6.1b-src.tgz / tar.out / contrib / unixtex / xdvik / events.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  40KB  |  1,554 lines

  1. /*
  2.  * Copyright (c) 1994 Paul Vojta.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 1. Redistributions of source code must retain the above copyright
  8.  *    notice, this list of conditions and the following disclaimer.
  9.  * 2. Redistributions in binary form must reproduce the above copyright
  10.  *    notice, this list of conditions and the following disclaimer in the
  11.  *    documentation and/or other materials provided with the distribution.
  12.  *
  13.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23.  * SUCH DAMAGE.
  24.  *
  25.  * NOTE:
  26.  *    xdvi is based on prior work as noted in the modification history, below.
  27.  */
  28.  
  29. /*
  30.  * DVI previewer for X.
  31.  *
  32.  * Eric Cooper, CMU, September 1985.
  33.  *
  34.  * Code derived from dvi-imagen.c.
  35.  *
  36.  * Modification history:
  37.  * 1/1986    Modified for X.10    --Bob Scheifler, MIT LCS.
  38.  * 7/1988    Modified for X.11    --Mark Eichin, MIT
  39.  * 12/1988    Added 'R' option, toolkit, magnifying glass
  40.  *                    --Paul Vojta, UC Berkeley.
  41.  * 2/1989    Added tpic support    --Jeffrey Lee, U of Toronto
  42.  * 4/1989    Modified for System V    --Donald Richardson, Clarkson Univ.
  43.  * 3/1990    Added VMS support    --Scott Allendorf, U of Iowa
  44.  * 7/1990    Added reflection mode    --Michael Pak, Hebrew U of Jerusalem
  45.  * 1/1992    Added greyscale code    --Till Brychcy, Techn. Univ. Muenchen
  46.  *                      and Lee Hetherington, MIT
  47.  * 4/1994    Added DPS support, bounding box
  48.  *                    --Ricardo Telichevesky
  49.  *                      and Luis Miguel Silveira, MIT RLE.
  50.  */
  51.  
  52. #include <config.h>
  53.  
  54.  
  55. /* Xlib and Xutil are already included */
  56. #ifdef    TOOLKIT
  57. #ifdef    OLD_X11_TOOLKIT
  58. #include <X11/Atoms.h>
  59. #else /* not OLD_X11_TOOLKIT */
  60. #include <X11/Xatom.h>
  61. #include <X11/StringDefs.h>
  62. #endif /* not OLD_X11_TOOLKIT */
  63. #include <X11/Shell.h>    /* needed for def. of XtNiconX */
  64. #ifndef    XtSpecificationRelease
  65. #define    XtSpecificationRelease    0
  66. #endif
  67. #if    XtSpecificationRelease >= 4
  68. #include <X11/Xaw/Viewport.h>
  69. #ifdef    BUTTONS
  70. #include <X11/Xaw/Command.h>
  71. #endif
  72. #else    /* XtSpecificationRelease < 4 */
  73. #define    XtPointer caddr_t
  74. #include <X11/Viewport.h>
  75. #ifdef    BUTTONS
  76. #include <X11/Command.h>
  77. #endif
  78. #endif    /* XtSpecificationRelease */
  79. #else    /* !TOOLKIT */
  80. typedef    int        Position;
  81. #define    XtPending()    XPending(DISP)
  82. #endif    /* TOOLKIT */
  83.  
  84. #if    HAS_SIGIO
  85. #include <fcntl.h>
  86. #include <signal.h>
  87. #ifndef    FASYNC
  88. #undef    HAS_SIGIO
  89. #define    HAS_SIGIO 0
  90. #endif
  91. #endif
  92.  
  93. #ifndef    X11HEIGHT
  94. #define    X11HEIGHT    8    /* Height of server default font */
  95. #endif
  96.  
  97. #define    MAGBORD    1    /* border size for magnifier */
  98.  
  99. /*
  100.  * Command line flags.
  101.  */
  102.  
  103. #define    fore_Pixel    resource._fore_Pixel
  104. #define    back_Pixel    resource._back_Pixel
  105. #ifdef    TOOLKIT
  106. extern struct _resource    resource;
  107. #define    brdr_Pixel    resource._brdr_Pixel
  108. #endif    /* TOOLKIT */
  109.  
  110. static    int    pageno_correct    = 1;
  111. static    Boolean    colors_allocated = False;
  112.  
  113. #define    clip_w    mane.width
  114. #define    clip_h    mane.height
  115. static    Position main_x, main_y;
  116. static    Position mag_x, mag_y, new_mag_x, new_mag_y;
  117. static    Boolean    mag_moved = False;
  118.  
  119. #ifdef    TOOLKIT
  120. #ifdef    BUTTONS
  121. static    Widget    line_widget, panel_widget;
  122. #endif
  123. static    Widget    x_bar, y_bar;    /* horizontal and vertical scroll bars */
  124.  
  125. static    Arg    resize_args[] = {
  126.     {XtNwidth,    (XtArgVal) 0},
  127.     {XtNheight,    (XtArgVal) 0},
  128. };
  129.  
  130. #define    XdviResizeWidget(widget, w, h)    \
  131.         (resize_args[0].value = (XtArgVal) (w), \
  132.         resize_args[1].value = (XtArgVal) (h), \
  133.         XtSetValues(widget, resize_args, XtNumber(resize_args)) )
  134.  
  135. #ifdef    BUTTONS
  136.  
  137. static    Arg    resizable_on[] = {
  138.     {XtNresizable,    (XtArgVal) True},
  139. };
  140.  
  141. static    Arg    resizable_off[] = {
  142.     {XtNresizable,    (XtArgVal) False},
  143. };
  144.  
  145. static    Arg    line_args[] = {
  146.     {XtNbackground,    (XtArgVal) 0},
  147.     {XtNwidth,    (XtArgVal) 1},
  148.     {XtNheight,    (XtArgVal) 0},
  149.     {XtNfromHoriz,    (XtArgVal) NULL},
  150.     {XtNborderWidth, (XtArgVal) 0},
  151.     {XtNtop,    (XtArgVal) XtChainTop},
  152.     {XtNbottom,    (XtArgVal) XtChainBottom},
  153.     {XtNleft,    (XtArgVal) XtChainRight},
  154.     {XtNright,    (XtArgVal) XtChainRight},
  155. };
  156.  
  157. static    Arg    panel_args[] = {
  158.     {XtNfromHoriz,    (XtArgVal) NULL},
  159.     {XtNwidth,    (XtArgVal) (XTRA_WID - 1)},
  160.     {XtNheight,    (XtArgVal) 0},
  161.     {XtNborderWidth, (XtArgVal) 0},
  162.     {XtNtop,    (XtArgVal) XtChainTop},
  163.     {XtNbottom,    (XtArgVal) XtChainBottom},
  164.     {XtNleft,    (XtArgVal) XtChainRight},
  165.     {XtNright,    (XtArgVal) XtChainRight},
  166. };
  167.  
  168. static    struct {
  169.     _Xconst    char    *label;
  170.     _Xconst    char    *name;
  171.     int    closure;
  172.     int    y_pos;
  173.     }
  174.     command_table[] = {
  175. #ifdef SELFILE
  176. /* Reposition "Quit" button to fit "File" button in JSP */
  177.         {"Quit",    "quit",        'q',        10},
  178.         {"File",    "file",     'F',        60},
  179. #else  /* SELFILE */
  180.         {"Quit",    "quit",        'q',        50},
  181. #endif  /* SELFILE */
  182.         {"Shrink1",    "sh1",        1 << 8 | 's',    150},
  183.         {"Shrink2",    "sh2",        2 << 8 | 's',    200},
  184.         {"Shrink3",    "sh3",        3 << 8 | 's',    250},
  185.         {"Shrink4",    "sh4",        4 << 8 | 's',    300},
  186.         {"Page-10",    "prev10",    10 << 8 | 'p',    400},
  187.         {"Page-5",    "prev5",    5 << 8 | 'p',    450},
  188.         {"Prev",    "prev",        'p',        500},
  189.         {"Next",    "next",        'n',        600},
  190.         {"Page+5",    "next5",    5 << 8 | 'n',    650},
  191.         {"Page+10",    "next10",    10 << 8 | 'n',    700},
  192. #if    PS
  193.         {"View PS",    "postscript",    'v',        750},
  194. #endif
  195. };
  196.  
  197. static    void    handle_command();
  198.  
  199. static    XtCallbackRec    command_call[] = {
  200.     {handle_command, NULL},
  201.     {NULL,        NULL},
  202. };
  203.  
  204. static    Arg    command_args[] = {
  205.     {XtNlabel,    (XtArgVal) NULL},
  206.     {XtNx,        (XtArgVal) 6},
  207.     {XtNy,        (XtArgVal) 0},
  208.     {XtNwidth,    (XtArgVal) 64},
  209.     {XtNheight,    (XtArgVal) 30},
  210.     {XtNcallback,    (XtArgVal) command_call},
  211. };
  212.  
  213. void
  214. create_buttons(h)
  215.     XtArgVal    h;
  216. {
  217.     int i;
  218.  
  219.     line_args[0].value = (XtArgVal) resource._hl_Pixel;
  220.     line_args[2].value = h;
  221.     line_args[3].value = (XtArgVal) vport_widget;
  222.     line_widget = XtCreateManagedWidget("line", widgetClass, form_widget,
  223.         line_args, XtNumber(line_args));
  224.     panel_args[0].value = (XtArgVal) line_widget;
  225.     panel_args[2].value = h;
  226.     panel_widget = XtCreateManagedWidget("panel", compositeWidgetClass,
  227.         form_widget, panel_args, XtNumber(panel_args));
  228.  
  229.     command_args[2].value = (XtArgVal) vport_widget;
  230.     for (i = 0; i < XtNumber(command_table); ++i) {
  231.         command_args[0].value = (XtArgVal) command_table[i].label;
  232.         command_args[2].value = (XtArgVal) command_table[i].y_pos;
  233.         command_call[0].closure = (XtPointer) &command_table[i].closure;
  234.         (void) XtCreateManagedWidget(command_table[i].name,
  235.         commandWidgetClass, panel_widget,
  236.         command_args, XtNumber(command_args));
  237.     }
  238. }
  239. #endif    /* BUTTONS */
  240.  
  241. #else    /* !TOOLKIT */
  242. static    Window    x_bar, y_bar;
  243. static    int    x_bgn, x_end, y_bgn, y_end;    /* scrollbar positions */
  244. #endif    /* TOOLKIT */
  245.  
  246. /*
  247.  *    Mechanism to keep track of the magnifier window.  The problems are,
  248.  *    (a) if the button is released while the window is being drawn, this
  249.  *    could cause an X error if we continue drawing in it after it is
  250.  *    destroyed, and
  251.  *    (b) creating and destroying the window too quickly confuses the window
  252.  *    manager, which is avoided by waiting for an expose event before
  253.  *    destroying it.
  254.  */
  255. static    short    alt_stat;    /* 1 = wait for expose, */
  256.                 /* -1 = destroy upon expose */
  257. static    Boolean    alt_canit;    /* stop drawing this window */
  258.  
  259. /*
  260.  *    Data for buffered events.
  261.  */
  262.  
  263. static    Boolean    has_arg        = False;
  264. static    VOLATILE short    event_freq    = 70;
  265. static    int    number        = 0;
  266. static    int    sign        = 1;
  267.  
  268. static    void    can_exposures(), keystroke();
  269.  
  270. #ifdef    GREY
  271. #define    gamma    resource._gamma
  272.  
  273. void
  274. init_pix(warn)
  275.     Boolean    warn;
  276. {
  277.     static    int    shrink_allocated_for = 0;
  278.     int    i;
  279.  
  280.     if (!colors_allocated)
  281.     {
  282.         Pixel plane_masks[4];
  283.         Pixel pixel;
  284.         XColor color, fc, bc;
  285.         XGCValues    values;
  286.  
  287.         if (gamma == 0.0) gamma = 1.0;
  288.  
  289.         if (!resource.copy)
  290.         /* allocate 4 color planes for 16 colors (for GXor drawing) */
  291.         if (!XAllocColorCells(DISP, DefaultColormapOfScreen(SCRN),
  292.                       False, plane_masks, 4, &pixel, 1))
  293.             resource.copy = warn = True;
  294.  
  295.         /* get foreground and background RGB values for interpolating */
  296.         fc.pixel = fore_Pixel;
  297.         XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &fc);
  298.         bc.pixel = back_Pixel;
  299.         XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &bc);
  300.  
  301.         for (i = 0; i < 16; ++i) {
  302.         double    pow();
  303.         double    frac = gamma > 0 ? pow((double) i / 15, 1 / gamma)
  304.             : 1 - pow((double) (15 - i) / 15, -gamma);
  305.  
  306.         color.red = frac * ((double) fc.red - bc.red) + bc.red;
  307.         color.green = frac * ((double) fc.green - bc.green) + bc.green;
  308.         color.blue = frac * ((double) fc.blue - bc.blue) + bc.blue;
  309.  
  310.         color.pixel = pixel;
  311.         color.flags = DoRed | DoGreen | DoBlue;
  312.  
  313.         if (!resource.copy) {
  314.             if (i & 1) color.pixel |= plane_masks[0];
  315.             if (i & 2) color.pixel |= plane_masks[1];
  316.             if (i & 4) color.pixel |= plane_masks[2];
  317.             if (i & 8) color.pixel |= plane_masks[3];
  318.             XStoreColor(DISP, DefaultColormapOfScreen(SCRN), &color);
  319.             palette[i] = color.pixel;
  320.         }
  321.         else {
  322.             if (!XAllocColor(DISP, DefaultColormapOfScreen(SCRN),
  323.             &color))
  324.             palette[i] = (i * 100 >= density * 15)
  325.                 ? fore_Pixel : back_Pixel;
  326.             else
  327.             palette[i] = color.pixel;
  328.         }
  329.         }
  330.  
  331.         /* Make sure fore_ and back_Pixel are a part of the palette */
  332.         fore_Pixel = palette[15];
  333.         back_Pixel = palette[0];
  334.         if (mane.win != (Window) 0)
  335.         XSetWindowBackground(DISP, mane.win, palette[0]);
  336.  
  337. #define    MakeGC(fcn, fg, bg)    (values.function = fcn, values.foreground=fg,\
  338.         values.background=bg,\
  339.         XCreateGC(DISP, RootWindowOfScreen(SCRN),\
  340.             GCFunction|GCForeground|GCBackground, &values))
  341.  
  342.         foreGC = ruleGC = MakeGC(resource.copy ? GXcopy : GXor,
  343.         fore_Pixel, back_Pixel);
  344.         foreGC2 = NULL;
  345.  
  346.         colors_allocated = True;
  347. #ifdef    TOOLKIT
  348. #define CopyByDefault() (resource.copy && !resource.copy_arg)
  349. #else
  350. #define CopyByDefault() (resource.copy == 2)
  351. #endif
  352.         /* warn only if copy was not explicitly requested */
  353.         if (CopyByDefault() && warn)
  354.         Puts("Note:  overstrike characters may be incorrect.");
  355.     }
  356. #undef    MakeGC
  357.  
  358.     if (mane.shrinkfactor == 1) return;
  359.  
  360.     if (shrink_allocated_for < mane.shrinkfactor) {
  361.         if (pixeltbl != NULL) free((char *) pixeltbl);
  362.         pixeltbl = (Pixel *) xmalloc((unsigned)
  363.         (mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof(Pixel),
  364.         "pixel table");
  365.         shrink_allocated_for = mane.shrinkfactor;
  366.     }
  367.  
  368.     for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i)
  369.         pixeltbl[i] =
  370.         palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
  371.             / (2 * mane.shrinkfactor * mane.shrinkfactor)];
  372. }
  373. #endif    /* GREY */
  374.  
  375. /*
  376.  *    Event-handling routines
  377.  */
  378.  
  379. static    void
  380. expose(windowrec, x, y, w, h)
  381.     register struct WindowRec *windowrec;
  382.     int        x, y;
  383.     unsigned int    w, h;
  384. {
  385.     if (windowrec->min_x > x) windowrec->min_x = x;
  386.     if (windowrec->max_x < x + w)
  387.         windowrec->max_x = x + w;
  388.     if (windowrec->min_y > y) windowrec->min_y = y;
  389.     if (windowrec->max_y < y + h)
  390.         windowrec->max_y = y + h;
  391. }
  392.  
  393. static    void
  394. clearexpose(windowrec, x, y, w, h)
  395.     struct WindowRec *windowrec;
  396.     int        x, y;
  397.     unsigned int    w, h;
  398. {
  399.     XClearArea(DISP, windowrec->win, x, y, w, h, False);
  400.     expose(windowrec, x, y, w, h);
  401. }
  402.  
  403. static    void
  404. scrollwindow(windowrec, x0, y0)
  405.     register struct WindowRec *windowrec;
  406.     int    x0, y0;
  407. {
  408.     int    x, y;
  409.     int    x2 = 0, y2 = 0;
  410.     int    ww, hh;
  411.  
  412.     x = x0 - windowrec->base_x;
  413.     y = y0 - windowrec->base_y;
  414.     ww = windowrec->width - x;
  415.     hh = windowrec->height - y;
  416.     windowrec->base_x = x0;
  417.     windowrec->base_y = y0;
  418.     if (currwin.win == windowrec->win) {
  419.         currwin.base_x = x0;
  420.         currwin.base_y = y0;
  421.     }
  422.     windowrec->min_x -= x;
  423.     if (windowrec->min_x < 0) windowrec->min_x = 0;
  424.     windowrec->max_x -= x;
  425.     if (windowrec->max_x > windowrec->width)
  426.         windowrec->max_x = windowrec->width;
  427.     windowrec->min_y -= y;
  428.     if (windowrec->min_y < 0) windowrec->min_y = 0;
  429.     windowrec->max_y -= y;
  430.     if (windowrec->max_y > windowrec->height)
  431.         windowrec->max_y = windowrec->height;
  432.     if (x < 0) {
  433.         x2 = -x;
  434.         x = 0;
  435.         ww = windowrec->width - x2;
  436.     }
  437.     if (y < 0) {
  438.         y2 = -y;
  439.         y = 0;
  440.         hh = windowrec->height - y2;
  441.     }
  442.     if (ww <= 0 || hh <= 0) {
  443.         XClearWindow(DISP, windowrec->win);
  444.         windowrec->min_x = windowrec->min_y = 0;
  445.         windowrec->max_x = windowrec->width;
  446.         windowrec->max_y = windowrec->height;
  447.     }
  448.     else {
  449.         XCopyArea(DISP, windowrec->win, windowrec->win,
  450.         DefaultGCOfScreen(SCRN), x, y,
  451.         (unsigned int) ww, (unsigned int) hh, x2, y2);
  452.         if (x > 0)
  453.         clearexpose(windowrec, ww, 0,
  454.             (unsigned int) x, windowrec->height);
  455.         if (x2 > 0)
  456.         clearexpose(windowrec, 0, 0,
  457.             (unsigned int) x2, windowrec->height);
  458.         if (y > 0)
  459.         clearexpose(windowrec, 0, hh,
  460.             windowrec->width, (unsigned int) y);
  461.         if (y2 > 0)
  462.         clearexpose(windowrec, 0, 0,
  463.             windowrec->width, (unsigned int) y2);
  464.     }
  465. }
  466.  
  467. #ifdef    TOOLKIT
  468. /*
  469.  *    routines for X11 toolkit
  470.  */
  471.  
  472. static    Arg    arg_wh[] = {
  473.     {XtNwidth,    (XtArgVal) &window_w},
  474.     {XtNheight,    (XtArgVal) &window_h},
  475. };
  476.  
  477. static    Position    window_x, window_y;
  478. static    Arg    arg_xy[] = {
  479.     {XtNx,        (XtArgVal) &window_x},
  480.     {XtNy,        (XtArgVal) &window_y},
  481. };
  482.  
  483. #define    get_xy()    XtGetValues(draw_widget, arg_xy, XtNumber(arg_xy))
  484.  
  485. #define    mane_base_x    0
  486. #define    mane_base_y    0
  487.  
  488. void /* not static because SELFILE stuff in dvi_init.c needs it */
  489. home(scrl)
  490.     Boolean    scrl;
  491. {
  492. #if    PS
  493.     psp.interrupt();
  494. #endif
  495.     if (!scrl) XUnmapWindow(DISP, mane.win);
  496.     get_xy();
  497.     if (x_bar != NULL) {
  498.         register int coord = (page_w - clip_w) / 2;
  499.         if (coord > home_x / mane.shrinkfactor)
  500.         coord = home_x / mane.shrinkfactor;
  501.         XtCallCallbacks(x_bar, XtNscrollProc,
  502.         (XtPointer) (window_x + coord));
  503.     }
  504.     if (y_bar != NULL) {
  505.         register int coord = (page_h - clip_h) / 2;
  506.         if (coord > home_y / mane.shrinkfactor)
  507.         coord = home_y / mane.shrinkfactor;
  508.         XtCallCallbacks(y_bar, XtNscrollProc,
  509.         (XtPointer) (window_y + coord));
  510.     }
  511.     if (!scrl) {
  512.         XMapWindow(DISP, mane.win);
  513.         /* Wait for the server to catch up---this eliminates flicker. */
  514.         XSync(DISP, False);
  515.     }
  516. }
  517.  
  518. static    Boolean    resized    = False;
  519.  
  520. static    void
  521. get_geom()
  522. {
  523.     static    Dimension    new_clip_w, new_clip_h;
  524.     static    Arg    arg_wh_clip[] = {
  525.         {XtNwidth,    (XtArgVal) &new_clip_w},
  526.         {XtNheight,    (XtArgVal) &new_clip_h},
  527.     };
  528.     register int    old_clip_w;
  529.  
  530.     XtGetValues(vport_widget, arg_wh, XtNumber(arg_wh));
  531.     XtGetValues(clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
  532.     /* Note:  widgets may be destroyed but not forgotten */
  533.     x_bar = page_w <= new_clip_w ? NULL
  534.         : XtNameToWidget(vport_widget, "horizontal");
  535.     y_bar = page_h <= new_clip_h ? NULL
  536.         : XtNameToWidget(vport_widget, "vertical");
  537.     old_clip_w = clip_w;
  538.             /* we need to do this because */
  539.             /* sizeof(Dimension) != sizeof(int) */
  540.     clip_w = new_clip_w;
  541.     clip_h = new_clip_h;
  542.     if (old_clip_w == 0) home(False);
  543.     resized = False;
  544. }
  545.  
  546. static    void
  547. center(x, y)
  548.     int x, y;
  549. {
  550. /*    We use the clip widget here because it gives a more exact value. */
  551.     x -= clip_w/2;
  552.     y -= clip_h/2;
  553.     if (x_bar) XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) x);
  554.     if (y_bar) XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) y);
  555.     XWarpPointer(DISP, None, None, 0, 0, 0, 0, -x, -y);
  556. }
  557.  
  558. /*
  559.  *    callback routines
  560.  */
  561.  
  562. /* The following callback routine should never be called. */
  563.     /*ARGSUSED*/
  564. void
  565. handle_key(widget, junk, event, cont)
  566.     Widget    widget;
  567.     XtPointer junk;
  568.     XEvent    *event;
  569.     Boolean    *cont;        /* unused */
  570. {
  571.     XBell(DISP, 20);
  572. }
  573.  
  574.     /*ARGSUSED*/
  575. void
  576. handle_resize(widget, junk, event, cont)
  577.     Widget    widget;
  578.     XtPointer junk;
  579.     XEvent    *event;
  580.     Boolean    *cont;        /* unused */
  581. {
  582.     resized = True;
  583. }
  584.  
  585. #ifdef    BUTTONS
  586.     /*ARGSUSED*/
  587. static    void
  588. handle_command(widget, client_data_p, call_data)
  589.     Widget    widget;
  590.     XtPointer client_data_p;
  591.     XtPointer call_data;
  592. {
  593.     int    client_data    = * (int *) client_data_p;
  594.  
  595.     keystroke((client_data) & 0xff, (client_data) >> 8,
  596.         ((client_data) >> 8) != 0, (XEvent *) NULL);
  597. }
  598. #endif    /* BUTTONS */
  599.  
  600. void
  601. reconfig()
  602. {
  603. #ifdef    BUTTONS
  604.     XtSetValues(vport_widget, resizable_off, XtNumber(resizable_off));
  605. #endif
  606.     XdviResizeWidget(draw_widget, page_w, page_h);
  607.     get_geom();
  608. }
  609.  
  610. #else    /* !TOOLKIT */
  611.  
  612. /*
  613.  *    brute force scrollbar routines
  614.  */
  615.  
  616. static    void
  617. paint_x_bar()
  618. {
  619.     register int    new_x_bgn = mane.base_x * clip_w / page_w;
  620.     register int    new_x_end = (mane.base_x + clip_w) * clip_w / page_w;
  621.  
  622.     if (new_x_bgn >= x_end || x_bgn >= new_x_end) {    /* no overlap */
  623.         XClearArea(DISP, x_bar, x_bgn, 1, x_end - x_bgn, BAR_WID, False);
  624.         XFillRectangle(DISP, x_bar, ruleGC,
  625.         new_x_bgn, 1, new_x_end - new_x_bgn, BAR_WID);
  626.     }
  627.     else {        /* this stuff avoids flicker */
  628.         if (x_bgn < new_x_bgn)
  629.         XClearArea(DISP, x_bar, x_bgn, 1, new_x_bgn - x_bgn,
  630.             BAR_WID, False);
  631.         else
  632.         XFillRectangle(DISP, x_bar, ruleGC,
  633.             new_x_bgn, 1, x_bgn - new_x_bgn, BAR_WID);
  634.         if (new_x_end < x_end)
  635.         XClearArea(DISP, x_bar, new_x_end, 1, x_end - new_x_end,
  636.             BAR_WID, False);
  637.         else
  638.         XFillRectangle(DISP, x_bar, ruleGC,
  639.             x_end, 1, new_x_end - x_end, BAR_WID);
  640.     }
  641.     x_bgn = new_x_bgn;
  642.     x_end = new_x_end;
  643. }
  644.  
  645. static    void
  646. paint_y_bar()
  647. {
  648.     register int    new_y_bgn = mane.base_y * clip_h / page_h;
  649.     register int    new_y_end = (mane.base_y + clip_h) * clip_h / page_h;
  650.  
  651.     if (new_y_bgn >= y_end || y_bgn >= new_y_end) {    /* no overlap */
  652.         XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, y_end - y_bgn, False);
  653.         XFillRectangle(DISP, y_bar, ruleGC,
  654.         1, new_y_bgn, BAR_WID, new_y_end - new_y_bgn);
  655.     }
  656.     else {        /* this stuff avoids flicker */
  657.         if (y_bgn < new_y_bgn)
  658.         XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, new_y_bgn - y_bgn,
  659.             False);
  660.         else
  661.         XFillRectangle(DISP, y_bar, ruleGC,
  662.             1, new_y_bgn, BAR_WID, y_bgn - new_y_bgn);
  663.         if (new_y_end < y_end)
  664.         XClearArea(DISP, y_bar, 1, new_y_end,
  665.             BAR_WID, y_end - new_y_end, False);
  666.         else
  667.         XFillRectangle(DISP, y_bar, ruleGC,
  668.             1, y_end, BAR_WID, new_y_end - y_end);
  669.     }
  670.     y_bgn = new_y_bgn;
  671.     y_end = new_y_end;
  672. }
  673.  
  674. static    void
  675. scrollmane(x, y)
  676.     int    x, y;
  677. {
  678.     register int    old_base_x = mane.base_x;
  679.     register int    old_base_y = mane.base_y;
  680.  
  681. #if    PS
  682.     psp.interrupt();
  683. #endif
  684.     if (x > (int) (page_w - clip_w)) x = page_w - clip_w;
  685.     if (x < 0) x = 0;
  686.     if (y > (int) (page_h - clip_h)) y = page_h - clip_h;
  687.     if (y < 0) y = 0;
  688.     scrollwindow(&mane, x, y);
  689.     if (old_base_x != mane.base_x && x_bar) paint_x_bar();
  690.     if (old_base_y != mane.base_y && y_bar) paint_y_bar();
  691. }
  692.  
  693. void
  694. reconfig()
  695. {
  696.     int    x_thick = 0;
  697.     int    y_thick = 0;
  698.  
  699.         /* determine existence of scrollbars */
  700.     if (window_w < page_w) x_thick = BAR_THICK;
  701.     if (window_h - x_thick < page_h) y_thick = BAR_THICK;
  702.     clip_w = window_w - y_thick;
  703.     if (clip_w < page_w) x_thick = BAR_THICK;
  704.     clip_h = window_h - x_thick;
  705.  
  706.         /* process drawing (clip) window */
  707.     if (mane.win == (Window) 0) {    /* initial creation */
  708.         XWindowAttributes attrs;
  709.  
  710.         mane.win = XCreateSimpleWindow(DISP, top_level, y_thick, x_thick,
  711.             (unsigned int) clip_w, (unsigned int) clip_h, 0,
  712.             brdr_Pixel, back_Pixel);
  713.         XSelectInput(DISP, mane.win, ExposureMask |
  714.             ButtonPressMask | ButtonMotionMask | ButtonReleaseMask);
  715.         (void) XGetWindowAttributes(DISP, mane.win, &attrs);
  716.         backing_store = attrs.backing_store;
  717.         XMapWindow(DISP, mane.win);
  718.     }
  719.     else
  720.         XMoveResizeWindow(DISP, mane.win, y_thick, x_thick, clip_w, clip_h);
  721.  
  722.         /* process scroll bars */
  723.     if (x_thick) {
  724.         if (x_bar) {
  725.         XMoveResizeWindow(DISP, x_bar,
  726.             y_thick - 1, -1, clip_w, BAR_THICK - 1);
  727.         paint_x_bar();
  728.         }
  729.         else {
  730.         x_bar = XCreateSimpleWindow(DISP, top_level, y_thick - 1, -1,
  731.                 (unsigned int) clip_w, BAR_THICK - 1, 1,
  732.                 brdr_Pixel, back_Pixel);
  733.         XSelectInput(DISP, x_bar,
  734.             ExposureMask | ButtonPressMask | Button2MotionMask);
  735.         XMapWindow(DISP, x_bar);
  736.         }
  737.         x_bgn = mane.base_x * clip_w / page_w;
  738.         x_end = (mane.base_x + clip_w) * clip_w / page_w;
  739.     }
  740.     else
  741.         if (x_bar) {
  742.         XDestroyWindow(DISP, x_bar);
  743.         x_bar = (Window) 0;
  744.         }
  745.  
  746.     if (y_thick) {
  747.         if (y_bar) {
  748.         XMoveResizeWindow(DISP, y_bar,
  749.             -1, x_thick - 1, BAR_THICK - 1, clip_h);
  750.         paint_y_bar();
  751.         }
  752.         else {
  753.         y_bar = XCreateSimpleWindow(DISP, top_level, -1, x_thick - 1,
  754.                 BAR_THICK - 1, (unsigned int) clip_h, 1,
  755.                 brdr_Pixel, back_Pixel);
  756.         XSelectInput(DISP, y_bar,
  757.             ExposureMask | ButtonPressMask | Button2MotionMask);
  758.         XMapWindow(DISP, y_bar);
  759.         }
  760.         y_bgn = mane.base_y * clip_h / page_h;
  761.         y_end = (mane.base_y + clip_h) * clip_h / page_h;
  762.     }
  763.     else
  764.         if (y_bar) {
  765.         XDestroyWindow(DISP, y_bar);
  766.         y_bar = (Window) 0;
  767.         }
  768. }
  769.  
  770. static    void
  771. home(scrl)
  772.     Boolean    scrl;
  773. {
  774.     int    x = 0, y = 0;
  775.  
  776.     if (page_w > clip_w) {
  777.         x = (page_w - clip_w) / 2;
  778.         if (x > home_x / mane.shrinkfactor)
  779.         x = home_x / mane.shrinkfactor;
  780.     }
  781.     if (page_h > clip_h) {
  782.         y = (page_h - clip_h) / 2;
  783.         if (y > home_y / mane.shrinkfactor)
  784.         y = home_y / mane.shrinkfactor;
  785.     }
  786.     if (scrl)
  787.         scrollmane(x, y);
  788.     else {
  789.         mane.base_x = x;
  790.         mane.base_y = y;
  791.         if (currwin.win == mane.win) {
  792.         currwin.base_x = x;
  793.         currwin.base_y = y;
  794.         }
  795.         if (x_bar) paint_x_bar();
  796.         if (y_bar) paint_y_bar();
  797.     }
  798. }
  799.  
  800. #define    get_xy()
  801. #define    window_x 0
  802. #define    window_y 0
  803. #define    mane_base_x    mane.base_x
  804. #define    mane_base_y    mane.base_y
  805. #endif    /* TOOLKIT */
  806.  
  807. static    void
  808. compute_mag_pos(xp, yp)
  809.     int    *xp, *yp;
  810. {
  811.     register int t;
  812.  
  813.     t = mag_x + main_x - alt.width/2;
  814.     if (t > WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD)
  815.         t = WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD;
  816.     if (t < 0) t = 0;
  817.     *xp = t;
  818.     t = mag_y + main_y - alt.height/2;
  819.     if (t > HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD)
  820.         t = HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD;
  821.     if (t < 0) t = 0;
  822.     *yp = t;
  823. }
  824.  
  825. #ifdef    TOOLKIT
  826.     /*ARGSUSED*/
  827. void
  828. handle_button(widget, junk, ev, cont)
  829.     Widget    widget;
  830.     XtPointer junk;
  831.     XEvent *ev;
  832. #define    event    (&(ev->xbutton))
  833.     Boolean    *cont;        /* unused */
  834. #else    /* !TOOLKIT */
  835. void
  836. handle_button(event)
  837.     XButtonEvent *event;
  838. #endif    /* TOOLKIT */
  839. {
  840.     int    x, y;
  841.     struct mg_size_rec    *size_ptr = mg_size + event->button - 1;
  842.     XSetWindowAttributes attr;
  843.  
  844.     if (alt.win != (Window) 0 || mane.shrinkfactor == 1 || size_ptr->w <= 0)
  845.         XBell(DISP, 20);
  846.     else {
  847.         mag_x = event->x;
  848.         mag_y = event->y;
  849.         alt.width = size_ptr->w;
  850.         alt.height = size_ptr->h;
  851.         main_x = event->x_root - mag_x;
  852.         main_y = event->y_root - mag_y;
  853.         compute_mag_pos(&x, &y);
  854.         alt.base_x = (event->x + mane_base_x) * mane.shrinkfactor -
  855.         alt.width/2;
  856.         alt.base_y = (event->y + mane_base_y) * mane.shrinkfactor -
  857.         alt.height/2;
  858.         attr.save_under = True;
  859.         attr.border_pixel = brdr_Pixel;
  860.         attr.background_pixel = back_Pixel;
  861.         attr.override_redirect = True;
  862.         alt.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
  863.             x, y, alt.width, alt.height, MAGBORD,
  864.             0,    /* depth from parent */
  865.             InputOutput, (Visual *) CopyFromParent,
  866.             CWSaveUnder | CWBorderPixel | CWBackPixel |
  867.             CWOverrideRedirect, &attr);
  868.         XSelectInput(DISP, alt.win, ExposureMask);
  869.         XMapWindow(DISP, alt.win);
  870.         alt_stat = 1;    /* waiting for exposure */
  871.     }
  872. }
  873.  
  874. #ifdef    TOOLKIT
  875. #undef    event
  876.  
  877.     /*ARGSUSED*/
  878. void
  879. handle_motion(widget, junk, ev, cont)
  880.     Widget    widget;
  881.     XtPointer junk;
  882.     XEvent *ev;
  883. #define    event    (&(ev->xmotion))
  884.     Boolean    *cont;        /* unused */
  885. {
  886.     new_mag_x = event->x;
  887.     main_x = event->x_root - new_mag_x;
  888.     new_mag_y = event->y;
  889.     main_y = event->y_root - new_mag_y;
  890.     mag_moved = (new_mag_x != mag_x || new_mag_y != mag_y);
  891. }
  892.  
  893. #undef    event
  894. #endif    /* TOOLKIT */
  895.  
  896. static    void
  897. movemag(x, y)
  898.     int    x, y;
  899. {
  900.     int    xx, yy;
  901.  
  902.     mag_x = x;
  903.     mag_y = y;
  904.     if (mag_x == new_mag_x && mag_y == new_mag_y) mag_moved = False;
  905.     compute_mag_pos(&xx, &yy);
  906.     XMoveWindow(DISP, alt.win, xx, yy);
  907.     scrollwindow(&alt,
  908.         (x + mane_base_x) * mane.shrinkfactor - (int) alt.width/2,
  909.         (y + mane_base_y) * mane.shrinkfactor - (int) alt.height/2);
  910. }
  911.  
  912. #ifdef    TOOLKIT
  913.     /*ARGSUSED*/
  914. void
  915. handle_release(widget, junk, ev, cont)
  916.     Widget    widget;
  917.     XtPointer junk;
  918.     XEvent *ev;
  919. #define    event    (&(ev->xbutton))
  920.     Boolean    *cont;        /* unused */
  921. #else    /* !TOOLKIT */
  922. void
  923. handle_release()
  924. #endif    /* TOOLKIT */
  925. {
  926.     if (alt.win != (Window) 0)
  927.         if (alt_stat) alt_stat = -1;    /* destroy upon expose */
  928.         else {
  929.         XDestroyWindow(DISP, alt.win);
  930.         if (currwin.win == alt.win) alt_canit = True;
  931.         alt.win = (Window) 0;
  932.         mag_moved = False;
  933.         can_exposures(&alt);
  934.         }
  935. }
  936.  
  937. #ifdef    TOOLKIT
  938. #undef    event
  939.  
  940.     /*ARGSUSED*/
  941. void
  942. handle_exp(widget, closure, ev, cont)
  943.     Widget    widget;
  944.     XtPointer closure;
  945.     register XEvent *ev;
  946. #define    event    (&(ev->xexpose))
  947.     Boolean    *cont;        /* unused */
  948. {
  949.     struct WindowRec *windowrec = (struct WindowRec *) closure;
  950.  
  951.     if (windowrec == &alt)
  952.         if (alt_stat < 0) {    /* destroy upon exposure */
  953.         alt_stat = 0;
  954.         handle_release(widget, (caddr_t) NULL, ev, (Boolean *) NULL);
  955.         return;
  956.         }
  957.         else
  958.         alt_stat = 0;
  959.     expose(windowrec, event->x, event->y,
  960.         (unsigned int) event->width, (unsigned int) event->height);
  961. }
  962.  
  963. #undef    event
  964. #endif    /* TOOLKIT */
  965.  
  966. /* |||
  967.  *    Currently the event handler does not coordinate XCopyArea requests
  968.  *    with GraphicsExpose events.  This can lead to problems if the window
  969.  *    is partially obscured and one, for example, drags a scrollbar.
  970.  */
  971.  
  972. static    void
  973. keystroke(ch, number0, arg0, eventp)
  974.     char    ch;
  975.     int    number0;
  976.     Boolean    arg0;
  977.     XEvent    *eventp;
  978. {
  979.     int    next_page;
  980. #ifdef    TOOLKIT
  981.     Window    ww;
  982. #endif
  983.  
  984.     next_page = current_page;
  985.     switch (ch) {
  986.         case 'q':
  987.         case '\003':    /* control-C */
  988.         case '\004':    /* control-D */
  989. #ifdef    VMS
  990.         case '\032':    /* control-Z */
  991. #endif
  992. #if    PS
  993.         psp.destroy();
  994. #endif
  995.         exit(0);
  996.  
  997.         case 'n':
  998.         case 'f':
  999.         case ' ':
  1000.         case '\r':
  1001.         case '\n':
  1002.         /* scroll forward; i.e. go to relative page */
  1003.         next_page = current_page + (arg0 ? number0 : 1);
  1004.         break;
  1005.         case 'p':
  1006.         case 'b':
  1007.         case '\b':
  1008.         case '\177':    /* Del */
  1009.         /* scroll backward */
  1010.         next_page = current_page - (arg0 ? number0 : 1);
  1011.         break;
  1012.         case 'g':
  1013.         /* go to absolute page */
  1014.         next_page = (arg0 ? number0 - pageno_correct :
  1015.             total_pages - 1);
  1016.         break;
  1017.         case 'P':        /* declare current page */
  1018.         pageno_correct = arg0 * number0 - current_page;
  1019.         return;
  1020.         case 'k':        /* toggle keep-position flag */
  1021.         resource.keep_flag = (arg0 ? number0 : !resource.keep_flag);
  1022.         return;
  1023.         case '\f':
  1024.         /* redisplay current page */
  1025.         break;
  1026.         case '^':
  1027.         home(True);
  1028.         return;
  1029. #ifdef    TOOLKIT
  1030.         case 'l':
  1031.         if (!x_bar) goto bad;
  1032.         XtCallCallbacks(x_bar, XtNscrollProc,
  1033.             (XtPointer) (-2 * (int) clip_w / 3));
  1034.         return;
  1035.         case 'r':
  1036.         if (!x_bar) goto bad;
  1037.         XtCallCallbacks(x_bar, XtNscrollProc,
  1038.             (XtPointer) (2 * (int) clip_w / 3));
  1039.         return;
  1040.         case 'u':
  1041.         if (!y_bar) goto bad;
  1042.         XtCallCallbacks(y_bar, XtNscrollProc,
  1043.             (XtPointer) (-2 * (int) clip_h / 3));
  1044.         return;
  1045.         case 'd':
  1046.         if (!y_bar) goto bad;
  1047.         XtCallCallbacks(y_bar, XtNscrollProc,
  1048.             (XtPointer) (2 * (int) clip_h / 3));
  1049.         return;
  1050.         case 'c':
  1051.         center(eventp->xkey.x, eventp->xkey.y);
  1052.         return;
  1053.         case 'M':
  1054.         (void) XTranslateCoordinates(DISP, eventp->xkey.window,
  1055.             mane.win, eventp->xkey.x, eventp->xkey.y,
  1056.             &home_x, &home_y, &ww);    /* throw away last argument */
  1057.         home_x *= mane.shrinkfactor;
  1058.         home_y *= mane.shrinkfactor;
  1059.         return;
  1060. #ifdef    BUTTONS
  1061.         case 'x':
  1062.         if (arg0 && resource.expert == (number0 != 0)) return;
  1063.         XtSetValues(vport_widget, resizable_on,
  1064.             XtNumber(resizable_off));
  1065.         if (resource.expert) {    /* create buttons */
  1066.             XdviResizeWidget(vport_widget,
  1067.             window_w -= XTRA_WID, window_h);
  1068.             create_buttons((XtArgVal) window_h);
  1069.             resource.expert = False;
  1070.         }
  1071.         else {        /* destroy buttons */
  1072.             XtDestroyWidget(panel_widget);
  1073.             XtDestroyWidget(line_widget);
  1074.             XdviResizeWidget(vport_widget,
  1075.             window_w += XTRA_WID, window_h);
  1076.             resource.expert = True;
  1077.         }
  1078.         return;
  1079. #endif    /* BUTTONS */
  1080. #else    /* !TOOLKIT */
  1081.         case 'l':
  1082.         if (mane.base_x <= 0) goto bad;
  1083.         scrollmane(mane.base_x - 2 * (int) clip_w / 3, mane.base_y);
  1084.         return;
  1085.         case 'r':
  1086.         if (mane.base_x >= page_w - clip_w) goto bad;
  1087.         scrollmane(mane.base_x + 2 * (int) clip_w / 3, mane.base_y);
  1088.         return;
  1089.         case 'u':
  1090.         if (mane.base_y <= 0) goto bad;
  1091.         scrollmane(mane.base_x, mane.base_y - 2 * (int) clip_h / 3);
  1092.         return;
  1093.         case 'd':
  1094.         if (mane.base_y >= page_h - clip_h) goto bad;
  1095.         scrollmane(mane.base_x, mane.base_y + 2 * (int) clip_h / 3);
  1096.         return;
  1097.         case 'c':    /* unchecked scrollmane() */
  1098.         scrollwindow(&mane, mane.base_x + eventp->xkey.x - clip_w/2,
  1099.             mane.base_y + eventp->xkey.y - clip_h/2);
  1100.         if (x_bar) paint_x_bar();
  1101.         if (y_bar) paint_y_bar();
  1102.         XWarpPointer(DISP, None, None, 0, 0, 0, 0,
  1103.             clip_w/2 - eventp->xkey.x, clip_h/2 - eventp->xkey.y);
  1104.         return;
  1105.         case 'M':
  1106.         home_x = (eventp->xkey.x - (y_bar ? BAR_THICK : 0)
  1107.             + mane.base_x) * mane.shrinkfactor;
  1108.         home_y = (eventp->xkey.y - (x_bar ? BAR_THICK : 0)
  1109.             + mane.base_y) * mane.shrinkfactor;
  1110.         return;
  1111. #endif    /* TOOLKIT */
  1112.  
  1113.         case '\020':    /* Control P */
  1114.         Printf("Unit = %d, bitord = %d, byteord = %d\n",
  1115.             BitmapUnit(DISP), BitmapBitOrder(DISP),
  1116.             ImageByteOrder(DISP));
  1117.         return;
  1118.         case 's':
  1119.         if (!arg0) {
  1120.             int temp;
  1121.             number0 = ROUNDUP(unshrunk_page_w, window_w - 2);
  1122.             temp = ROUNDUP(unshrunk_page_h, window_h - 2);
  1123.             if (number0 < temp) number0 = temp;
  1124.         }
  1125.         if (number0 <= 0) goto bad;
  1126.         if (number0 == mane.shrinkfactor) return;
  1127.         mane.shrinkfactor = number0;
  1128.         init_page();
  1129.         if (number0 != 1 && number0 != bak_shrink) {
  1130.             bak_shrink = number0;
  1131. #ifdef    GREY
  1132.             if (use_grey) init_pix(False);
  1133. #endif
  1134.             reset_fonts();
  1135.         }
  1136.         reconfig();
  1137.         home(False);
  1138.         break;
  1139.         case 'S':
  1140.         if (!arg0) goto bad;
  1141.         if (number0 < 0) goto bad;
  1142.         if (number0 == density) return;
  1143.         density = number0;
  1144.         reset_fonts();
  1145.         if (mane.shrinkfactor == 1) return;
  1146.         break;
  1147. #ifdef    GREY
  1148.         case 'G':
  1149.         use_grey = (arg0 ? number0 : !use_grey);
  1150.          if (use_grey) {
  1151.           if (arg0 && (number0 != 1)) {
  1152.             gamma = number0 / 100.0;
  1153.             colors_allocated = 0;    /* Rethink this in init_pix. */
  1154.           }
  1155.           init_pix(False);
  1156.         }
  1157.         reset_fonts();
  1158.         break;
  1159. #endif
  1160.  
  1161. #if    PS
  1162.         case 'v':
  1163.         if (!arg0 || resource._postscript != !number0) {
  1164.             resource._postscript = !resource._postscript;
  1165.             psp.toggle();
  1166.         }
  1167.         break;
  1168. #endif
  1169.  
  1170. #ifdef SELFILE
  1171.             case 'F':
  1172.         ++dvi_time ; /* notice we want a new file in check_dvi_file */
  1173.         break ;
  1174. #endif  /* SELFILE */
  1175.  
  1176.         case 'R':
  1177.         /* reread DVI file */
  1178.         --dvi_time;    /* then it will notice a change */
  1179.         break;
  1180.         default:
  1181.         goto bad;
  1182.     }
  1183.     if (0 <= next_page && next_page < total_pages) {
  1184.         if (current_page != next_page) {
  1185.         current_page = next_page;
  1186.         hush_spec_now = hush_spec;
  1187.         if (!resource.keep_flag) home(False);
  1188.         }
  1189.         canit = True;
  1190.         XFlush(DISP);
  1191.         return;    /* don't use longjmp here:  it might be called from
  1192.              * within the toolkit, and we don't want to longjmp out
  1193.              * of Xt routines. */
  1194.     }
  1195.     bad:  XBell(DISP, 10);
  1196. }
  1197.  
  1198.  
  1199. #define    TRSIZE    100
  1200.  
  1201. void
  1202. read_events(wait)
  1203.     wide_bool    wait;
  1204. {
  1205.     char    ch;
  1206.     Boolean    arg0;
  1207.     int    number0;
  1208.     XEvent    event;
  1209.     char    trbuf[TRSIZE];
  1210. #define string xdvi_string /* kpathsea has a type `string', and cc chokes */
  1211.     char    *string;
  1212.     int    nbytes;
  1213.  
  1214.     alt_canit = False;
  1215.     for (;;) {
  1216.         ch = '\0';
  1217.         event_counter = event_freq;
  1218.         /*
  1219.          * The above line clears the flag indicating that an event is
  1220.          * pending.  So if an event comes in right now, the flag will be
  1221.          * set again needlessly, but we just end up making an extra call.
  1222.          * Also, be careful about destroying the magnifying glass while
  1223.          * writing it.
  1224.          */
  1225.         if (!XtPending() && (!wait || canit || mane.min_x < MAXDIM ||
  1226.             alt.min_x < MAXDIM || mag_moved)) {
  1227.         if (!wait && (canit | alt_canit)) {
  1228. #if    PS
  1229.             psp.interrupt();
  1230. #endif
  1231.             if (allow_can) longjmp(canit_env, 1);
  1232.         }
  1233.         return;
  1234.         }
  1235. #ifdef    TOOLKIT
  1236.         XtNextEvent(&event);
  1237.         if (resized) get_geom();
  1238.         if (event.xany.window == alt.win && event.type == Expose) {
  1239.         handle_exp((Widget) NULL, (XtPointer) &alt, &event,
  1240.             (Boolean *) NULL);
  1241.         continue;
  1242.         }
  1243.         if (event.type != KeyPress) {
  1244.         (void) XtDispatchEvent(&event);
  1245.         continue;
  1246.         }
  1247.         string = trbuf;
  1248.         nbytes = XLookupString(&event.xkey, string, TRSIZE, (KeySym *) NULL,
  1249.         (XComposeStatus *) NULL);
  1250.         if (nbytes > 1) ch = '?';
  1251.         if (nbytes != 0) ch = *string;
  1252. #else    /* !TOOLKIT */
  1253.  
  1254.         XNextEvent(DISP, &event);
  1255.         if (event.xany.window == mane.win || event.xany.window == alt.win) {
  1256.         struct WindowRec *wr = &mane;
  1257.  
  1258.         if (event.xany.window == alt.win) {
  1259.             wr = &alt;
  1260.             /* check in case we already destroyed the window */
  1261.             if (alt_stat < 0) { /* destroy upon exposure */
  1262.             alt_stat = 0;
  1263.             handle_release();
  1264.             continue;
  1265.             }
  1266.             else
  1267.             alt_stat = 0;
  1268.         }
  1269.         switch (event.type) {
  1270.         case GraphicsExpose:
  1271.         case Expose:
  1272.             expose(wr, event.xexpose.x, event.xexpose.y,
  1273.             event.xexpose.width, event.xexpose.height);
  1274.             break;
  1275.  
  1276.         case MotionNotify:
  1277.             new_mag_x = event.xmotion.x;
  1278.             new_mag_y = event.xmotion.y;
  1279.             mag_moved = (new_mag_x != mag_x || new_mag_y != mag_y);
  1280.             break;
  1281.  
  1282.         case ButtonPress:
  1283.             handle_button(&event.xbutton);
  1284.             break;
  1285.  
  1286.         case ButtonRelease:
  1287.             handle_release();
  1288.             break;
  1289.         }    /* end switch */
  1290.         }    /* end if window == {mane,alt}.win */
  1291.  
  1292.         else if (event.xany.window == x_bar) {
  1293.         if (event.type == Expose)
  1294.             XFillRectangle(DISP, x_bar, ruleGC,
  1295.             x_bgn, 1, x_end - x_bgn, BAR_WID);
  1296.         else if (event.type == MotionNotify)
  1297.             scrollmane(event.xmotion.x * page_w / clip_w,
  1298.             mane.base_y);
  1299.         else switch (event.xbutton.button)
  1300.         {
  1301.             case 1:
  1302.             scrollmane(mane.base_x + event.xbutton.x, mane.base_y);
  1303.             break;
  1304.             case 2:
  1305.             scrollmane(event.xbutton.x * page_w / clip_w,
  1306.                 mane.base_y);
  1307.             break;
  1308.             case 3:
  1309.             scrollmane(mane.base_x - event.xbutton.x, mane.base_y);
  1310.         }
  1311.         }
  1312.  
  1313.         else if (event.xany.window == y_bar) {
  1314.         if (event.type == Expose)
  1315.             XFillRectangle(DISP, y_bar, ruleGC,
  1316.             1, y_bgn, BAR_WID, y_end - y_bgn);
  1317.         else if (event.type == MotionNotify)
  1318.             scrollmane(mane.base_x,
  1319.             event.xmotion.y * page_h / clip_h);
  1320.         else switch (event.xbutton.button)
  1321.         {
  1322.             case 1:
  1323.             scrollmane(mane.base_x, mane.base_y + event.xbutton.y);
  1324.             break;
  1325.             case 2:
  1326.             scrollmane(mane.base_x,
  1327.                 event.xbutton.y * page_h / clip_h);
  1328.             break;
  1329.             case 3:
  1330.             scrollmane(mane.base_x, mane.base_y - event.xbutton.y);
  1331.         }
  1332.         }
  1333.  
  1334.         else if (event.xany.window == top_level)
  1335.         switch (event.type) {
  1336.         case ConfigureNotify:
  1337.             if (event.xany.window == top_level &&
  1338.             (event.xconfigure.width != window_w ||
  1339.             event.xconfigure.height != window_h)) {
  1340.                 register Window old_mane_win = mane.win;
  1341.  
  1342.                 window_w = event.xconfigure.width;
  1343.                 window_h = event.xconfigure.height;
  1344.                 reconfig();
  1345.                 if (old_mane_win == (Window) 0) home(False);
  1346.             }
  1347.             break;
  1348.  
  1349.         case MapNotify:        /* if running w/o WM */
  1350.             if (mane.win == (Window) 0) {
  1351.             reconfig();
  1352.             home(False);
  1353.             }
  1354.             break;
  1355.  
  1356.         case KeyPress:
  1357.             string = trbuf;
  1358.             nbytes = XLookupString(&event.xkey, string, TRSIZE, NULL,
  1359.             NULL);
  1360.             if (nbytes != 0) ch = *string;
  1361.             if (nbytes > 1) ch = '?';
  1362.             break;
  1363.         }
  1364. #endif    /* TOOLKIT */
  1365.         if (ch == '\0') continue;
  1366.         if (ch >= '0' && ch <= '9') {
  1367.         has_arg = True;
  1368.         number = number * 10 + sign * (ch - '0');
  1369.         continue;
  1370.         }
  1371.         else if (ch == '-') {
  1372.         has_arg = True;
  1373.         sign = -1;
  1374.         number = 0;
  1375.         continue;
  1376.         }
  1377.         number0 = number;
  1378.         number = 0;
  1379.         sign = 1;
  1380.         arg0 = has_arg;
  1381.         has_arg = False;
  1382.         keystroke(ch, number0, arg0, &event);
  1383.     }
  1384. }
  1385.  
  1386. static    void
  1387. redraw(windowrec)
  1388.     struct WindowRec *windowrec;
  1389. {
  1390.  
  1391.     currwin = *windowrec;
  1392.     min_x = currwin.min_x + currwin.base_x;
  1393.     min_y = currwin.min_y + currwin.base_y;
  1394.     max_x = currwin.max_x + currwin.base_x;
  1395.     max_y = currwin.max_y + currwin.base_y;
  1396.     can_exposures(windowrec);
  1397.  
  1398.     if (debug & DBG_EVENT)
  1399.         Printf("Redraw %d x %d at (%d, %d) (base=%d,%d)\n", max_x - min_x,
  1400.         max_y - min_y, min_x, min_y, currwin.base_x, currwin.base_y);
  1401.     XDefineCursor(DISP, mane.win, redraw_cursor);
  1402.     XFlush(DISP);
  1403.     if (setjmp(dvi_env)) {
  1404.         XClearWindow(DISP, mane.win);
  1405.         get_xy();
  1406.         XDrawString(DISP, mane.win, foreGC,
  1407.         5 - window_x, 5 + X11HEIGHT - window_y,
  1408.         dvi_oops_msg, strlen(dvi_oops_msg));
  1409.         if (dvi_file) {
  1410.         Fclose(dvi_file);
  1411.         dvi_file = NULL;
  1412.         }
  1413.     }
  1414.     else {
  1415.         draw_page();
  1416.         hush_spec_now = True;
  1417.     }
  1418. }
  1419.  
  1420. void
  1421. redraw_page()
  1422. {
  1423.     if (debug & DBG_EVENT) Fputs("Redraw page:  ", stdout);
  1424.     XClearWindow(DISP, mane.win);
  1425.     if (backing_store != NotUseful) {
  1426.         mane.min_x = mane.min_y = 0;
  1427.         mane.max_x = page_w;
  1428.         mane.max_y = page_h;
  1429.     }
  1430.     else {
  1431.         get_xy();
  1432.         mane.min_x = -window_x;
  1433.         mane.max_x = -window_x + clip_w;
  1434.         mane.min_y = -window_y;
  1435.         mane.max_y = -window_y + clip_h;
  1436.     }
  1437.     redraw(&mane);
  1438. }
  1439.  
  1440. /*
  1441.  *    Interrupt system for receiving events.  The program sets a flag
  1442.  *    whenever an event comes in, so that at the proper time (i.e., when
  1443.  *    reading a new dvi item), we can check incoming events to see if we
  1444.  *    still want to go on printing this page.  This way, one can stop
  1445.  *    displaying a page if it is about to be erased anyway.  We try to read
  1446.  *    as many events as possible before doing anything and base the next
  1447.  *    action on all events read.
  1448.  *    Note that the Xlib and Xt routines are not reentrant, so the most we
  1449.  *    can do is set a flag in the interrupt routine and check it later.
  1450.  *    Also, sometimes the interrupts are not generated (some systems only
  1451.  *    guarantee that SIGIO is generated for terminal files, and on the system
  1452.  *    I use, the interrupts are not generated if I use "(xdvi foo &)" instead
  1453.  *    of "xdvi foo").  Therefore, there is also a mechanism to check the
  1454.  *    event queue every 70 drawing operations or so.  This mechanism is
  1455.  *    disabled if it turns out that the interrupts do work.
  1456.  *    For a fuller discussion of some of the above, see xlife in
  1457.  *    comp.sources.x.
  1458.  */
  1459.  
  1460. static    void
  1461. can_exposures(windowrec)
  1462.     struct WindowRec *windowrec;
  1463. {
  1464.     windowrec->min_x = windowrec->min_y = MAXDIM;
  1465.     windowrec->max_x = windowrec->max_y = 0;
  1466. }
  1467.  
  1468. #if    HAS_SIGIO
  1469. /* ARGSUSED */
  1470. static    void
  1471. handle_intr(signo)
  1472.     int    signo;
  1473. {
  1474.     event_counter = 1;
  1475.     event_freq = -1;    /* forget Plan B */
  1476. }
  1477.  
  1478. static    void
  1479. enable_intr() {
  1480.     int    socket    = ConnectionNumber(DISP);
  1481.  
  1482. #ifdef SA_RESTART
  1483.     /* Subprocess handling, e.g., MakeTeXPK, fails on the Alpha without
  1484.        this, because SIGIO interrupts the call of system(3), since OSF/1
  1485.        doesn't retry interrupted wait calls by default.  From code by
  1486.        maj@cl.cam.ac.uk.  */
  1487.     {
  1488.           struct sigaction a;
  1489.           a.sa_handler = handle_intr;
  1490.           sigemptyset (&a.sa_mask);
  1491.           sigaddset (&a.sa_mask, SIGIO);
  1492.           a.sa_flags = SA_RESTART;
  1493.           sigaction (SIGIO, &a, NULL);
  1494.         }
  1495. #else
  1496.         (void) signal(SIGIO, handle_intr);
  1497. #endif /* SA_RESTART */
  1498.     (void) fcntl(socket, F_SETOWN, getpid());
  1499.     (void) fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, 0) | FASYNC);
  1500. }
  1501. #endif    /* HAS_SIGIO */
  1502.  
  1503. void
  1504. do_pages()
  1505. {
  1506.     if (debug & DBG_BATCH) {
  1507. #ifdef    TOOLKIT
  1508.         while (mane.min_x == MAXDIM) read_events(True);
  1509. #else    /* !TOOLKIT */
  1510.         while (mane.min_x == MAXDIM)
  1511.         if (setjmp(canit_env)) break;
  1512.         else read_events(True);
  1513. #endif    /* TOOLKIT */
  1514.         for (current_page = 0; current_page < total_pages; ++current_page)
  1515.         redraw_page();
  1516.     }
  1517.     else {    /* normal operation */
  1518. #if    HAS_SIGIO
  1519.         enable_intr();
  1520. #endif
  1521. #ifdef    __convex__
  1522.         /* convex C turns off optimization for the entire function
  1523.            if setjmp return value is discarded.*/
  1524.         if (setjmp(canit_env))    /*optimize me*/;
  1525. #else
  1526.         (void) setjmp(canit_env);
  1527. #endif
  1528.         for (;;) {
  1529.         if (mane.win != (Window) 0)
  1530.             XDefineCursor(DISP, mane.win, ready_cursor);
  1531.         read_events(True);
  1532.         if (canit) {
  1533.             canit = False;
  1534.             can_exposures(&mane);
  1535.             can_exposures(&alt);
  1536.             redraw_page();
  1537.         }
  1538.         else if (mag_moved) {
  1539.             if (alt.win == (Window) 0) mag_moved = False;
  1540.             else if (abs(new_mag_x - mag_x) >
  1541.             2 * abs(new_mag_y - mag_y))
  1542.                 movemag(new_mag_x, mag_y);
  1543.             else if (abs(new_mag_y - mag_y) >
  1544.             2 * abs(new_mag_x - mag_x))
  1545.                 movemag(mag_x, new_mag_y);
  1546.             else movemag(new_mag_x, new_mag_y);
  1547.         }
  1548.         else if (alt.min_x < MAXDIM) redraw(&alt);
  1549.         else if (mane.min_x < MAXDIM) redraw(&mane);
  1550.         XFlush(DISP);
  1551.         }
  1552.     }
  1553. }
  1554.