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 >
Wrap
C/C++ Source or Header
|
1996-09-28
|
40KB
|
1,554 lines
/*
* Copyright (c) 1994 Paul Vojta. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* NOTE:
* xdvi is based on prior work as noted in the modification history, below.
*/
/*
* DVI previewer for X.
*
* Eric Cooper, CMU, September 1985.
*
* Code derived from dvi-imagen.c.
*
* Modification history:
* 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
* 7/1988 Modified for X.11 --Mark Eichin, MIT
* 12/1988 Added 'R' option, toolkit, magnifying glass
* --Paul Vojta, UC Berkeley.
* 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
* 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
* 3/1990 Added VMS support --Scott Allendorf, U of Iowa
* 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
* 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
* and Lee Hetherington, MIT
* 4/1994 Added DPS support, bounding box
* --Ricardo Telichevesky
* and Luis Miguel Silveira, MIT RLE.
*/
#include <config.h>
/* Xlib and Xutil are already included */
#ifdef TOOLKIT
#ifdef OLD_X11_TOOLKIT
#include <X11/Atoms.h>
#else /* not OLD_X11_TOOLKIT */
#include <X11/Xatom.h>
#include <X11/StringDefs.h>
#endif /* not OLD_X11_TOOLKIT */
#include <X11/Shell.h> /* needed for def. of XtNiconX */
#ifndef XtSpecificationRelease
#define XtSpecificationRelease 0
#endif
#if XtSpecificationRelease >= 4
#include <X11/Xaw/Viewport.h>
#ifdef BUTTONS
#include <X11/Xaw/Command.h>
#endif
#else /* XtSpecificationRelease < 4 */
#define XtPointer caddr_t
#include <X11/Viewport.h>
#ifdef BUTTONS
#include <X11/Command.h>
#endif
#endif /* XtSpecificationRelease */
#else /* !TOOLKIT */
typedef int Position;
#define XtPending() XPending(DISP)
#endif /* TOOLKIT */
#if HAS_SIGIO
#include <fcntl.h>
#include <signal.h>
#ifndef FASYNC
#undef HAS_SIGIO
#define HAS_SIGIO 0
#endif
#endif
#ifndef X11HEIGHT
#define X11HEIGHT 8 /* Height of server default font */
#endif
#define MAGBORD 1 /* border size for magnifier */
/*
* Command line flags.
*/
#define fore_Pixel resource._fore_Pixel
#define back_Pixel resource._back_Pixel
#ifdef TOOLKIT
extern struct _resource resource;
#define brdr_Pixel resource._brdr_Pixel
#endif /* TOOLKIT */
static int pageno_correct = 1;
static Boolean colors_allocated = False;
#define clip_w mane.width
#define clip_h mane.height
static Position main_x, main_y;
static Position mag_x, mag_y, new_mag_x, new_mag_y;
static Boolean mag_moved = False;
#ifdef TOOLKIT
#ifdef BUTTONS
static Widget line_widget, panel_widget;
#endif
static Widget x_bar, y_bar; /* horizontal and vertical scroll bars */
static Arg resize_args[] = {
{XtNwidth, (XtArgVal) 0},
{XtNheight, (XtArgVal) 0},
};
#define XdviResizeWidget(widget, w, h) \
(resize_args[0].value = (XtArgVal) (w), \
resize_args[1].value = (XtArgVal) (h), \
XtSetValues(widget, resize_args, XtNumber(resize_args)) )
#ifdef BUTTONS
static Arg resizable_on[] = {
{XtNresizable, (XtArgVal) True},
};
static Arg resizable_off[] = {
{XtNresizable, (XtArgVal) False},
};
static Arg line_args[] = {
{XtNbackground, (XtArgVal) 0},
{XtNwidth, (XtArgVal) 1},
{XtNheight, (XtArgVal) 0},
{XtNfromHoriz, (XtArgVal) NULL},
{XtNborderWidth, (XtArgVal) 0},
{XtNtop, (XtArgVal) XtChainTop},
{XtNbottom, (XtArgVal) XtChainBottom},
{XtNleft, (XtArgVal) XtChainRight},
{XtNright, (XtArgVal) XtChainRight},
};
static Arg panel_args[] = {
{XtNfromHoriz, (XtArgVal) NULL},
{XtNwidth, (XtArgVal) (XTRA_WID - 1)},
{XtNheight, (XtArgVal) 0},
{XtNborderWidth, (XtArgVal) 0},
{XtNtop, (XtArgVal) XtChainTop},
{XtNbottom, (XtArgVal) XtChainBottom},
{XtNleft, (XtArgVal) XtChainRight},
{XtNright, (XtArgVal) XtChainRight},
};
static struct {
_Xconst char *label;
_Xconst char *name;
int closure;
int y_pos;
}
command_table[] = {
#ifdef SELFILE
/* Reposition "Quit" button to fit "File" button in JSP */
{"Quit", "quit", 'q', 10},
{"File", "file", 'F', 60},
#else /* SELFILE */
{"Quit", "quit", 'q', 50},
#endif /* SELFILE */
{"Shrink1", "sh1", 1 << 8 | 's', 150},
{"Shrink2", "sh2", 2 << 8 | 's', 200},
{"Shrink3", "sh3", 3 << 8 | 's', 250},
{"Shrink4", "sh4", 4 << 8 | 's', 300},
{"Page-10", "prev10", 10 << 8 | 'p', 400},
{"Page-5", "prev5", 5 << 8 | 'p', 450},
{"Prev", "prev", 'p', 500},
{"Next", "next", 'n', 600},
{"Page+5", "next5", 5 << 8 | 'n', 650},
{"Page+10", "next10", 10 << 8 | 'n', 700},
#if PS
{"View PS", "postscript", 'v', 750},
#endif
};
static void handle_command();
static XtCallbackRec command_call[] = {
{handle_command, NULL},
{NULL, NULL},
};
static Arg command_args[] = {
{XtNlabel, (XtArgVal) NULL},
{XtNx, (XtArgVal) 6},
{XtNy, (XtArgVal) 0},
{XtNwidth, (XtArgVal) 64},
{XtNheight, (XtArgVal) 30},
{XtNcallback, (XtArgVal) command_call},
};
void
create_buttons(h)
XtArgVal h;
{
int i;
line_args[0].value = (XtArgVal) resource._hl_Pixel;
line_args[2].value = h;
line_args[3].value = (XtArgVal) vport_widget;
line_widget = XtCreateManagedWidget("line", widgetClass, form_widget,
line_args, XtNumber(line_args));
panel_args[0].value = (XtArgVal) line_widget;
panel_args[2].value = h;
panel_widget = XtCreateManagedWidget("panel", compositeWidgetClass,
form_widget, panel_args, XtNumber(panel_args));
command_args[2].value = (XtArgVal) vport_widget;
for (i = 0; i < XtNumber(command_table); ++i) {
command_args[0].value = (XtArgVal) command_table[i].label;
command_args[2].value = (XtArgVal) command_table[i].y_pos;
command_call[0].closure = (XtPointer) &command_table[i].closure;
(void) XtCreateManagedWidget(command_table[i].name,
commandWidgetClass, panel_widget,
command_args, XtNumber(command_args));
}
}
#endif /* BUTTONS */
#else /* !TOOLKIT */
static Window x_bar, y_bar;
static int x_bgn, x_end, y_bgn, y_end; /* scrollbar positions */
#endif /* TOOLKIT */
/*
* Mechanism to keep track of the magnifier window. The problems are,
* (a) if the button is released while the window is being drawn, this
* could cause an X error if we continue drawing in it after it is
* destroyed, and
* (b) creating and destroying the window too quickly confuses the window
* manager, which is avoided by waiting for an expose event before
* destroying it.
*/
static short alt_stat; /* 1 = wait for expose, */
/* -1 = destroy upon expose */
static Boolean alt_canit; /* stop drawing this window */
/*
* Data for buffered events.
*/
static Boolean has_arg = False;
static VOLATILE short event_freq = 70;
static int number = 0;
static int sign = 1;
static void can_exposures(), keystroke();
#ifdef GREY
#define gamma resource._gamma
void
init_pix(warn)
Boolean warn;
{
static int shrink_allocated_for = 0;
int i;
if (!colors_allocated)
{
Pixel plane_masks[4];
Pixel pixel;
XColor color, fc, bc;
XGCValues values;
if (gamma == 0.0) gamma = 1.0;
if (!resource.copy)
/* allocate 4 color planes for 16 colors (for GXor drawing) */
if (!XAllocColorCells(DISP, DefaultColormapOfScreen(SCRN),
False, plane_masks, 4, &pixel, 1))
resource.copy = warn = True;
/* get foreground and background RGB values for interpolating */
fc.pixel = fore_Pixel;
XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &fc);
bc.pixel = back_Pixel;
XQueryColor(DISP, DefaultColormapOfScreen(SCRN), &bc);
for (i = 0; i < 16; ++i) {
double pow();
double frac = gamma > 0 ? pow((double) i / 15, 1 / gamma)
: 1 - pow((double) (15 - i) / 15, -gamma);
color.red = frac * ((double) fc.red - bc.red) + bc.red;
color.green = frac * ((double) fc.green - bc.green) + bc.green;
color.blue = frac * ((double) fc.blue - bc.blue) + bc.blue;
color.pixel = pixel;
color.flags = DoRed | DoGreen | DoBlue;
if (!resource.copy) {
if (i & 1) color.pixel |= plane_masks[0];
if (i & 2) color.pixel |= plane_masks[1];
if (i & 4) color.pixel |= plane_masks[2];
if (i & 8) color.pixel |= plane_masks[3];
XStoreColor(DISP, DefaultColormapOfScreen(SCRN), &color);
palette[i] = color.pixel;
}
else {
if (!XAllocColor(DISP, DefaultColormapOfScreen(SCRN),
&color))
palette[i] = (i * 100 >= density * 15)
? fore_Pixel : back_Pixel;
else
palette[i] = color.pixel;
}
}
/* Make sure fore_ and back_Pixel are a part of the palette */
fore_Pixel = palette[15];
back_Pixel = palette[0];
if (mane.win != (Window) 0)
XSetWindowBackground(DISP, mane.win, palette[0]);
#define MakeGC(fcn, fg, bg) (values.function = fcn, values.foreground=fg,\
values.background=bg,\
XCreateGC(DISP, RootWindowOfScreen(SCRN),\
GCFunction|GCForeground|GCBackground, &values))
foreGC = ruleGC = MakeGC(resource.copy ? GXcopy : GXor,
fore_Pixel, back_Pixel);
foreGC2 = NULL;
colors_allocated = True;
#ifdef TOOLKIT
#define CopyByDefault() (resource.copy && !resource.copy_arg)
#else
#define CopyByDefault() (resource.copy == 2)
#endif
/* warn only if copy was not explicitly requested */
if (CopyByDefault() && warn)
Puts("Note: overstrike characters may be incorrect.");
}
#undef MakeGC
if (mane.shrinkfactor == 1) return;
if (shrink_allocated_for < mane.shrinkfactor) {
if (pixeltbl != NULL) free((char *) pixeltbl);
pixeltbl = (Pixel *) xmalloc((unsigned)
(mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof(Pixel),
"pixel table");
shrink_allocated_for = mane.shrinkfactor;
}
for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i)
pixeltbl[i] =
palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
/ (2 * mane.shrinkfactor * mane.shrinkfactor)];
}
#endif /* GREY */
/*
* Event-handling routines
*/
static void
expose(windowrec, x, y, w, h)
register struct WindowRec *windowrec;
int x, y;
unsigned int w, h;
{
if (windowrec->min_x > x) windowrec->min_x = x;
if (windowrec->max_x < x + w)
windowrec->max_x = x + w;
if (windowrec->min_y > y) windowrec->min_y = y;
if (windowrec->max_y < y + h)
windowrec->max_y = y + h;
}
static void
clearexpose(windowrec, x, y, w, h)
struct WindowRec *windowrec;
int x, y;
unsigned int w, h;
{
XClearArea(DISP, windowrec->win, x, y, w, h, False);
expose(windowrec, x, y, w, h);
}
static void
scrollwindow(windowrec, x0, y0)
register struct WindowRec *windowrec;
int x0, y0;
{
int x, y;
int x2 = 0, y2 = 0;
int ww, hh;
x = x0 - windowrec->base_x;
y = y0 - windowrec->base_y;
ww = windowrec->width - x;
hh = windowrec->height - y;
windowrec->base_x = x0;
windowrec->base_y = y0;
if (currwin.win == windowrec->win) {
currwin.base_x = x0;
currwin.base_y = y0;
}
windowrec->min_x -= x;
if (windowrec->min_x < 0) windowrec->min_x = 0;
windowrec->max_x -= x;
if (windowrec->max_x > windowrec->width)
windowrec->max_x = windowrec->width;
windowrec->min_y -= y;
if (windowrec->min_y < 0) windowrec->min_y = 0;
windowrec->max_y -= y;
if (windowrec->max_y > windowrec->height)
windowrec->max_y = windowrec->height;
if (x < 0) {
x2 = -x;
x = 0;
ww = windowrec->width - x2;
}
if (y < 0) {
y2 = -y;
y = 0;
hh = windowrec->height - y2;
}
if (ww <= 0 || hh <= 0) {
XClearWindow(DISP, windowrec->win);
windowrec->min_x = windowrec->min_y = 0;
windowrec->max_x = windowrec->width;
windowrec->max_y = windowrec->height;
}
else {
XCopyArea(DISP, windowrec->win, windowrec->win,
DefaultGCOfScreen(SCRN), x, y,
(unsigned int) ww, (unsigned int) hh, x2, y2);
if (x > 0)
clearexpose(windowrec, ww, 0,
(unsigned int) x, windowrec->height);
if (x2 > 0)
clearexpose(windowrec, 0, 0,
(unsigned int) x2, windowrec->height);
if (y > 0)
clearexpose(windowrec, 0, hh,
windowrec->width, (unsigned int) y);
if (y2 > 0)
clearexpose(windowrec, 0, 0,
windowrec->width, (unsigned int) y2);
}
}
#ifdef TOOLKIT
/*
* routines for X11 toolkit
*/
static Arg arg_wh[] = {
{XtNwidth, (XtArgVal) &window_w},
{XtNheight, (XtArgVal) &window_h},
};
static Position window_x, window_y;
static Arg arg_xy[] = {
{XtNx, (XtArgVal) &window_x},
{XtNy, (XtArgVal) &window_y},
};
#define get_xy() XtGetValues(draw_widget, arg_xy, XtNumber(arg_xy))
#define mane_base_x 0
#define mane_base_y 0
void /* not static because SELFILE stuff in dvi_init.c needs it */
home(scrl)
Boolean scrl;
{
#if PS
psp.interrupt();
#endif
if (!scrl) XUnmapWindow(DISP, mane.win);
get_xy();
if (x_bar != NULL) {
register int coord = (page_w - clip_w) / 2;
if (coord > home_x / mane.shrinkfactor)
coord = home_x / mane.shrinkfactor;
XtCallCallbacks(x_bar, XtNscrollProc,
(XtPointer) (window_x + coord));
}
if (y_bar != NULL) {
register int coord = (page_h - clip_h) / 2;
if (coord > home_y / mane.shrinkfactor)
coord = home_y / mane.shrinkfactor;
XtCallCallbacks(y_bar, XtNscrollProc,
(XtPointer) (window_y + coord));
}
if (!scrl) {
XMapWindow(DISP, mane.win);
/* Wait for the server to catch up---this eliminates flicker. */
XSync(DISP, False);
}
}
static Boolean resized = False;
static void
get_geom()
{
static Dimension new_clip_w, new_clip_h;
static Arg arg_wh_clip[] = {
{XtNwidth, (XtArgVal) &new_clip_w},
{XtNheight, (XtArgVal) &new_clip_h},
};
register int old_clip_w;
XtGetValues(vport_widget, arg_wh, XtNumber(arg_wh));
XtGetValues(clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
/* Note: widgets may be destroyed but not forgotten */
x_bar = page_w <= new_clip_w ? NULL
: XtNameToWidget(vport_widget, "horizontal");
y_bar = page_h <= new_clip_h ? NULL
: XtNameToWidget(vport_widget, "vertical");
old_clip_w = clip_w;
/* we need to do this because */
/* sizeof(Dimension) != sizeof(int) */
clip_w = new_clip_w;
clip_h = new_clip_h;
if (old_clip_w == 0) home(False);
resized = False;
}
static void
center(x, y)
int x, y;
{
/* We use the clip widget here because it gives a more exact value. */
x -= clip_w/2;
y -= clip_h/2;
if (x_bar) XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) x);
if (y_bar) XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) y);
XWarpPointer(DISP, None, None, 0, 0, 0, 0, -x, -y);
}
/*
* callback routines
*/
/* The following callback routine should never be called. */
/*ARGSUSED*/
void
handle_key(widget, junk, event, cont)
Widget widget;
XtPointer junk;
XEvent *event;
Boolean *cont; /* unused */
{
XBell(DISP, 20);
}
/*ARGSUSED*/
void
handle_resize(widget, junk, event, cont)
Widget widget;
XtPointer junk;
XEvent *event;
Boolean *cont; /* unused */
{
resized = True;
}
#ifdef BUTTONS
/*ARGSUSED*/
static void
handle_command(widget, client_data_p, call_data)
Widget widget;
XtPointer client_data_p;
XtPointer call_data;
{
int client_data = * (int *) client_data_p;
keystroke((client_data) & 0xff, (client_data) >> 8,
((client_data) >> 8) != 0, (XEvent *) NULL);
}
#endif /* BUTTONS */
void
reconfig()
{
#ifdef BUTTONS
XtSetValues(vport_widget, resizable_off, XtNumber(resizable_off));
#endif
XdviResizeWidget(draw_widget, page_w, page_h);
get_geom();
}
#else /* !TOOLKIT */
/*
* brute force scrollbar routines
*/
static void
paint_x_bar()
{
register int new_x_bgn = mane.base_x * clip_w / page_w;
register int new_x_end = (mane.base_x + clip_w) * clip_w / page_w;
if (new_x_bgn >= x_end || x_bgn >= new_x_end) { /* no overlap */
XClearArea(DISP, x_bar, x_bgn, 1, x_end - x_bgn, BAR_WID, False);
XFillRectangle(DISP, x_bar, ruleGC,
new_x_bgn, 1, new_x_end - new_x_bgn, BAR_WID);
}
else { /* this stuff avoids flicker */
if (x_bgn < new_x_bgn)
XClearArea(DISP, x_bar, x_bgn, 1, new_x_bgn - x_bgn,
BAR_WID, False);
else
XFillRectangle(DISP, x_bar, ruleGC,
new_x_bgn, 1, x_bgn - new_x_bgn, BAR_WID);
if (new_x_end < x_end)
XClearArea(DISP, x_bar, new_x_end, 1, x_end - new_x_end,
BAR_WID, False);
else
XFillRectangle(DISP, x_bar, ruleGC,
x_end, 1, new_x_end - x_end, BAR_WID);
}
x_bgn = new_x_bgn;
x_end = new_x_end;
}
static void
paint_y_bar()
{
register int new_y_bgn = mane.base_y * clip_h / page_h;
register int new_y_end = (mane.base_y + clip_h) * clip_h / page_h;
if (new_y_bgn >= y_end || y_bgn >= new_y_end) { /* no overlap */
XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, y_end - y_bgn, False);
XFillRectangle(DISP, y_bar, ruleGC,
1, new_y_bgn, BAR_WID, new_y_end - new_y_bgn);
}
else { /* this stuff avoids flicker */
if (y_bgn < new_y_bgn)
XClearArea(DISP, y_bar, 1, y_bgn, BAR_WID, new_y_bgn - y_bgn,
False);
else
XFillRectangle(DISP, y_bar, ruleGC,
1, new_y_bgn, BAR_WID, y_bgn - new_y_bgn);
if (new_y_end < y_end)
XClearArea(DISP, y_bar, 1, new_y_end,
BAR_WID, y_end - new_y_end, False);
else
XFillRectangle(DISP, y_bar, ruleGC,
1, y_end, BAR_WID, new_y_end - y_end);
}
y_bgn = new_y_bgn;
y_end = new_y_end;
}
static void
scrollmane(x, y)
int x, y;
{
register int old_base_x = mane.base_x;
register int old_base_y = mane.base_y;
#if PS
psp.interrupt();
#endif
if (x > (int) (page_w - clip_w)) x = page_w - clip_w;
if (x < 0) x = 0;
if (y > (int) (page_h - clip_h)) y = page_h - clip_h;
if (y < 0) y = 0;
scrollwindow(&mane, x, y);
if (old_base_x != mane.base_x && x_bar) paint_x_bar();
if (old_base_y != mane.base_y && y_bar) paint_y_bar();
}
void
reconfig()
{
int x_thick = 0;
int y_thick = 0;
/* determine existence of scrollbars */
if (window_w < page_w) x_thick = BAR_THICK;
if (window_h - x_thick < page_h) y_thick = BAR_THICK;
clip_w = window_w - y_thick;
if (clip_w < page_w) x_thick = BAR_THICK;
clip_h = window_h - x_thick;
/* process drawing (clip) window */
if (mane.win == (Window) 0) { /* initial creation */
XWindowAttributes attrs;
mane.win = XCreateSimpleWindow(DISP, top_level, y_thick, x_thick,
(unsigned int) clip_w, (unsigned int) clip_h, 0,
brdr_Pixel, back_Pixel);
XSelectInput(DISP, mane.win, ExposureMask |
ButtonPressMask | ButtonMotionMask | ButtonReleaseMask);
(void) XGetWindowAttributes(DISP, mane.win, &attrs);
backing_store = attrs.backing_store;
XMapWindow(DISP, mane.win);
}
else
XMoveResizeWindow(DISP, mane.win, y_thick, x_thick, clip_w, clip_h);
/* process scroll bars */
if (x_thick) {
if (x_bar) {
XMoveResizeWindow(DISP, x_bar,
y_thick - 1, -1, clip_w, BAR_THICK - 1);
paint_x_bar();
}
else {
x_bar = XCreateSimpleWindow(DISP, top_level, y_thick - 1, -1,
(unsigned int) clip_w, BAR_THICK - 1, 1,
brdr_Pixel, back_Pixel);
XSelectInput(DISP, x_bar,
ExposureMask | ButtonPressMask | Button2MotionMask);
XMapWindow(DISP, x_bar);
}
x_bgn = mane.base_x * clip_w / page_w;
x_end = (mane.base_x + clip_w) * clip_w / page_w;
}
else
if (x_bar) {
XDestroyWindow(DISP, x_bar);
x_bar = (Window) 0;
}
if (y_thick) {
if (y_bar) {
XMoveResizeWindow(DISP, y_bar,
-1, x_thick - 1, BAR_THICK - 1, clip_h);
paint_y_bar();
}
else {
y_bar = XCreateSimpleWindow(DISP, top_level, -1, x_thick - 1,
BAR_THICK - 1, (unsigned int) clip_h, 1,
brdr_Pixel, back_Pixel);
XSelectInput(DISP, y_bar,
ExposureMask | ButtonPressMask | Button2MotionMask);
XMapWindow(DISP, y_bar);
}
y_bgn = mane.base_y * clip_h / page_h;
y_end = (mane.base_y + clip_h) * clip_h / page_h;
}
else
if (y_bar) {
XDestroyWindow(DISP, y_bar);
y_bar = (Window) 0;
}
}
static void
home(scrl)
Boolean scrl;
{
int x = 0, y = 0;
if (page_w > clip_w) {
x = (page_w - clip_w) / 2;
if (x > home_x / mane.shrinkfactor)
x = home_x / mane.shrinkfactor;
}
if (page_h > clip_h) {
y = (page_h - clip_h) / 2;
if (y > home_y / mane.shrinkfactor)
y = home_y / mane.shrinkfactor;
}
if (scrl)
scrollmane(x, y);
else {
mane.base_x = x;
mane.base_y = y;
if (currwin.win == mane.win) {
currwin.base_x = x;
currwin.base_y = y;
}
if (x_bar) paint_x_bar();
if (y_bar) paint_y_bar();
}
}
#define get_xy()
#define window_x 0
#define window_y 0
#define mane_base_x mane.base_x
#define mane_base_y mane.base_y
#endif /* TOOLKIT */
static void
compute_mag_pos(xp, yp)
int *xp, *yp;
{
register int t;
t = mag_x + main_x - alt.width/2;
if (t > WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD)
t = WidthOfScreen(SCRN) - (int) alt.width - 2*MAGBORD;
if (t < 0) t = 0;
*xp = t;
t = mag_y + main_y - alt.height/2;
if (t > HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD)
t = HeightOfScreen(SCRN) - (int) alt.height - 2*MAGBORD;
if (t < 0) t = 0;
*yp = t;
}
#ifdef TOOLKIT
/*ARGSUSED*/
void
handle_button(widget, junk, ev, cont)
Widget widget;
XtPointer junk;
XEvent *ev;
#define event (&(ev->xbutton))
Boolean *cont; /* unused */
#else /* !TOOLKIT */
void
handle_button(event)
XButtonEvent *event;
#endif /* TOOLKIT */
{
int x, y;
struct mg_size_rec *size_ptr = mg_size + event->button - 1;
XSetWindowAttributes attr;
if (alt.win != (Window) 0 || mane.shrinkfactor == 1 || size_ptr->w <= 0)
XBell(DISP, 20);
else {
mag_x = event->x;
mag_y = event->y;
alt.width = size_ptr->w;
alt.height = size_ptr->h;
main_x = event->x_root - mag_x;
main_y = event->y_root - mag_y;
compute_mag_pos(&x, &y);
alt.base_x = (event->x + mane_base_x) * mane.shrinkfactor -
alt.width/2;
alt.base_y = (event->y + mane_base_y) * mane.shrinkfactor -
alt.height/2;
attr.save_under = True;
attr.border_pixel = brdr_Pixel;
attr.background_pixel = back_Pixel;
attr.override_redirect = True;
alt.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
x, y, alt.width, alt.height, MAGBORD,
0, /* depth from parent */
InputOutput, (Visual *) CopyFromParent,
CWSaveUnder | CWBorderPixel | CWBackPixel |
CWOverrideRedirect, &attr);
XSelectInput(DISP, alt.win, ExposureMask);
XMapWindow(DISP, alt.win);
alt_stat = 1; /* waiting for exposure */
}
}
#ifdef TOOLKIT
#undef event
/*ARGSUSED*/
void
handle_motion(widget, junk, ev, cont)
Widget widget;
XtPointer junk;
XEvent *ev;
#define event (&(ev->xmotion))
Boolean *cont; /* unused */
{
new_mag_x = event->x;
main_x = event->x_root - new_mag_x;
new_mag_y = event->y;
main_y = event->y_root - new_mag_y;
mag_moved = (new_mag_x != mag_x || new_mag_y != mag_y);
}
#undef event
#endif /* TOOLKIT */
static void
movemag(x, y)
int x, y;
{
int xx, yy;
mag_x = x;
mag_y = y;
if (mag_x == new_mag_x && mag_y == new_mag_y) mag_moved = False;
compute_mag_pos(&xx, &yy);
XMoveWindow(DISP, alt.win, xx, yy);
scrollwindow(&alt,
(x + mane_base_x) * mane.shrinkfactor - (int) alt.width/2,
(y + mane_base_y) * mane.shrinkfactor - (int) alt.height/2);
}
#ifdef TOOLKIT
/*ARGSUSED*/
void
handle_release(widget, junk, ev, cont)
Widget widget;
XtPointer junk;
XEvent *ev;
#define event (&(ev->xbutton))
Boolean *cont; /* unused */
#else /* !TOOLKIT */
void
handle_release()
#endif /* TOOLKIT */
{
if (alt.win != (Window) 0)
if (alt_stat) alt_stat = -1; /* destroy upon expose */
else {
XDestroyWindow(DISP, alt.win);
if (currwin.win == alt.win) alt_canit = True;
alt.win = (Window) 0;
mag_moved = False;
can_exposures(&alt);
}
}
#ifdef TOOLKIT
#undef event
/*ARGSUSED*/
void
handle_exp(widget, closure, ev, cont)
Widget widget;
XtPointer closure;
register XEvent *ev;
#define event (&(ev->xexpose))
Boolean *cont; /* unused */
{
struct WindowRec *windowrec = (struct WindowRec *) closure;
if (windowrec == &alt)
if (alt_stat < 0) { /* destroy upon exposure */
alt_stat = 0;
handle_release(widget, (caddr_t) NULL, ev, (Boolean *) NULL);
return;
}
else
alt_stat = 0;
expose(windowrec, event->x, event->y,
(unsigned int) event->width, (unsigned int) event->height);
}
#undef event
#endif /* TOOLKIT */
/* |||
* Currently the event handler does not coordinate XCopyArea requests
* with GraphicsExpose events. This can lead to problems if the window
* is partially obscured and one, for example, drags a scrollbar.
*/
static void
keystroke(ch, number0, arg0, eventp)
char ch;
int number0;
Boolean arg0;
XEvent *eventp;
{
int next_page;
#ifdef TOOLKIT
Window ww;
#endif
next_page = current_page;
switch (ch) {
case 'q':
case '\003': /* control-C */
case '\004': /* control-D */
#ifdef VMS
case '\032': /* control-Z */
#endif
#if PS
psp.destroy();
#endif
exit(0);
case 'n':
case 'f':
case ' ':
case '\r':
case '\n':
/* scroll forward; i.e. go to relative page */
next_page = current_page + (arg0 ? number0 : 1);
break;
case 'p':
case 'b':
case '\b':
case '\177': /* Del */
/* scroll backward */
next_page = current_page - (arg0 ? number0 : 1);
break;
case 'g':
/* go to absolute page */
next_page = (arg0 ? number0 - pageno_correct :
total_pages - 1);
break;
case 'P': /* declare current page */
pageno_correct = arg0 * number0 - current_page;
return;
case 'k': /* toggle keep-position flag */
resource.keep_flag = (arg0 ? number0 : !resource.keep_flag);
return;
case '\f':
/* redisplay current page */
break;
case '^':
home(True);
return;
#ifdef TOOLKIT
case 'l':
if (!x_bar) goto bad;
XtCallCallbacks(x_bar, XtNscrollProc,
(XtPointer) (-2 * (int) clip_w / 3));
return;
case 'r':
if (!x_bar) goto bad;
XtCallCallbacks(x_bar, XtNscrollProc,
(XtPointer) (2 * (int) clip_w / 3));
return;
case 'u':
if (!y_bar) goto bad;
XtCallCallbacks(y_bar, XtNscrollProc,
(XtPointer) (-2 * (int) clip_h / 3));
return;
case 'd':
if (!y_bar) goto bad;
XtCallCallbacks(y_bar, XtNscrollProc,
(XtPointer) (2 * (int) clip_h / 3));
return;
case 'c':
center(eventp->xkey.x, eventp->xkey.y);
return;
case 'M':
(void) XTranslateCoordinates(DISP, eventp->xkey.window,
mane.win, eventp->xkey.x, eventp->xkey.y,
&home_x, &home_y, &ww); /* throw away last argument */
home_x *= mane.shrinkfactor;
home_y *= mane.shrinkfactor;
return;
#ifdef BUTTONS
case 'x':
if (arg0 && resource.expert == (number0 != 0)) return;
XtSetValues(vport_widget, resizable_on,
XtNumber(resizable_off));
if (resource.expert) { /* create buttons */
XdviResizeWidget(vport_widget,
window_w -= XTRA_WID, window_h);
create_buttons((XtArgVal) window_h);
resource.expert = False;
}
else { /* destroy buttons */
XtDestroyWidget(panel_widget);
XtDestroyWidget(line_widget);
XdviResizeWidget(vport_widget,
window_w += XTRA_WID, window_h);
resource.expert = True;
}
return;
#endif /* BUTTONS */
#else /* !TOOLKIT */
case 'l':
if (mane.base_x <= 0) goto bad;
scrollmane(mane.base_x - 2 * (int) clip_w / 3, mane.base_y);
return;
case 'r':
if (mane.base_x >= page_w - clip_w) goto bad;
scrollmane(mane.base_x + 2 * (int) clip_w / 3, mane.base_y);
return;
case 'u':
if (mane.base_y <= 0) goto bad;
scrollmane(mane.base_x, mane.base_y - 2 * (int) clip_h / 3);
return;
case 'd':
if (mane.base_y >= page_h - clip_h) goto bad;
scrollmane(mane.base_x, mane.base_y + 2 * (int) clip_h / 3);
return;
case 'c': /* unchecked scrollmane() */
scrollwindow(&mane, mane.base_x + eventp->xkey.x - clip_w/2,
mane.base_y + eventp->xkey.y - clip_h/2);
if (x_bar) paint_x_bar();
if (y_bar) paint_y_bar();
XWarpPointer(DISP, None, None, 0, 0, 0, 0,
clip_w/2 - eventp->xkey.x, clip_h/2 - eventp->xkey.y);
return;
case 'M':
home_x = (eventp->xkey.x - (y_bar ? BAR_THICK : 0)
+ mane.base_x) * mane.shrinkfactor;
home_y = (eventp->xkey.y - (x_bar ? BAR_THICK : 0)
+ mane.base_y) * mane.shrinkfactor;
return;
#endif /* TOOLKIT */
case '\020': /* Control P */
Printf("Unit = %d, bitord = %d, byteord = %d\n",
BitmapUnit(DISP), BitmapBitOrder(DISP),
ImageByteOrder(DISP));
return;
case 's':
if (!arg0) {
int temp;
number0 = ROUNDUP(unshrunk_page_w, window_w - 2);
temp = ROUNDUP(unshrunk_page_h, window_h - 2);
if (number0 < temp) number0 = temp;
}
if (number0 <= 0) goto bad;
if (number0 == mane.shrinkfactor) return;
mane.shrinkfactor = number0;
init_page();
if (number0 != 1 && number0 != bak_shrink) {
bak_shrink = number0;
#ifdef GREY
if (use_grey) init_pix(False);
#endif
reset_fonts();
}
reconfig();
home(False);
break;
case 'S':
if (!arg0) goto bad;
if (number0 < 0) goto bad;
if (number0 == density) return;
density = number0;
reset_fonts();
if (mane.shrinkfactor == 1) return;
break;
#ifdef GREY
case 'G':
use_grey = (arg0 ? number0 : !use_grey);
if (use_grey) {
if (arg0 && (number0 != 1)) {
gamma = number0 / 100.0;
colors_allocated = 0; /* Rethink this in init_pix. */
}
init_pix(False);
}
reset_fonts();
break;
#endif
#if PS
case 'v':
if (!arg0 || resource._postscript != !number0) {
resource._postscript = !resource._postscript;
psp.toggle();
}
break;
#endif
#ifdef SELFILE
case 'F':
++dvi_time ; /* notice we want a new file in check_dvi_file */
break ;
#endif /* SELFILE */
case 'R':
/* reread DVI file */
--dvi_time; /* then it will notice a change */
break;
default:
goto bad;
}
if (0 <= next_page && next_page < total_pages) {
if (current_page != next_page) {
current_page = next_page;
hush_spec_now = hush_spec;
if (!resource.keep_flag) home(False);
}
canit = True;
XFlush(DISP);
return; /* don't use longjmp here: it might be called from
* within the toolkit, and we don't want to longjmp out
* of Xt routines. */
}
bad: XBell(DISP, 10);
}
#define TRSIZE 100
void
read_events(wait)
wide_bool wait;
{
char ch;
Boolean arg0;
int number0;
XEvent event;
char trbuf[TRSIZE];
#define string xdvi_string /* kpathsea has a type `string', and cc chokes */
char *string;
int nbytes;
alt_canit = False;
for (;;) {
ch = '\0';
event_counter = event_freq;
/*
* The above line clears the flag indicating that an event is
* pending. So if an event comes in right now, the flag will be
* set again needlessly, but we just end up making an extra call.
* Also, be careful about destroying the magnifying glass while
* writing it.
*/
if (!XtPending() && (!wait || canit || mane.min_x < MAXDIM ||
alt.min_x < MAXDIM || mag_moved)) {
if (!wait && (canit | alt_canit)) {
#if PS
psp.interrupt();
#endif
if (allow_can) longjmp(canit_env, 1);
}
return;
}
#ifdef TOOLKIT
XtNextEvent(&event);
if (resized) get_geom();
if (event.xany.window == alt.win && event.type == Expose) {
handle_exp((Widget) NULL, (XtPointer) &alt, &event,
(Boolean *) NULL);
continue;
}
if (event.type != KeyPress) {
(void) XtDispatchEvent(&event);
continue;
}
string = trbuf;
nbytes = XLookupString(&event.xkey, string, TRSIZE, (KeySym *) NULL,
(XComposeStatus *) NULL);
if (nbytes > 1) ch = '?';
if (nbytes != 0) ch = *string;
#else /* !TOOLKIT */
XNextEvent(DISP, &event);
if (event.xany.window == mane.win || event.xany.window == alt.win) {
struct WindowRec *wr = &mane;
if (event.xany.window == alt.win) {
wr = &alt;
/* check in case we already destroyed the window */
if (alt_stat < 0) { /* destroy upon exposure */
alt_stat = 0;
handle_release();
continue;
}
else
alt_stat = 0;
}
switch (event.type) {
case GraphicsExpose:
case Expose:
expose(wr, event.xexpose.x, event.xexpose.y,
event.xexpose.width, event.xexpose.height);
break;
case MotionNotify:
new_mag_x = event.xmotion.x;
new_mag_y = event.xmotion.y;
mag_moved = (new_mag_x != mag_x || new_mag_y != mag_y);
break;
case ButtonPress:
handle_button(&event.xbutton);
break;
case ButtonRelease:
handle_release();
break;
} /* end switch */
} /* end if window == {mane,alt}.win */
else if (event.xany.window == x_bar) {
if (event.type == Expose)
XFillRectangle(DISP, x_bar, ruleGC,
x_bgn, 1, x_end - x_bgn, BAR_WID);
else if (event.type == MotionNotify)
scrollmane(event.xmotion.x * page_w / clip_w,
mane.base_y);
else switch (event.xbutton.button)
{
case 1:
scrollmane(mane.base_x + event.xbutton.x, mane.base_y);
break;
case 2:
scrollmane(event.xbutton.x * page_w / clip_w,
mane.base_y);
break;
case 3:
scrollmane(mane.base_x - event.xbutton.x, mane.base_y);
}
}
else if (event.xany.window == y_bar) {
if (event.type == Expose)
XFillRectangle(DISP, y_bar, ruleGC,
1, y_bgn, BAR_WID, y_end - y_bgn);
else if (event.type == MotionNotify)
scrollmane(mane.base_x,
event.xmotion.y * page_h / clip_h);
else switch (event.xbutton.button)
{
case 1:
scrollmane(mane.base_x, mane.base_y + event.xbutton.y);
break;
case 2:
scrollmane(mane.base_x,
event.xbutton.y * page_h / clip_h);
break;
case 3:
scrollmane(mane.base_x, mane.base_y - event.xbutton.y);
}
}
else if (event.xany.window == top_level)
switch (event.type) {
case ConfigureNotify:
if (event.xany.window == top_level &&
(event.xconfigure.width != window_w ||
event.xconfigure.height != window_h)) {
register Window old_mane_win = mane.win;
window_w = event.xconfigure.width;
window_h = event.xconfigure.height;
reconfig();
if (old_mane_win == (Window) 0) home(False);
}
break;
case MapNotify: /* if running w/o WM */
if (mane.win == (Window) 0) {
reconfig();
home(False);
}
break;
case KeyPress:
string = trbuf;
nbytes = XLookupString(&event.xkey, string, TRSIZE, NULL,
NULL);
if (nbytes != 0) ch = *string;
if (nbytes > 1) ch = '?';
break;
}
#endif /* TOOLKIT */
if (ch == '\0') continue;
if (ch >= '0' && ch <= '9') {
has_arg = True;
number = number * 10 + sign * (ch - '0');
continue;
}
else if (ch == '-') {
has_arg = True;
sign = -1;
number = 0;
continue;
}
number0 = number;
number = 0;
sign = 1;
arg0 = has_arg;
has_arg = False;
keystroke(ch, number0, arg0, &event);
}
}
static void
redraw(windowrec)
struct WindowRec *windowrec;
{
currwin = *windowrec;
min_x = currwin.min_x + currwin.base_x;
min_y = currwin.min_y + currwin.base_y;
max_x = currwin.max_x + currwin.base_x;
max_y = currwin.max_y + currwin.base_y;
can_exposures(windowrec);
if (debug & DBG_EVENT)
Printf("Redraw %d x %d at (%d, %d) (base=%d,%d)\n", max_x - min_x,
max_y - min_y, min_x, min_y, currwin.base_x, currwin.base_y);
XDefineCursor(DISP, mane.win, redraw_cursor);
XFlush(DISP);
if (setjmp(dvi_env)) {
XClearWindow(DISP, mane.win);
get_xy();
XDrawString(DISP, mane.win, foreGC,
5 - window_x, 5 + X11HEIGHT - window_y,
dvi_oops_msg, strlen(dvi_oops_msg));
if (dvi_file) {
Fclose(dvi_file);
dvi_file = NULL;
}
}
else {
draw_page();
hush_spec_now = True;
}
}
void
redraw_page()
{
if (debug & DBG_EVENT) Fputs("Redraw page: ", stdout);
XClearWindow(DISP, mane.win);
if (backing_store != NotUseful) {
mane.min_x = mane.min_y = 0;
mane.max_x = page_w;
mane.max_y = page_h;
}
else {
get_xy();
mane.min_x = -window_x;
mane.max_x = -window_x + clip_w;
mane.min_y = -window_y;
mane.max_y = -window_y + clip_h;
}
redraw(&mane);
}
/*
* Interrupt system for receiving events. The program sets a flag
* whenever an event comes in, so that at the proper time (i.e., when
* reading a new dvi item), we can check incoming events to see if we
* still want to go on printing this page. This way, one can stop
* displaying a page if it is about to be erased anyway. We try to read
* as many events as possible before doing anything and base the next
* action on all events read.
* Note that the Xlib and Xt routines are not reentrant, so the most we
* can do is set a flag in the interrupt routine and check it later.
* Also, sometimes the interrupts are not generated (some systems only
* guarantee that SIGIO is generated for terminal files, and on the system
* I use, the interrupts are not generated if I use "(xdvi foo &)" instead
* of "xdvi foo"). Therefore, there is also a mechanism to check the
* event queue every 70 drawing operations or so. This mechanism is
* disabled if it turns out that the interrupts do work.
* For a fuller discussion of some of the above, see xlife in
* comp.sources.x.
*/
static void
can_exposures(windowrec)
struct WindowRec *windowrec;
{
windowrec->min_x = windowrec->min_y = MAXDIM;
windowrec->max_x = windowrec->max_y = 0;
}
#if HAS_SIGIO
/* ARGSUSED */
static void
handle_intr(signo)
int signo;
{
event_counter = 1;
event_freq = -1; /* forget Plan B */
}
static void
enable_intr() {
int socket = ConnectionNumber(DISP);
#ifdef SA_RESTART
/* Subprocess handling, e.g., MakeTeXPK, fails on the Alpha without
this, because SIGIO interrupts the call of system(3), since OSF/1
doesn't retry interrupted wait calls by default. From code by
maj@cl.cam.ac.uk. */
{
struct sigaction a;
a.sa_handler = handle_intr;
sigemptyset (&a.sa_mask);
sigaddset (&a.sa_mask, SIGIO);
a.sa_flags = SA_RESTART;
sigaction (SIGIO, &a, NULL);
}
#else
(void) signal(SIGIO, handle_intr);
#endif /* SA_RESTART */
(void) fcntl(socket, F_SETOWN, getpid());
(void) fcntl(socket, F_SETFL, fcntl(socket, F_GETFL, 0) | FASYNC);
}
#endif /* HAS_SIGIO */
void
do_pages()
{
if (debug & DBG_BATCH) {
#ifdef TOOLKIT
while (mane.min_x == MAXDIM) read_events(True);
#else /* !TOOLKIT */
while (mane.min_x == MAXDIM)
if (setjmp(canit_env)) break;
else read_events(True);
#endif /* TOOLKIT */
for (current_page = 0; current_page < total_pages; ++current_page)
redraw_page();
}
else { /* normal operation */
#if HAS_SIGIO
enable_intr();
#endif
#ifdef __convex__
/* convex C turns off optimization for the entire function
if setjmp return value is discarded.*/
if (setjmp(canit_env)) /*optimize me*/;
#else
(void) setjmp(canit_env);
#endif
for (;;) {
if (mane.win != (Window) 0)
XDefineCursor(DISP, mane.win, ready_cursor);
read_events(True);
if (canit) {
canit = False;
can_exposures(&mane);
can_exposures(&alt);
redraw_page();
}
else if (mag_moved) {
if (alt.win == (Window) 0) mag_moved = False;
else if (abs(new_mag_x - mag_x) >
2 * abs(new_mag_y - mag_y))
movemag(new_mag_x, mag_y);
else if (abs(new_mag_y - mag_y) >
2 * abs(new_mag_x - mag_x))
movemag(mag_x, new_mag_y);
else movemag(new_mag_x, new_mag_y);
}
else if (alt.min_x < MAXDIM) redraw(&alt);
else if (mane.min_x < MAXDIM) redraw(&mane);
XFlush(DISP);
}
}
}