This is events.c in view mode; [Download] [Up]
/* * 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> /* to get a prototype for pow() */ #include <math.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) { /* math.h should know this declaration better */ #if 0 double pow(); #endif 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) { #if defined (POINTER_IS_NOT_INT) register long coord = (page_w - clip_w) / 2; #else register int coord = (page_w - clip_w) / 2; #endif /* POINTER_IS_NOT_INT */ if (coord > home_x / mane.shrinkfactor) coord = home_x / mane.shrinkfactor; XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (window_x + coord)); } if (y_bar != NULL) { #if defined (POINTER_IS_NOT_INT) register long coord = (page_h - clip_h) / 2; #else register int coord = (page_h - clip_h) / 2; #endif /* POINTER_IS_NOT_INT */ 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) #ifdef POINTER_IS_NOT_INT long x,y; #else int x, y; #endif /* POINTER_IS_NOT_INT */ { /* 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; #ifdef POINTER_IS_NOT_INT XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (-2 * (long) clip_w / 3)); #else XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (-2 * (int) clip_w / 3)); #endif /* POINTER_IS_NOT_INT */ return; case 'r': if (!x_bar) goto bad; #ifdef POINTER_IS_NOT_INT XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (2 * (long) clip_w / 3)); #else XtCallCallbacks(x_bar, XtNscrollProc, (XtPointer) (2 * (int) clip_w / 3)); #endif /* POINTER_IS_NOT_INT */ return; case 'u': if (!y_bar) goto bad; #ifdef POINTER_IS_NOT_INT XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (-2 * (long) clip_h / 3)); #else XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (-2 * (int) clip_h / 3)); #endif /* POINTER_IS_NOT_INT */ return; case 'd': if (!y_bar) goto bad; #ifdef POINTER_IS_NOT_INT XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (2 * (long) clip_h / 3)); #else XtCallCallbacks(y_bar, XtNscrollProc, (XtPointer) (2 * (int) clip_h / 3)); #endif /* POINTER_IS_NOT_INT */ 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); } } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.