diff options
Diffstat (limited to 'Build/source/texk/xdvik/xdvi.c')
-rw-r--r-- | Build/source/texk/xdvik/xdvi.c | 4342 |
1 files changed, 4342 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/xdvi.c b/Build/source/texk/xdvik/xdvi.c new file mode 100644 index 00000000000..3a73f678394 --- /dev/null +++ b/Build/source/texk/xdvik/xdvi.c @@ -0,0 +1,4342 @@ +/*========================================================================*\ + +Copyright (c) 1990-2004 Paul Vojta and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL PAUL +VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +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 + * 7/1992 Added extra menu buttons--Nelson H. F. Beebe <beebe@math.utah.edu> + * 4/1994 Added DPS support, bounding box + * --Ricardo Telichevesky + * and Luis Miguel Silveira, MIT RLE. + * 2/1995 Added rulers support --Nelson H. F. Beebe <beebe@math.utah.edu> + * 1/2001 Added source specials --including ideas from Stefan Ulrich, + * U Munich + * + * Compilation options: + * + * VMS compile for VMS + * WORDS_BIGENDIAN store bitmaps internally with most significant bit first + * BMTYPE store bitmaps in unsigned BMTYPE + * BMBYTES sizeof(unsigned BMTYPE) + * ALTFONT default for -altfont option + * SHRINK default for -s option (shrink factor) + * MFMODE default for -mfmode option + * A4 use European size paper, and change default dimension to cm + * TEXXET support reflection dvi codes (right-to-left typesetting) + * GREY use grey levels to shrink fonts + * PS_GS use Ghostscript to render pictures/bounding boxes + * PS_DPS use display postscript to render pictures/bounding boxes + * PS_NEWS use the NeWS server to render pictures/bounding boxes + * GS_PATH path to call the Ghostscript interpreter by + * MAGICK use ImageMagick to render (external) image files + */ + + +#include "xdvi-config.h" +#include "xdvi.h" +#include "version.h" + +#include <locale.h> + +/* Xlib and Xutil are already included */ +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> /* needed for def. of XtNiconX */ + +#ifdef HAVE_X11_XMU_EDITRES_H +# include <X11/Xmu/Editres.h> +#endif + +/* to allow one common dependency file for Xaw/Motif, + we always include all the headers and have + #ifdef MOTIF + tests inside the headers. +*/ +#if defined(NEW_MENU_CREATION) || defined(MOTIF) +#include "menu.h" +#else +#include "xm_menu.h" +#include "xaw_menu.h" +#endif /* NEW_MENU_CREATION */ +#include "xm_toolbar.h" + +#ifdef T1LIB +#include "t1lib.h" +#endif /* T1LIB */ + +#ifdef MOTIF + +# include <Xm/Xm.h> +# include <Xm/Frame.h> +# include <Xm/PushB.h> +# include <Xm/MainW.h> +# include <Xm/ToggleB.h> +# include <Xm/RowColumn.h> +# include <Xm/ScrolledW.h> +# include <Xm/MenuShell.h> +# include <Xm/DrawingA.h> +# include <Xm/Form.h> +# include <Xm/PanedW.h> +# include <Xm/List.h> +# include <Xm/Protocols.h> + +# include <Xm/Display.h> + +# ifdef MOTIF11 /* FIXME: We'll probably need a config check for this? */ +/* used to set up XmStrings */ +XmStringCharSet G_charset = (XmStringCharSet)XmSTRING_DEFAULT_CHARSET; +# else +XmStringCharSet G_charset = XmFONTLIST_DEFAULT_TAG; +# endif + +#else /* MOTIF */ + +# include <X11/Xaw/Viewport.h> +# include <X11/Xaw/AsciiText.h> +# include <X11/Xaw/Box.h> +# include <X11/Xaw/Command.h> +# include <X11/Xaw/Dialog.h> +# include <X11/Xaw/Form.h> +# include <X11/Xaw/Paned.h> +# include <X11/Xaw/Scrollbar.h> +# include <X11/Xaw/Command.h> + +#endif /* MOTIF */ + +#include <signal.h> +#include <stdlib.h> +#include <ctype.h> + +#include "xserver-info.h" + +#include "kpathsea/c-fopen.h" +#include "kpathsea/c-pathch.h" +#include "kpathsea/c-stat.h" +#include "kpathsea/proginit.h" +#include "kpathsea/progname.h" +#include "kpathsea/tex-file.h" +#include "kpathsea/tex-hush.h" +#include "kpathsea/tex-make.h" +#include "string-utils.h" +#include "kpathsea/c-errno.h" +#include "kpathsea/expand.h" + +#include "translations.h" +#include "dvi-init.h" +#include "c-openmx.h" +#include "xicon.h" +#include "x_util.h" +#include "message-window.h" +#include "events.h" +#include "mag.h" +#include "pagesel.h" +#include "dvi-draw.h" +#include "statusline.h" +#include "util.h" +#include "my-snprintf.h" +#include "hypertex.h" +#include "xaw_menu.h" +#include "xdvi-debug.h" +#include "pagehist.h" +#include "filehist.h" +#include "sfSelFile.h" +#include "print-internal.h" +#include "xm_prefsP.h" /* for Xdvi_PREFS_BROWSER_DEFAULTS and Xdvi_PREFS_EDITOR_DEFAULTS */ + +#include "pixmaps/time16.xbm" +#include "pixmaps/time16_mask.xbm" +#ifdef VMS +# include "pixmaps/hand.xbm" +# include "pixmaps/hand_mask.xbm" +#endif +#include "pixmaps/magglass.xbm" +#include "pixmaps/magglass_mask.xbm" +#include "pixmaps/drag_vert.xbm" +#include "pixmaps/drag_vert_mask.xbm" +#include "pixmaps/drag_horiz.xbm" +#include "pixmaps/drag_horiz_mask.xbm" +#include "pixmaps/drag_omni.xbm" +#include "pixmaps/drag_omni_mask.xbm" + +#ifdef DEBUG +#include<asm/msr.h> +unsigned long time_start=0, time_end=0; +#endif + + +#ifdef MOTIF +#include <Xm/MwmUtil.h> + +#else /* MOTIF */ + +/* need to fake it */ + +/* bit definitions for MwmHints.flags */ +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) + +/* bit definitions for MwmHints.decorations */ +#define MWM_DECOR_ALL (1L << 0) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) + +struct PropMotifWmHints { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long inputMode; + unsigned long status; +}; + +#define PROP_MOTIF_WM_HINTS_ELEMENTS 5 + +#endif /* MOTIF */ + +char *dvi_property; /* for setting in window */ +size_t dvi_property_length; /* length of above, for efficiency */ +XImage *G_image; +int G_backing_store; +Display *DISP; +Screen *SCRN; +XtAccelerators G_accels_cr; + +#ifdef GREY +Visual *G_visual; +unsigned int G_depth; +Colormap G_colormap; +#else +# define G_depth (unsigned int) DefaultDepthOfScreen(SCRN) +# define G_visual DefaultVisualOfScreen(SCRN) +# define G_colormap DefaultColormapOfScreen(SCRN) +#endif + +/* global widgets */ + +#if defined(MOTIF) +Widget page_list, page_list_scroll; +#if USE_XAW_PANNER +#include "Panner.h" +Widget panner; +static Dimension g_save_shadow_thickness; +#endif +#endif + +static Atom mainDeleteWindow; + +#ifndef MOTIF +static Atom wmProtocols; +static void +handle_delete_message(Widget widget, XtPointer closure, XEvent *event, Boolean *cont) +{ + UNUSED(cont); + UNUSED(widget); + + ASSERT(closure == NULL, "handle_delete_message doesn't accept a non-NULL closure argument"); + if (event->type == ClientMessage + && event->xclient.message_type == wmProtocols + && (unsigned)(event->xclient.data.l[0]) == mainDeleteWindow) { + /* non-k xdvi also evaluates closure, but we don't, since it's a function pointer + which isn't convertible to void * in ANSI C */ + xdvi_exit(EXIT_SUCCESS); + } +} +#endif + +#ifdef TEST_SCROLLING +#warning ========== compiling with TEST_SCROLLING ========== +#endif + + +/* for measuring distance from the ruler */ +int g_ruler_pos_x, g_ruler_pos_y; + +Boolean ignore_papersize_specials = False; + +#ifndef ALTFONT +# define ALTFONT "cmr10" +#endif + +#ifndef SHRINK +# define SHRINK 8 +#endif + +#ifndef MFMODE +# define MFMODE NULL +#endif + +#undef MKTEXPK +#define MKTEXPK MAKEPK + +#if defined(PS_GS) && !defined(GS_PATH) +# define GS_PATH "gs" +#endif + +#if A4 +# define DEFAULT_PAPER "a4" +#else +# define DEFAULT_PAPER "us" +#endif + +/* + * Main application context, used for Xt event processing. + */ +XtAppContext app = NULL; + +static Dimension bwidth = 2; + +struct x_resources resource; + +struct program_globals globals; + +/* color of cursor */ +static XColor m_cursor_color; + +/* default magnifier dimensions */ +static struct mg_size_rec { + int w; + int h; +} mg_size[] = { + {200, 150}, {400, 250}, {700, 500}, {1000, 800}, {1200, 1200} +}; + +size_t get_magglass_items(void) { + return XtNumber(mg_size); +} + +int get_magglass_width(int idx) { + return mg_size[idx].w; +} + +int get_magglass_height(int idx) { + return mg_size[idx].h; +} + +struct WindowRec mane = { (Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0 }; + +/* currwin is temporary storage except for within redraw() */ +struct WindowRec currwin = { (Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0 }; + +/* + * Data for options processing. + */ +static const char SILENT[] = " "; /* flag value for usage() */ + +static const char SUBST[] = "x"; /* another flag value */ + +static const char USAGESTR_END_MARKER[] = "__USAGE_END_MARKER__"; /* end marker */ + +static const char *SUBST_VAL[] = { "-mgs[n] <size>" }; + +static XrmOptionDescRec options[] = { + {"-q", ".noInitFile", XrmoptionNoArg, (XPointer)"on" }, + {"+q", ".noInitFile", XrmoptionNoArg, (XPointer)"off" }, + {"-geometry", ".geometry", XrmoptionSepArg, (XPointer)NULL }, +#ifdef MOTIF + /* to make `-font' and `-fn' options work, make them an alias for `fontList' */ + { "-font", "*fontList", XrmoptionSepArg, (XPointer)NULL }, + { "-fn", "*fontList", XrmoptionSepArg, (XPointer)NULL }, +#endif + {"-s", ".shrinkFactor", XrmoptionSepArg, (XPointer)NULL }, +#ifndef VMS + {"-S", ".densityPercent", XrmoptionSepArg, (XPointer)NULL }, +#endif + {"-density", ".densityPercent", XrmoptionSepArg, (XPointer)NULL }, + {"-noomega", ".omega", XrmoptionNoArg, (XPointer)"off" }, + {"+noomega", ".omega", XrmoptionNoArg, (XPointer)"on" }, +#if COLOR + {"-nocolor", ".color", XrmoptionNoArg, (XPointer)"off" }, + {"+nocolor", ".color", XrmoptionNoArg, (XPointer)"on" }, +#endif +#ifdef GREY + {"-nogrey", ".grey", XrmoptionNoArg, (XPointer)"off" }, + {"+nogrey", ".grey", XrmoptionNoArg, (XPointer)"on" }, + {"-gamma", ".gamma", XrmoptionSepArg, (XPointer)NULL }, + {"-nomatchinverted",".matchInverted", XrmoptionNoArg, (XPointer)"off" }, + {"+nomatchinverted",".matchInverted", XrmoptionNoArg, (XPointer)"on" }, +/* {"-invertedfactor", ".invertedFactor", XrmoptionSepArg, (XPointer)NULL }, */ + {"-install", ".install", XrmoptionNoArg, (XPointer)"on" }, + {"-noinstall", ".install", XrmoptionNoArg, (XPointer)"off" }, +#endif + {"-rulecolor", ".ruleColor", XrmoptionSepArg, (XPointer)NULL }, + {"-p", ".pixelsPerInch", XrmoptionSepArg, (XPointer)NULL }, + {"-margins", ".Margin", XrmoptionSepArg, (XPointer)NULL }, + {"-sidemargin", ".sideMargin", XrmoptionSepArg, (XPointer)NULL }, + {"-topmargin", ".topMargin", XrmoptionSepArg, (XPointer)NULL }, + {"-offsets", ".Offset", XrmoptionSepArg, (XPointer)NULL }, + {"-xoffset", ".xOffset", XrmoptionSepArg, (XPointer)NULL }, + {"-yoffset", ".yOffset", XrmoptionSepArg, (XPointer)NULL }, + {"-paper", ".paper", XrmoptionSepArg, (XPointer)NULL }, + {"-altfont", ".altFont", XrmoptionSepArg, (XPointer)NULL }, +#ifdef MKTEXPK + {"-nomakepk", ".makePk", XrmoptionNoArg, (XPointer)"off" }, + {"+nomakepk", ".makePk", XrmoptionNoArg, (XPointer)"on" }, +#endif + {"-mfmode", ".mfMode", XrmoptionSepArg, (XPointer)NULL }, + {"-editor", ".editor", XrmoptionSepArg, (XPointer)NULL }, +#ifdef T1LIB + {"-not1lib", ".t1lib", XrmoptionNoArg, (XPointer)"off" }, + {"+not1lib", ".t1lib", XrmoptionNoArg, (XPointer)"on" }, +#endif + {"-sourceposition", ".sourcePosition", XrmoptionSepArg, (XPointer)NULL }, + {"-findstring", ".findString", XrmoptionSepArg, (XPointer)NULL }, + {"-text-encoding", ".textEncoding", XrmoptionSepArg, (XPointer)NULL }, + {"-unique", ".unique", XrmoptionNoArg, (XPointer)"on" }, + {"+unique", ".unique", XrmoptionNoArg, (XPointer)"off" }, + {"-nofork", ".fork", XrmoptionNoArg, (XPointer)"off" }, + {"+nofork", ".fork", XrmoptionNoArg, (XPointer)"on" }, +#ifdef RGB_ANTI_ALIASING + {"-subpixels", ".subPixels", XrmoptionSepArg, (XPointer)NULL }, +#endif + {"-l", ".listFonts", XrmoptionNoArg, (XPointer)"on" }, + {"+l", ".listFonts", XrmoptionNoArg, (XPointer)"off" }, + {"-watchfile", ".watchFile", XrmoptionSepArg, (XPointer)NULL }, + {"-expertmode", ".expertMode", XrmoptionSepArg, (XPointer)NULL }, + {"-expert", ".expert", XrmoptionNoArg, (XPointer)"on" }, + {"+expert", ".expert", XrmoptionNoArg, (XPointer)"off" }, + {"+statusline", ".statusline", XrmoptionNoArg, (XPointer)"off" }, + {"-statusline", ".statusline", XrmoptionNoArg, (XPointer)"on" }, + {"+useTeXpages", ".useTeXPages", XrmoptionNoArg, (XPointer)"off" }, + {"-useTeXpages", ".useTeXPages", XrmoptionNoArg, (XPointer)"on" }, + {"-mgs", ".magnifierSize1", XrmoptionSepArg, (XPointer)NULL }, + {"-mgs1", ".magnifierSize1", XrmoptionSepArg, (XPointer)NULL }, + {"-mgs2", ".magnifierSize2", XrmoptionSepArg, (XPointer)NULL }, + {"-mgs3", ".magnifierSize3", XrmoptionSepArg, (XPointer)NULL }, + {"-mgs4", ".magnifierSize4", XrmoptionSepArg, (XPointer)NULL }, + {"-mgs5", ".magnifierSize5", XrmoptionSepArg, (XPointer)NULL }, + {"-warnspecials", ".warnSpecials", XrmoptionNoArg, (XPointer)"on" }, + {"+warnspecials", ".warnSpecials", XrmoptionNoArg, (XPointer)"off" }, + {"-hush", ".Hush", XrmoptionNoArg, (XPointer)"on" }, + {"+hush", ".Hush", XrmoptionNoArg, (XPointer)"off" }, + {"-hushchars", ".hushLostChars", XrmoptionNoArg, (XPointer)"on" }, + {"+hushchars", ".hushLostChars", XrmoptionNoArg, (XPointer)"off" }, + {"-hushchecksums", ".hushChecksums", XrmoptionNoArg, (XPointer)"on" }, + {"+hushchecksums", ".hushChecksums", XrmoptionNoArg, (XPointer)"off" }, + {"-hushstdout", ".hushStdout", XrmoptionNoArg, (XPointer)"on" }, + {"+hushstdout", ".hushStdout", XrmoptionNoArg, (XPointer)"off" }, + {"-safer", ".safer", XrmoptionNoArg, (XPointer)"on" }, + {"+safer", ".safer", XrmoptionNoArg, (XPointer)"off" }, + {"-fg", ".foreground", XrmoptionSepArg, (XPointer)NULL }, + {"-foreground", ".foreground", XrmoptionSepArg, (XPointer)NULL }, + {"-bg", ".background", XrmoptionSepArg, (XPointer)NULL }, + {"-background", ".background", XrmoptionSepArg, (XPointer)NULL }, + {"-hl", ".highlight", XrmoptionSepArg, (XPointer)NULL }, + {"-cr", ".cursorColor", XrmoptionSepArg, (XPointer)NULL }, + {"-icongeometry", ".iconGeometry", XrmoptionSepArg, (XPointer)NULL }, + {"-keep", ".keepPosition", XrmoptionNoArg, (XPointer)"on" }, + {"+keep", ".keepPosition", XrmoptionNoArg, (XPointer)"off" }, + {"-copy", ".copy", XrmoptionNoArg, (XPointer)"on" }, + {"+copy", ".copy", XrmoptionNoArg, (XPointer)"off" }, + {"-thorough", ".thorough", XrmoptionNoArg, (XPointer)"on" }, + {"+thorough", ".thorough", XrmoptionNoArg, (XPointer)"off" }, + {"-fullscreen", ".fullscreen", XrmoptionNoArg, (XPointer)"on" }, + {"+fullscreen", ".fullscreen", XrmoptionNoArg, (XPointer)"off" }, + {"-pause", ".pause", XrmoptionNoArg, (XPointer)"on" }, + {"+pause", ".pause", XrmoptionNoArg, (XPointer)"off" }, + {"-pausespecial", ".pauseSpecial", XrmoptionSepArg, (XPointer)NULL }, + {"-wheelunit", ".wheelUnit", XrmoptionSepArg, (XPointer)NULL }, + {"-mousemode", ".mouseMode", XrmoptionSepArg, (XPointer)NULL }, +#ifdef PS + {"-postscript", ".postscript", XrmoptionSepArg, (XPointer)NULL }, + {"-allowshell", ".allowShell", XrmoptionNoArg, (XPointer)"on" }, + {"+allowshell", ".allowShell", XrmoptionNoArg, (XPointer)"off" }, +# ifdef PS_DPS + {"-nodps", ".dps", XrmoptionNoArg, (XPointer)"off" }, + {"+nodps", ".dps", XrmoptionNoArg, (XPointer)"on" }, +# endif +# ifdef PS_NEWS + {"-nonews", ".news", XrmoptionNoArg, (XPointer)"off" }, + {"+nonews", ".news", XrmoptionNoArg, (XPointer)"on" }, +# endif +# ifdef PS_GS + {"-noghostscript", ".ghostscript", XrmoptionNoArg, (XPointer)"off" }, + {"+noghostscript", ".ghostscript", XrmoptionNoArg, (XPointer)"on" }, + {"-nogssafer", ".gsSafer", XrmoptionNoArg, (XPointer)"off" }, + {"+nogssafer", ".gsSafer", XrmoptionNoArg, (XPointer)"on" }, + {"-gsalpha", ".gsAlpha", XrmoptionNoArg, (XPointer)"on" }, + {"+gsalpha", ".gsAlpha", XrmoptionNoArg, (XPointer)"off" }, + {"-interpreter", ".interpreter", XrmoptionSepArg, (XPointer)NULL }, + {"-gspalette", ".palette", XrmoptionSepArg, (XPointer)NULL }, +# endif +# ifdef MAGICK + {"-magick", ".ImageMagick", XrmoptionNoArg, (XPointer)"on" }, + {"+magick", ".ImageMagick", XrmoptionNoArg, (XPointer)"off" }, + {"-magick_cache", ".MagickCache", XrmoptionSepArg, (XPointer)NULL }, +# endif +#endif /* PS */ + {"-noscan", ".prescan", XrmoptionNoArg, (XPointer)"off" }, + {"+noscan", ".prescan", XrmoptionNoArg, (XPointer)"on" }, + {"-notempfile", ".tempFile", XrmoptionNoArg, (XPointer)"off" }, + {"+notempfile", ".tempFile", XrmoptionNoArg, (XPointer)"on" }, + {"-dvipspath", ".dvipsPath", XrmoptionSepArg, (XPointer)NULL }, + {"-ps2pdfpath", ".ps2pdfPath", XrmoptionSepArg, (XPointer)NULL }, + {"-debug", ".debugLevel", XrmoptionSepArg, (XPointer)NULL }, + {"-linkstyle", ".linkStyle", XrmoptionSepArg, (XPointer)NULL }, + {"-linkcolor", ".linkColor", XrmoptionSepArg, (XPointer)NULL }, + {"-visitedlinkcolor",".visitedLinkColor", XrmoptionSepArg, (XPointer)NULL }, + {"-browser", ".wwwBrowser", XrmoptionSepArg, (XPointer)NULL }, + {"-anchorposition", ".anchorPosition", XrmoptionSepArg, (XPointer)NULL }, +}; + + +#define offset(field) XtOffsetOf(struct x_resources, field) +static int base_tick_length = 4; + +static char XtRBool3[] = "Bool3"; /* resource for Bool3 */ + +static XtResource application_resources[] = { + {"regression", "Regression", XtRBoolean, sizeof(Boolean), + offset(regression), XtRString, "false"}, + {"geometry", "Geometry", XtRString, sizeof(char *), + offset(geometry), XtRString, (XtPointer) NULL}, + {"windowSize", "WindowSize", XtRString, sizeof(char *), + offset(windowsize), XtRString, (XtPointer) NULL}, + {"rememberWindowSize", "RememberWindowSize", XtRBoolean, sizeof(Boolean), + offset(remember_windowsize), XtRString, "false"}, + /* used to check whether app-defaults file is out of sync. Initialize + to a low default value (one before the resource was introduced) */ + {"appDefaultsFileVersion", "AppDefaultsFileVersion", XtRInt, sizeof(int), + offset(app_defaults_fileversion), XtRImmediate, (XtPointer)20030302 }, + {"shrinkFactor", "ShrinkFactor", XtRInt, sizeof(int), + offset(shrinkfactor), XtRImmediate, (XtPointer) SHRINK}, + {"delayRulers", "DelayRulers", XtRBoolean, sizeof(Boolean), + offset(delay_rulers), XtRString, "true"}, + {"useTeXPages", "UseTeXPages", XtRBoolean, sizeof(Boolean), + offset(use_tex_pages), XtRString, "false"}, + {"densityPercent", "DensityPercent", XtRInt, sizeof(int), + offset(density), XtRString, "40"}, + {"omega", "Omega", XtRBoolean, sizeof(Boolean), + offset(omega), XtRString, "true"}, + {"mainTranslations", "MainTranslations", XtRString, sizeof(char *), + offset(main_translations), XtRString, (XtPointer) NULL}, + {"wheelTranslations", "WheelTranslations", XtRString, sizeof(char *), + offset(wheel_translations), XtRString, (XtPointer) "<Btn4Down>:wheel(-0.2)\n<Btn5Down>:wheel(0.2)"}, + {"wheelUnit", "WheelUnit", XtRInt, sizeof(int), + offset(wheel_unit), XtRImmediate, (XtPointer) 80}, + {"mouseMode", "MouseMode", XtRInt, sizeof(int), + offset(mouse_mode), XtRImmediate, (XtPointer)MOUSE_MAGNIFIER_MODE}, +#ifdef GREY + {"gamma", "Gamma", XtRFloat, sizeof(float), + offset(gamma), XtRString, "1"}, +/* {"invertedFactor", "InvertedFactor", XtRFloat, sizeof(float), */ +/* offset(inverted_factor), XtRString, "3.0"}, */ +#endif + {"pixelsPerInch", "PixelsPerInch", XtRInt, sizeof(int), + offset(pixels_per_inch), XtRImmediate, (XtPointer) BDPI}, + {"sideMargin", "Margin", XtRString, sizeof(char *), + offset(sidemargin), XtRString, (XtPointer) NULL}, + {"tickLength", "TickLength", XtRInt, sizeof(int), + offset(tick_length), XtRInt, (XtPointer) & base_tick_length}, + {"tickUnits", "TickUnits", XtRString, sizeof(char *), + offset(tick_units), XtRString, "mm"}, + {"topMargin", "Margin", XtRString, sizeof(char *), + offset(topmargin), XtRString, (XtPointer) NULL}, + {"xOffset", "Offset", XtRString, sizeof(char *), + offset(xoffset), XtRString, (XtPointer) NULL}, + {"yOffset", "Offset", XtRString, sizeof(char *), + offset(yoffset), XtRString, (XtPointer) NULL}, + {"useCurrentOffset", "UseCurrentOffset", XtRBoolean, sizeof(Boolean), + offset(use_current_offset), XtRString, "False" }, + {"paper", "Paper", XtRString, sizeof(char *), + offset(paper), XtRString, (XtPointer) DEFAULT_PAPER}, + {"paperLandscape", "PaperLandscape", XtRBoolean, sizeof(Boolean), + offset(paper_landscape), XtRString, "false"}, + {"altFont", "AltFont", XtRString, sizeof(char *), + offset(alt_font), XtRString, (XtPointer) ALTFONT}, + {"makePk", "MakePk", XtRBoolean, sizeof(Boolean), + offset(makepk), XtRString, +#ifdef MAKE_TEX_PK_BY_DEFAULT + "true" +#else + "false" +#endif + }, + {"mfMode", "MfMode", XtRString, sizeof(char *), + offset(mfmode), XtRString, MFMODE}, + {"editor", "Editor", XtRString, sizeof(char *), + offset(editor), XtRString, (XtPointer) NULL}, +#ifdef T1LIB + {"t1lib", "T1lib", XtRBoolean, sizeof(Boolean), + offset(t1lib), XtRString, "true"}, +#endif + {"sourcePosition", "SourcePosition", XtRString, sizeof(char *), + offset(src_pos), XtRString, (XtPointer) NULL}, + {"findString", "FindString", XtRString, sizeof(char *), + offset(find_string), XtRString, (XtPointer) NULL}, + {"textEncoding", "TextEncoding", XtRString, sizeof(char *), + offset(text_encoding), XtRString, (XtPointer) NULL}, + {"fork", "Fork", XtRBoolean, sizeof(Boolean), + offset(src_fork), XtRString, "true"}, +#ifdef RGB_ANTI_ALIASING + {"subPixels", "SubPixels", XtRString, sizeof(char *), + offset(sub_pixels), XtRString, "Unknown"}, +#endif + {"noFileArgUseHistory", "NoFileArgUseHistory", XtRBoolean, sizeof(Boolean), + offset(no_file_arg_use_history), XtRString, "true"}, + {"fileHistory", "FileHistory", XtRString, sizeof(char *), + offset(file_history), XtRString, (XtPointer) NULL}, + {"fileHistorySize", "FileHistorySize", XtRInt, sizeof(int), + offset(file_history_size), XtRImmediate, (XtPointer)20}, + {"unique", "Unique", XtRBoolean, sizeof(Boolean), + offset(unique), XtRString, "false"}, + {"listFonts", "ListFonts", XtRBoolean, sizeof(Boolean), + offset(list_fonts), XtRString, "false"}, + {"reverseVideo", "ReverseVideo", XtRBoolean, sizeof(Boolean), + offset(reverse), XtRString, "false"}, + {"warnSpecials", "WarnSpecials", XtRBoolean, sizeof(Boolean), + offset(warn_spec), XtRString, "false"}, + {"hushLostChars", "Hush", XtRBoolean, sizeof(Boolean), + offset(hush_chars), XtRString, "false"}, + {"hushChecksums", "Hush", XtRBoolean, sizeof(Boolean), + offset(hush_chk), XtRString, "false"}, + {"hushStdout", "HushStdout", XtRBoolean, sizeof(Boolean), + offset(hush_stdout), XtRString, "false"}, + {"safer", "Safer", XtRBoolean, sizeof(Boolean), + offset(safer), XtRString, "false"}, +#ifdef VMS + {"foreground", "Foreground", XtRString, sizeof(char *), + offset(fore_color), XtRString, (XtPointer) NULL}, + {"background", "Background", XtRString, sizeof(char *), + offset(back_color), XtRString, (XtPointer) NULL}, +#endif + {"iconGeometry", "IconGeometry", XtRString, sizeof(char *), + offset(icon_geometry), XtRString, (XtPointer) NULL}, + {"keepPosition", "KeepPosition", XtRBoolean, sizeof(Boolean), + offset(keep_flag), XtRString, "false"}, +#ifdef PS + {"postscript", "Postscript", XtRInt, sizeof(int), + offset(postscript), XtRImmediate, (XtPointer)1}, + {"allowShell", "AllowShell", XtRBoolean, sizeof(Boolean), + offset(allow_shell), XtRString, "false"}, +# ifdef PS_DPS + {"dps", "DPS", XtRBoolean, sizeof(Boolean), + offset(useDPS), XtRString, "true"}, +# endif +# ifdef PS_NEWS + {"news", "News", XtRBoolean, sizeof(Boolean), + offset(useNeWS), XtRString, "true"}, +# endif +# ifdef PS_GS + {"ghostscript", "Ghostscript", XtRBoolean, sizeof(Boolean), + offset(useGS), XtRString, "true"}, + {"gsSafer", "Safer", XtRBoolean, sizeof(Boolean), + offset(gs_safer), XtRString, "true"}, + {"gsAlpha", "Alpha", XtRBoolean, sizeof(Boolean), + offset(gs_alpha), XtRString, "false"}, + {"interpreter", "Interpreter", XtRString, sizeof(char *), + offset(gs_path), XtRString, (XtPointer) GS_PATH}, + {"palette", "Palette", XtRString, sizeof(char *), + offset(gs_palette), XtRString, (XtPointer) "Color"}, + {"gsTimeout", "GSTimeout", XtRInt, sizeof(int), + offset(gs_timeout), XtRImmediate, (XtPointer)3000}, +# endif /* PS_GS */ +# ifdef MAGICK + {"magick", "ImageMagick", XtRBoolean, sizeof(Boolean), + offset(useMAGICK), XtRString, "true"}, + {"magick_cache", "MagickCache", XtRString, sizeof(char *), + offset(magick_cache), XtRString, (XtPointer) NULL}, +# endif +#endif /* PS */ + {"prescan", "Prescan", XtRBoolean, sizeof(Boolean), + offset(prescan), XtRString, "true"}, + {"tempFile", "TempFile", XtRBoolean, sizeof(Boolean), + offset(use_temp_fp), XtRString, "true"}, + {"copy", "Copy", XtRBoolean, sizeof(Boolean), + offset(copy), XtRString, "false"}, + {"thorough", "Thorough", XtRBoolean, sizeof(Boolean), + offset(thorough), XtRString, "false"}, + {"fullscreen", "Fullscreen", XtRBoolean, sizeof(Boolean), + offset(fullscreen), XtRString, "false"}, + {"pause", "Pause", XtRBoolean, sizeof(Boolean), + offset(pause), XtRString, "false"}, + {"pauseSpecial", "PauseSpecial", XtRString, sizeof(char *), + offset(pause_special), XtRString, (XtPointer)"xdvi:pause"}, + {"debugLevel", "DebugLevel", XtRString, sizeof(char *), + offset(debug_arg), XtRString, (XtPointer) NULL}, + {"menuTranslations", "MenuTranslations", XtRString, sizeof(char *), + offset(menu_translations), XtRString, (XtPointer) default_menu_config}, + {"watchFile", "WatchFile", XtRFloat, sizeof(float), + offset(watch_file), XtRString, "0"}, + {"expert", "Expert", XtRBoolean, sizeof(Boolean), + offset(expert), XtRString, (XtPointer) NULL}, + {"expertMode", "ExpertMode", XtRInt, sizeof(int), + offset(expert_mode), XtRImmediate, (XtPointer)31 /* everything on */ }, +#ifndef MOTIF + {"buttonSideSpacing", "ButtonSpacing", XtRDimension, sizeof(Dimension), + offset(btn_side_spacing), XtRImmediate, (XtPointer) 8}, + {"buttonTopSpacing", "ButtonSpacing", XtRDimension, sizeof(Dimension), + offset(btn_top_spacing), XtRImmediate, (XtPointer) 16}, + {"buttonBetweenSpacing", "ButtonSpacing", XtRDimension, sizeof(Dimension), + offset(btn_between_spacing), XtRImmediate, (XtPointer) 8}, + /* ignored; only for backwards compatibility */ + {"buttonBetweenExtra", "ButtonSpacing", XtRDimension, sizeof(Dimension), + offset(btn_between_extra), XtRImmediate, (XtPointer)0}, + {"buttonBorderWidth", "BorderWidth", XtRDimension, sizeof(Dimension), + offset(btn_border_width), XtRImmediate, (XtPointer) 1}, +#endif /* MOTIF */ + {"statusline", "Statusline", XtRBoolean, sizeof(Boolean), + offset(statusline), XtRString, (XtPointer) NULL}, +#ifdef MOTIF + {"toolbarTranslations", "ToolbarTranslations", XtRString, sizeof(char *), + offset(toolbar_translations), XtRString, (XtPointer) default_toolbar_translations}, + {"toolbarPixmapFile", "ToolbarPixmapFile", XtRString, sizeof(char *), + offset(toolbar_pixmap_file), XtRString, (XtPointer) "toolbar.xpm"}, + {"toolbarButtonsRaised", "ToolbarButtonsRaised", XtRBoolean, sizeof(Boolean), + offset(toolbar_buttons_raised), XtRString, "True"}, + {"tooltipsInStatusline", "TooltipsInStatusline", XtRBoolean, sizeof(Boolean), + offset(tooltips_in_statusline), XtRString, "True"}, + {"showTooltips", "ShowTooltips", XtRBoolean, sizeof(Boolean), + offset(show_tooltips), XtRString, "True"}, +#endif /* MOTIF */ + {"pageListHighlightCurrent", "PageListHighlightCurrent", XtRBoolean, sizeof(Boolean), + offset(pagelist_highlight_current), XtRString, "True"}, + {"pageListWidth", "PageListWidth", XtRDimension, sizeof(Dimension), + offset(pagelist_width), XtRImmediate, (XtPointer) 80}, + {"magnifierSize1", "MagnifierSize", XtRString, sizeof(char *), + offset(mg_arg[0]), XtRString, (XtPointer) NULL}, + {"magnifierSize2", "MagnifierSize", XtRString, sizeof(char *), + offset(mg_arg[1]), XtRString, (XtPointer) NULL}, + {"magnifierSize3", "MagnifierSize", XtRString, sizeof(char *), + offset(mg_arg[2]), XtRString, (XtPointer) NULL}, + {"magnifierSize4", "MagnifierSize", XtRString, sizeof(char *), + offset(mg_arg[3]), XtRString, (XtPointer) NULL}, + {"magnifierSize5", "MagnifierSize", XtRString, sizeof(char *), + offset(mg_arg[4]), XtRString, (XtPointer) NULL}, +#if COLOR + {"color", "Color", XtRBoolean, sizeof(Boolean), + offset(use_color), XtRString, "true"}, +#endif /* COLOR */ + {"dvipsPath", "DvipsPath", XtRString, sizeof(char *), + offset(dvips_path), XtRString, (XtPointer)DEFAULT_DVIPS_PATH}, + {"ps2pdfPath", "Ps2PdfPath", XtRString, sizeof(char *), + offset(ps2pdf_path), XtRString, (XtPointer)DEFAULT_PS2PDF_PATH}, + {"dvipsHangTime", "DvipsHangTime", XtRInt, sizeof(int), + offset(dvips_hang), XtRImmediate, (XtPointer) -1500}, + {"dvipsFailHangTime", "DvipsFailHangTime", XtRInt, sizeof(int), + offset(dvips_fail_hang), XtRImmediate, (XtPointer) -5000}, + {"dvipsPrinterString", "DvipsPrinterString", XtRString, sizeof(char *), + offset(dvips_printer_str), XtRString, (XtPointer)NULL}, + {"dvipsOptionsString", "DvipsOptionsString", XtRString, sizeof(char *), + offset(dvips_options_str), XtRString, (XtPointer)NULL}, + {"defaultSavingFormat", "DefaultSavingFormat", XtRInt, sizeof(int), + offset(default_saving_format), XtRImmediate, (XtPointer)0}, + {"defaultPrintingTarget", "DefaultPrintingTarget", XtRInt, sizeof(int), + offset(default_printing_target), XtRImmediate, (XtPointer)1}, +#ifdef GREY + {"grey", "Grey", XtRBoolean, sizeof(Boolean), + offset(use_grey), XtRString, "true"}, + {"install", "Install", XtRBool3, sizeof(Bool3), + offset(install), XtRString, "maybe"}, +#endif /* GREY */ + {"matchInverted", "MatchInverted", XtRBoolean, sizeof(Boolean), + offset(match_highlight_inverted), XtRString, "true"}, + {"ruleColor", "RuleColor", XtRPixel, sizeof(Pixel), + offset(rule_pixel), XtRPixel, (XtPointer) &resource.rule_pixel}, + {"ruleColor", "RuleColor", XtRString, sizeof(char *), + offset(rule_color), XtRString, (XtPointer) NULL}, + /* linkStyle: style for presenting links: + link_style is a bitsmask `xy' with x = color, y = underline, viz.: + 0: no highlighting at all + 1: underline with linkColor + 2: no underlining, text with linkColor + 3: underlining and text with linkColor + */ + {"linkStyle", "LinkStyle", XtRInt, sizeof(int), + offset(link_style), XtRImmediate, (XtPointer) 3}, + {"linkColor", "LinkColor", XtRString, sizeof(char *), + offset(link_color), XtRString, (XtPointer)LINK_COLOR_FALLBACK}, + {"visitedLinkColor", "VisitedLinkColor", XtRString, sizeof(char *), + offset(visited_link_color), XtRString, (XtPointer)VISITED_LINK_COLOR_FALLBACK}, + {"wwwBrowser", "WWWBrowser", XtRString, sizeof(char *), + offset(browser), XtRString, (XtPointer) NULL}, +#ifdef MOTIF + {"prefsBrowserList", "PrefsBrowserList", XtRString, sizeof(char *), + offset(prefs_browser_list), XtRString, (XtPointer)Xdvi_PREFS_BROWSER_DEFAULTS }, + {"prefsEditorList", "PrefsEditorList", XtRString, sizeof(char *), + offset(prefs_editor_list), XtRString, (XtPointer)Xdvi_PREFS_EDITOR_DEFAULTS }, +#endif + /* defaults for unknown mime types */ + {"unknownMimeSuffix", "UnknownMimeSuffix", XtRString, sizeof(char *), + offset(unknown_mime_suffix), XtRString, "application/x-unknown"}, + {"noMimeSuffix", "NoMimeSuffix", XtRString, sizeof(char *), + offset(no_mime_suffix), XtRString, "application/x-unknown"}, + {"anchorPosition", "AnchorPosition", XtRString, sizeof(char *), + offset(anchor_pos), XtRString, (XtPointer) NULL}, + /* bitmask for current search window settings; only used internally! */ + {"searchWindowDefaults", "SearchWindowDefaults", XtRInt, sizeof(int), + offset(search_window_defaults), XtRImmediate, (XtPointer)0}, + /* resources for help text */ + {"helpGeneral", "HelpGeneral", XtRString, sizeof(char *), + offset(help_general), XtRString, NULL}, + {"helpHypertex", "HelpHypertex", XtRString, sizeof(char *), + offset(help_hypertex), XtRString, NULL}, + {"helpOthercommands", "HelpOthercommands", XtRString, sizeof(char *), + offset(help_othercommands), XtRString, NULL}, + {"helpMarking", "HelpMarking", XtRString, sizeof(char *), + offset(help_marking), XtRString, NULL}, + {"helpPagemotion", "HelpPagemotion", XtRString, sizeof(char *), + offset(help_pagemotion), XtRString, NULL}, + {"helpMousebuttons", "HelpMousebuttons", XtRString, sizeof(char *), + offset(help_mousebuttons), XtRString, NULL}, + {"helpModes", "HelpModes", XtRString, sizeof(char *), + offset(help_modes), XtRString, NULL}, + {"helpSearch", "HelpSearch", XtRString, sizeof(char *), + offset(help_search), XtRString, NULL}, + {"helpSourcespecials", "HelpSoucespecials", XtRString, sizeof(char *), + offset(help_sourcespecials), XtRString, NULL}, +#ifdef GREY + {"pageHistorySize", "PageHistorySize", XtRInt, sizeof(int), + offset(page_history_size), XtRImmediate, (XtPointer)1000}, +}; + +/* get these before setting `application_resources' */ +static XtResource xdvirc_resources[] = { + {"noInitFile", "NoInitFile", XtRBoolean, sizeof(Boolean), + offset(no_init_file), XtRString, "false"}, +}; + +static XtResource app_pixel_resources[] = { /* get these later */ +#endif /* GREY */ + {"foreground", "Foreground", XtRPixel, sizeof(Pixel), + offset(fore_Pixel), XtRString, XtDefaultForeground}, + {"background", "Background", XtRPixel, sizeof(Pixel), + offset(back_Pixel), XtRString, XtDefaultBackground}, +/* {"borderColor", "BorderColor", XtRPixel, sizeof(Pixel), */ +/* offset(brdr_Pixel), XtRPixel, (XtPointer) &resource.fore_Pixel}, */ + {"highlight", "Highlight", XtRPixel, sizeof(Pixel), + offset(hl_Pixel), XtRPixel, (XtPointer) &resource.fore_Pixel}, + {"cursorColor", "CursorColor", XtRPixel, sizeof(Pixel), + offset(cr_Pixel), XtRImmediate, (XtPointer)ULONG_MAX}, +}; +#undef offset + +/* Here, list usage values for options that have `XrmoptionSepArg' set. + TODO: what does the `^' stand for? + */ +static const char *usagestr[] = { + /* geometry */ SILENT, +#ifdef MOTIF + /* font */ SILENT, + /* f */ SILENT, +#endif + /* shrinkFactor */ "shrink", +#ifndef VMS + /* S */ "density", + /* density */ SILENT, +#else + /* density */ "density", +#endif +#ifdef GREY + /* gamma */ "float", +#endif + /* rulecolor */ "color", + /* p */ "pixels", + /* margins */ "dimen", + /* sidemargin */ "dimen", + /* topmargin */ "dimen", + /* offsets */ "dimen", + /* xoffset */ "dimen", + /* yoffset */ "dimen", + /* paper */ "papertype", + /* altfont */ "font", + /* mfmode */ "mode-def", + /* editor */ "editor", + /* sourceposition */ "linenumber[ ]*filename", + /* findstring */ "string", + /* textencoding */ "charset", +#ifdef RGB_ANTI_ALIASING + /* subpixels */ "{rgb,bgr}[ i1 i2 i3]", +#endif + /* rv */ "^-l", "-rv", + /* watchfile */ "secs", + /* expertmode */ "flag", + /* mgs */ SUBST, + /* mgs1 */ SILENT, + /* mgs2 */ SILENT, + /* mgs3 */ SILENT, + /* mgs4 */ SILENT, + /* mgs5 */ SILENT, + /* fg */ "color", + /* foreground */ SILENT, + /* bg */ "color", + /* background */ SILENT, + /* hl */ "color", + /* cr */ "color", +#ifndef VMS + /* display */ "^-cr", "-display <host:display>", +#else + /* display */ "^-cr", "-display <host::display>", +#endif + /* geometry */ "^-cr", "-geometry <geometry>", + /* icongeometry */ "geometry", + /* iconic */ "^-icongeometry", "-iconic", + /* font */ "^-icongeometry", "-font <font>", + /* pausespecial */ "string", + /* wheelunit */ "pixels", + /* mousemode */ "0|1|2", +#ifdef PS + /* postscript */ "0|1|2", +# ifdef PS_GS + /* interpreter */ "path", + /* gspalette */ "monochrome|grayscale|color", +# endif +# ifdef MAGICK + /* magick_cache */ "size[k|K|m|M|g|G]", +# endif +#endif + /* dvipspath */ "path", + /* ps2pdfpath */ "path", + /* debug */ "bitmask|string[,string ...]", + /* linkstyle */ "0|1|2|3", + /* linkcolor */ "color", + /* visitedlinkcolor */ "color", + /* browser */ "WWWbrowser", + /* anchorposition */ "anchor", + /* [end marker] */ USAGESTR_END_MARKER +}; + +#ifndef MOTIF + +# ifdef NOQUERY +# define drawWidgetClass widgetClass +# else + +static XtGeometryResult +QueryGeometry(Widget w, + XtWidgetGeometry *constraints, + XtWidgetGeometry *reply) +{ + UNUSED(w); + UNUSED(constraints); + reply->request_mode = CWWidth | CWHeight; + reply->width = globals.page.w; + reply->height = globals.page.h + global_statusline_h; + + return XtGeometryAlmost; +} + +# include <X11/IntrinsicP.h> +# include <X11/CoreP.h> + +/* if the following gives you trouble, just compile with -DNOQUERY */ +static WidgetClassRec drawingWidgetClass = { + { + /* superclass */ &widgetClassRec, + /* class_name */ "Draw", + /* widget_size */ sizeof(WidgetRec), + /* class_initialize */ NULL, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ NULL, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ NULL, + /* num_resources */ 0, + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ XtInheritResize, + /* expose */ XtInheritExpose, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ XtInheritAcceptFocus, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ XtInheritTranslations, + /* query_geometry */ QueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + } +}; + +# define drawWidgetClass &drawingWidgetClass + +# endif /* NOQUERY */ +#endif /* not MOTIF */ + +static int +compare_strings(const void *s, const void *t) +{ + const char **ss = (const char**)s; + const char **tt = (const char**)t; + + return memicmp(*ss, *tt, strlen(*tt) + 1); /* also check for final 0 */ +} + +static void +usage(int exitval) +{ + XrmOptionDescRec *opt; + const char **usageptr = usagestr; + const char **sv = SUBST_VAL; + const char *str1; + const char *str2; + const char *sorted_options[XtNumber(options)]; + char buf[256]; + char *s; + int col, n; + size_t nopt = 0, k; + + for (opt = options; opt < options + XtNumber(options); ++opt) { + str1 = opt->option; + if (*str1 != '-') + continue; + + ASSERT(*usageptr != USAGESTR_END_MARKER, "Too few elements in usageptr[]"); + + str2 = NULL; + if (opt->argKind != XrmoptionNoArg) { + str2 = *usageptr++; + if (str2 == SILENT) + continue; + if (str2 == SUBST) { + str1 = *sv++; + str2 = NULL; + } + } +#if 0 + fprintf(stderr, "str1: %s, str2: %s\n", str1, str2); +#endif + for (;;) { + if (str2 == NULL) + sprintf(buf, "[%.80s]", str1); + else + sprintf(buf, "[%.80s <%.80s>]", str1, str2); + +/* fprintf(stderr, "number of options: %d; len of usagestr: %d\n", */ +/* XtNumber(options), XtNumber(usagestr)); */ + ASSERT(nopt < XtNumber(options), "index out of range"); +/* fprintf(stderr, "sorted: %d=%s\n", nopt, buf); */ + sorted_options[nopt++] = xstrdup(buf); + + if (**usageptr != '^' || strcmp(*usageptr + 1, opt->option) != 0) + break; + ++usageptr; + str1 = *usageptr++; + str2 = NULL; + } + } + + ASSERT(*usageptr == USAGESTR_END_MARKER, "Too many elements in usageptr[]"); + +/* fprintf(stderr, "elems in sorted options: %d\n", nopt); */ + qsort((void*)sorted_options, + nopt, + sizeof(sorted_options[0]), + compare_strings); + + s = xstrdup("Usage: "); + s = xstrcat(s, XDVI_PROGNAME); /* use `xdvi' here, not `xdvik' or `xdvi-xaw.bin' or ... */ + s = xstrcat(s, " [+[<page>]]"); + + col = strlen(s); + fputs(s, stdout); + + for (k = 0; k < nopt; ++k) { + n = strlen(sorted_options[k]); + if (col + n < 80) + putc(' ', stdout); + else { + fputs("\n\t", stdout); + col = 8 - 1; + } + fputs(sorted_options[k], stdout); + col += n + 1; + } + + /* put this in an extra line, to emphasize that it must come last */ + fputs("\n\t[dvi_file]\n", stdout); + + xdvi_exit(exitval); +} + +int +atopix(const char *arg, Boolean allow_minus) +{ + int len = strlen(arg); + const char *arg_end = arg; + char tmp[11]; + double factor; + + if (allow_minus && *arg_end == '-') + ++arg_end; + while ((*arg_end >= '0' && *arg_end <= '9') || *arg_end == '.') + if (arg_end >= arg + XtNumber(tmp) - 1) + return 0; + else + ++arg_end; + memcpy(tmp, arg, arg_end - arg); + tmp[arg_end - arg] = '\0'; + +#if A4 + factor = 1.0 / 2.54; /* cm */ +#else + factor = 1.0; /* inches */ +#endif + if (len > 2) + switch (arg[len - 2] << 8 | arg[len - 1]) { +#if A4 + case 'i' << 8 | 'n': + factor = 1.0; + break; +#else + case 'c' << 8 | 'm': + factor = 1.0 / 2.54; + break; +#endif + case 'm' << 8 | 'm': + factor = 1.0 / 25.4; + break; + case 'p' << 8 | 't': + factor = 1.0 / 72.27; + break; + case 'p' << 8 | 'c': + factor = 12.0 / 72.27; + break; + case 'b' << 8 | 'p': + factor = 1.0 / 72.0; + break; + case 'd' << 8 | 'd': + factor = 1238.0 / 1157.0 / 72.27; + break; + case 'c' << 8 | 'c': + factor = 12 * 1238.0 / 1157.0 / 72.27; + break; + case 's' << 8 | 'p': + factor = 1.0 / 72.27 / 65536; + break; + } + + return factor * atof(tmp) * resource.pixels_per_inch + 0.5; +} + +#if CHECK_APP_FILEVERSION +static void +check_app_defaults_fileversion(void) +{ + /* update this when new essential resources are introduced */ + static const int required_version = 20030303; + + if (resource.app_defaults_fileversion < required_version) { + const char *filename = kpse_find_file("XDvi", kpse_program_text_format, 0); + if (filename == NULL) + filename = "XDvi"; + + fprintf(stderr, "filename: %d\n", resource.app_defaults_fileversion); + popup_message(globals.widgets.top_level, + MSG_WARN, + NULL, + "Your application defaults file `%s' is outdated. " + "This version of xdvi requires a file " + "with date >= %d. Your file is older, or doesn't have a date.\n" + "Please obtain a new version of the file `XDvi', e.g. from:\n" + "http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/xdvi/xdvik/texk/xdvik/texmf/\n" + "and copy it to a directory in your $XDVIINPUTS path.", + filename, required_version); + } +} +#endif + + +static void +warn_about_prerelease_versions(void) +{ + int unstable_version = 0; + if (strstr(XDVI_VERSION_INFO, "-cvs") != NULL) + unstable_version = 1; + else if (strstr(XDVI_VERSION_INFO, "-beta") != NULL) + unstable_version = 2; + + if (unstable_version > 0) { + printf("\n**********************************************************************\n"); + printf("%s version %s,\n%s version.\n\n", XDVIK_PROGNAME, XDVI_VERSION_INFO, + unstable_version == 1 ? "an unstable development" : "a beta testing"); + printf("Want a stable version instead?\n" + " -> please visit one of:\n" + " http://xdvi.sourceforge.net/cvs-upgrade.html\n" + " http://sourceforge.net/project/showfiles.php?group_id=23164\n\n" + "Found a bug?\n" + " -> please report it to:\n" + " http://sourceforge.net/tracker/?group_id=23164&atid=377580\n\n" + "Thanks for your support!\n"); + printf("**********************************************************************\n"); + } +} + + +#ifdef GREY +static Arg temp_args1[] = { + {XtNdepth, (XtArgVal) 0}, + {XtNvisual, (XtArgVal) 0}, + {XtNcolormap, (XtArgVal) 0}, +}; + +/* + * Alternate routine to convert color name to Pixel (needed to substitute + * "black" or "white" for BlackPixelOfScreen, etc., since a different visual + * and colormap are in use). + */ + +static Boolean +XdviCvtStringToPixel(Display *dpy, + XrmValuePtr args, Cardinal *num_args, + XrmValuePtr fromVal, XrmValuePtr toVal, + XtPointer *closure_ret) +{ + XrmValue replacement_val; + Boolean default_is_fg; + + if ((strcmp((String) fromVal->addr, XtDefaultForeground) == 0 + && (default_is_fg = True, True)) + || (strcmp((String) fromVal->addr, XtDefaultBackground) == 0 + && ((default_is_fg = False), True))) { + replacement_val.size = sizeof(String); + replacement_val.addr = (default_is_fg == resource.reverse) + ? "white" : "black"; + fromVal = &replacement_val; + } + + return XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret); +} + +/* + * Convert string to yes/no/maybe. Adapted from the X toolkit. + */ + +static Boolean +XdviCvtStringToBool3(Display *dpy, + XrmValuePtr args, Cardinal *num_args, + XrmValuePtr fromVal, XrmValuePtr toVal, + XtPointer *closure_ret) +{ + String str = (String) fromVal->addr; + static Bool3 value; + + UNUSED(args); + UNUSED(num_args); + UNUSED(closure_ret); + + if (memicmp(str, "true", 5) == 0 + || memicmp(str, "yes", 4) == 0 + || memicmp(str, "on", 3) == 0 || memicmp(str, "1", 2) == 0) + value = True; + + else if (memicmp(str, "false", 6) == 0 + || memicmp(str, "no", 3) == 0 + || memicmp(str, "off", 4) == 0 || memicmp(str, "0", 2) == 0) + value = False; + + else if (memicmp(str, "maybe", 6) == 0) + value = Maybe; + + else { + XtDisplayStringConversionWarning(dpy, str, XtRBoolean); + return False; + } + + if (toVal->addr != NULL) { + if (toVal->size < sizeof(Bool3)) { + toVal->size = sizeof(Bool3); + return False; + } + *(Bool3 *) (toVal->addr) = value; + } + else + toVal->addr = (XPointer) & value; + + toVal->size = sizeof(Bool3); + return True; +} + +#endif + + +/* + * Set the `sourceposition' propery of the window `w' to `source_str'. + * This is usually done in `client' mode to notify the instance of + * xdvi running in window `w' to start a forward search. After this, + * the client usually exits normally. + */ +static void +set_sourceposition_property(const char *source_str, Window win) +{ + /* parse the special in order to expand the filename */ + struct src_parsed_special data; + char *new_special = NULL; + char *expanded_filename = NULL; + + data.filename_len = 0; + data.filename = NULL; + + src_parse(source_str, strlen(source_str), &data); + + if (data.filename_len == 0) { + /* can't give a GUI warning in `client' mode - just exit with error */ + XDVI_FATAL((stderr, + "Filename missing in -sourceposition argument (%s)!", + source_str)); + } + + TRACE_CLIENT((stderr, "got data: line %d, col %d, file |%s|, len %lu\n", + data.line, data.col, data.filename, (unsigned long)data.filename_len)); + + /* expand -sourceposition argument if it contains a path component. + We don't use REALPATH here, because `tex -src' doesn't expand + symlinks either. Instead, use canonicalize_path() to expand + `../' and './' manually. */ + if (strchr(data.filename, '/') != NULL + && (expanded_filename = expand_filename(data.filename, USE_CWD_PATH)) != NULL) { + char *tmp = canonicalize_path(expanded_filename); + free(data.filename); + free(expanded_filename); + expanded_filename = tmp; + } + else + expanded_filename = data.filename; + + TRACE_CLIENT((stderr, "expanded1: |%s|\n", expanded_filename)); + + new_special = xmalloc(2 * LENGTH_OF_INT + 2 /* 2 for `:' and separating space */ + + strlen(expanded_filename) + 1); + sprintf(new_special, "%d:%d %s", data.line, data.col, expanded_filename); + free(expanded_filename); + + TRACE_CLIENT((stderr, "matched!")); + set_string_property(new_special, atom_src_goto(), win); + free(new_special); + set_string_property("", atom_raise(), win); +} + +static void +set_stringsearch_property(const char *str, Window win) +{ + set_string_property(str, atom_find_string(), win); + set_string_property("", atom_raise(), win); +} + + + +/* Translation of valid paper types to dimensions, + which are used internally. The newline characters are a hack + to format the list neatly for error messages. + A* series measures are taken from + http://www.cl.cam.ac.uk/~mgk25/iso-paper.html +*/ +static const char *paper_types[] = { + "us", "8.5x11in", + "letter", "8.5x11in", /* dvips compatibility */ + "ledger", "17x11in", /* dvips compatibility */ + "tabloid", "11x17in", /* dvips compatibility */ + "usr", "11x8.5in", + "legal", "8.5x14in", + "legalr", "14x8.5in", + "foolscap", "13.5x17.0in", /* ??? */ + "foolscapr", "17.0x13.5in", + "", "0", + + /* ISO `A' formats, Portrait */ + "a0", "841x1189mm", + "a1", "594x841mm", + "a2", "420x594mm", + "a3", "297x420mm", + "a4", "210x297mm", + "a5", "148x210mm", + "a6", "105x148mm", + "a7", "74x105mm", + "a8", "52x74mm", + "a9", "37x52mm", + "a10","26x37mm", + "", "0", + + /* ISO `A' formats, Landscape */ + "a0r", "1189x841mm", + "a1r", "841x594mm", + "a2r", "594x420mm", + "a3r", "420x297mm", + "a4r", "297x210mm", + "a5r", "210x148mm", + "a6r", "148x105mm", + "a7r", "105x74mm", + "a8r", "74x52mm", + "a9r", "52x37mm", + "a10r","37x26mm", + "", "0", + + /* ISO `B' formats, Portrait */ + "b0", "1000x1414mm", + "b1", "707x1000mm", + "b2", "500x707mm", + "b3", "353x500mm", + "b4", "250x353mm", + "b5", "176x250mm", + "b6", "125x176mm", + "b7", "88x125mm", + "b8", "62x88mm", + "b9", "44x62mm", + "b10","31x44mm", + "", "0", + + /* ISO `B' formats, Landscape */ + "b0r", "1414x1000mm", + "b1r", "1000x707mm", + "b2r", "707x500mm", + "b3r", "500x353mm", + "b4r", "353x250mm", + "b5r", "250x176mm", + "b6r", "176x125mm", + "b7r", "125x88mm", + "b8r", "88x62mm", + "b9r", "62x44mm", + "b10r","44x31mm", + "", "0", + + /* ISO `C' formats, Portrait */ + "c0", "917x1297mm", + "c1", "648x917mm", + "c2", "458x648mm", + "c3", "324x458mm", + "c4", "229x324mm", + "c5", "162x229mm", + "c6", "114x162mm", + "c7", "81x114mm", + "c8", "57x81mm", + "c9", "40x57mm", + "c10","28x40mm", + "", "0", + + /* ISO `C' formats, Landscape */ + "c0r", "1297x917mm", + "c1r", "917x648mm", + "c2r", "648x458mm", + "c3r", "458x324mm", + "c4r", "324x229mm", + "c5r", "229x162mm", + "c6r", "162x114mm", + "c7r", "114x81mm", + "c8r", "81x57mm", + "c9r", "57x40mm", + "c10r","40x28mm", +}; + +/* access methods for paper_types */ +const char **get_paper_types(void) { + return paper_types; +} + +size_t get_paper_types_size(void) { + return XtNumber(paper_types); +} + +/* Set the icon name and title name standard properties on `globals.widgets.top_level'. + * We use the basename of the DVI file (without the .dvi), so different xdvi + * invocations can be distinguished, yet do not use up too much real estate. + * + * This function returns freshly allocated memory in *icon_name and *title_name + * which the caller is responsible for free()ing again. + */ +void +get_icon_and_title(const char *filename, char **icon_name, char **title_name) +{ + /* Use basename of DVI file for name in icon and title. */ + const char *ptr; + char *ptr2; + + /* SU 2000/12/16: added page number information */ + const char *const title_name_fmt = "%s: %s (%d page%s)"; + + MYTRACE((stderr, "get_icon_and_title called with: |%s|", filename)); + + ptr = strrchr(filename, '/'); + if (ptr != NULL) + ++ptr; + else { + ptr = filename; + } + + /* + * Remove the `file:' prefix from the icon name; since some windowmanagers + * only display a prefix in window lists etc., it's more significant this + * way. + */ + + if (memcmp(ptr, "file:", 5) == 0) { + ptr += 5; + } + *icon_name = xstrdup(ptr); + + MYTRACE((stderr, "before chopping: icon_name: |%s|", *icon_name)); + if ((ptr2 = strstr(*icon_name, ".dvi")) != NULL) { + /* chop off .dvi extension */ + *ptr2 = '\0'; + } + MYTRACE((stderr, "after chopping: icon_name: |%s|", *icon_name)); + + *title_name = xmalloc(strlen(title_name_fmt) + + strlen(XDVIK_PROGNAME) + + strlen(*icon_name) + + LENGTH_OF_INT + + 2); /* 2 for additional plural `s' */ + MYTRACE((stderr, "total_pages: %d", total_pages)); + sprintf(*title_name, title_name_fmt, XDVIK_PROGNAME, *icon_name, total_pages, + (total_pages > 1) ? "s" : ""); + + MYTRACE((stderr, "title_name, icon_name: |%s|%s|", *title_name, *icon_name)); +} + +void +set_icon_and_title(const char *icon_name, const char *title_name) +{ + if (!XtIsRealized(globals.widgets.top_level)) { + MYTRACE((stderr, "set_icon_and_title: returning")); + return; + } + XtVaSetValues(globals.widgets.top_level, XtNtitle, (XtArgVal) title_name, XtNiconName, (XtArgVal) icon_name, NULL); + XSetStandardProperties(DISP, XtWindow(globals.widgets.top_level), title_name, icon_name, + (Pixmap) 0, NULL, 0, NULL); +} + +static void +display_version_info(void) +{ + printf("%s version %s ", XDVIK_PROGNAME, XDVI_VERSION); +#ifdef MOTIF + printf("(%s, runtime version %d.%d)\n", + /* XmVERSION, XmREVISION, XmUPDATE_LEVEL, */ + XmVERSION_STRING, + xmUseVersion / 1000, xmUseVersion % 1000); +#else + printf("%s\n", XDVI_GUI); +#endif + printf("Libraries: %s, T1lib version %s\n", kpathsea_version_string, T1LIB_VERSIONSTRING); +} + +static void +display_bug_reporting_info(void) +{ + printf("Please send bug reports, feature requests etc. to one of:\n" + " http://sourceforge.net/tracker/?group_id=23164&atid=377580\n" + " tex-k@tug.org (http://tug.org/mailman/listinfo/tex-k)\n\n" + "\n"); +} + +static void +display_licensing_info(void) +{ + fputs("Licenses: X Consortium license, GNU Library General Public\n" + "License, GNU General Public License (use option `-license'\n" + "for more details). There is NO WARRANTY of anything.\n\n", stdout); +} + +static void +display_long_licensing_info(void) +{ + fputs("The major parts of Xdvik are licensed under the X Consortium license.\n" + "Parts (encoding.c) are licensed under the GNU General Public License.\n" + "Xdvik uses the following libraries:\n" + "- The kpathsea library, licensed in part under the GNU General Public\n" + " License, in part under the GNU Library General Public License.\n" + "- t1lib, licensed in parts under the GNU Library General Public License,\n" + " in parts under the X Consortium license.\n" + "There is NO WARRANTY of anything.\n\n", stdout); +} + +static void +get_window_constraints(XtWidgetGeometry *reply, + Dimension screen_w, Dimension screen_h, + int add_h) +{ + XtWidgetGeometry constraints; + + constraints.request_mode = reply->request_mode = 0; + + /* fprintf(stderr, "setting constraints.width to %d\n", globals.page.w); */ + constraints.width = globals.page.w; + if (globals.page.w > screen_w) { + /* fprintf(stderr, "setting CWWidth constraint\n"); */ + constraints.request_mode |= CWWidth; + constraints.width = screen_w; + } + + /* fprintf(stderr, "setting constraints.height to %d\n", globals.page.h + global_statusline_h); */ + constraints.height = globals.page.h + global_statusline_h; + if (constraints.height > screen_h) { + /* fprintf(stderr, "setting CWHeight constraint\n"); */ + constraints.request_mode |= CWHeight; + /* if window too large, need to subtract height of toolbar etc. again */ + constraints.height = screen_h - add_h; + } + + if (constraints.request_mode != 0 + && constraints.request_mode != (CWWidth | CWHeight)) { +#ifdef MOTIF + (void)XtQueryGeometry(globals.widgets.main_window, &constraints, reply); +#else + (void)XtQueryGeometry(globals.widgets.vport_widget, &constraints, reply); +#endif + } + if (!(reply->request_mode & CWWidth)) + reply->width = constraints.width; + if (reply->width >= screen_w) + reply->width = screen_w; + if (!(reply->request_mode & CWHeight)) + reply->height = constraints.height; + if (reply->height >= screen_h) + reply->height = screen_h; + /* fprintf(stderr, "width now: %d\n", reply.width); */ + +} + +void +set_windowsize(Dimension *ret_w, Dimension *ret_h, int add_w, int add_h, Boolean override) +{ + static Arg set_wh_args[] = { + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal) 0}, + }; + Dimension screen_w, screen_h; + + const char *test_geometry = resource.geometry; + + if (resource.fullscreen) { + Dimension w = WidthOfScreen(SCRN), h = HeightOfScreen(SCRN); + + if (currwin.shrinkfactor == 0) { /* if not set by user */ + Dimension height_factor = ROUNDUP(globals.page.unshrunk_h, h); + currwin.shrinkfactor = ROUNDUP(globals.page.unshrunk_w, w); + if (height_factor >= currwin.shrinkfactor) + currwin.shrinkfactor = height_factor; +/* fprintf(stderr, "factor was 0, using %d\n", currwin.shrinkfactor); */ + } +/* else */ +/* fprintf(stderr, "factor != 0, using %d\n", currwin.shrinkfactor); */ + + mane.shrinkfactor = currwin.shrinkfactor; + init_page(); + set_wh_args[0].value = (XtArgVal)w; + set_wh_args[1].value = (XtArgVal)h; + *ret_w = w; + *ret_h = h; +#ifdef MOTIF +#if USE_XAW_PANNER + XtVaGetValues(globals.widgets.main_window, XmNshadowThickness, &g_save_shadow_thickness, NULL); +#endif + XtVaSetValues(globals.widgets.main_window, XmNshadowThickness, 0, NULL); +#endif + XtSetValues(globals.widgets.top_level, set_wh_args, XtNumber(set_wh_args)); + } + else if (override) { + set_wh_args[0].value = (XtArgVal)*ret_w; + set_wh_args[1].value = (XtArgVal)*ret_h; + XtSetValues(globals.widgets.top_level, set_wh_args, XtNumber(set_wh_args)); + } + else { /* determine a window size that fits the current shrink factor */ + Arg temp_args3 = { XtNborderWidth, (XtArgVal)&bwidth }; + XtWidgetGeometry reply; + + XtGetValues(globals.widgets.top_level, &temp_args3, 1); /* get border width */ + screen_w = WidthOfScreen(SCRN) - 2 * bwidth; + + screen_w -= add_w; + screen_h = HeightOfScreen(SCRN) - 2 * bwidth - global_statusline_h - 6; + for (;;) { /* actually, at most two passes */ + Dimension height_factor; + + TRACE_GUI((stderr, "geometry: |%s|; remember: %d, windowsize: %s", + resource.geometry ? resource.geometry : "<NULL>", + resource.remember_windowsize, + resource.windowsize ? resource.windowsize : "<NULL>")); + + if (resource.geometry == NULL && !resource.remember_windowsize) { + /* geometry not set by user, try to find geometry that fits the shrink factor */ + get_window_constraints(&reply, screen_w, screen_h, add_h); + } + else { + int x, y; + unsigned int width, height; + int flags; + + if (resource.remember_windowsize && resource.windowsize != NULL) + test_geometry = resource.windowsize; + else + test_geometry = resource.geometry; + flags = XParseGeometry(test_geometry, &x, &y, &width, &height); + + if (!(flags & WidthValue) || !(flags & HeightValue)) { + /* no geometry specified, use fallback */ + get_window_constraints(&reply, screen_w, screen_h, add_h); + } + + /* warn about bad values */ + if (flags & WidthValue) { + if (width > (unsigned int)(2 * bwidth + add_w)) { + TRACE_FILES((stderr, "width: %hu, bwidth: %hu, add_w: %d", + width, bwidth, add_w)); + reply.width = width - 2 * bwidth - add_w; + } + else { + reply.width = width; + } + } + if (flags & HeightValue) { + if (height > (unsigned int)(2 * bwidth + add_h)) { + TRACE_FILES((stderr, "height: %hu, bwidth: %hu, add_h: %d", + height, bwidth, add_h)); + reply.height = height - 2 * bwidth - add_h; + } + else { + reply.height = height; + } + } + TRACE_FILES((stderr, "setting geometry: %dx%d", (int)reply.width, (int)reply.height)); + } + + /* now reply.{width,height} contain max. usable window size */ + + /* User didn't use `-s 0', use either default or other user-specified value */ + if (currwin.shrinkfactor != 0) { +/* fprintf(stderr, "factor != 0, using %d\n", currwin.shrinkfactor); */ + break; + } +/* else { */ +/* fprintf(stderr, "factor was 0, using %d\n", currwin.shrinkfactor); */ +/* } */ + + /* else, try to find a suitable shrink factor: */ + currwin.shrinkfactor = ROUNDUP(globals.page.unshrunk_w, reply.width - 2); +/* fprintf(stderr, "factor w: %d\n", currwin.shrinkfactor); */ + + height_factor = ROUNDUP(globals.page.unshrunk_h, reply.height - 2); +/* fprintf(stderr, "factor h: %d\n", height_factor); */ + if (height_factor >= currwin.shrinkfactor) + currwin.shrinkfactor = height_factor; + +/* fprintf(stderr, "factor now is: %d\n", currwin.shrinkfactor); */ + + mane.shrinkfactor = currwin.shrinkfactor; + init_page(); + set_wh_args[0].value = (XtArgVal)globals.page.w; + set_wh_args[1].value = (XtArgVal)globals.page.h; + *ret_w = globals.page.w; + *ret_h = globals.page.h; + XtSetValues(globals.widgets.draw_widget, set_wh_args, XtNumber(set_wh_args)); + } +#ifdef MOTIF + /* + SU 2002/11/23: Added scrollbar width to height computation. + Otherwise, when the vertical space isn't sufficient, a + vertical scrollbar will be added, but since this makes the + display narrower, a horizontal scrollbar will be added as + well, even if this wouldn't be neccessary. + + SU 2003/09/30: Apparently the size computation works now, even + though I'm not sure why (scrollbar value isn't in add_w). Investigate. + */ + /* HACK ALERT: 4 for window decoration borders - FIXME: get actual values?? */ + set_wh_args[0].value = reply.width + add_w + (test_geometry == NULL ? 4 : 0); + set_wh_args[1].value = reply.height + add_h - (test_geometry == NULL ? 4 : 0); + XtSetValues(globals.widgets.top_level, set_wh_args, XtNumber(set_wh_args)); + +#else /* MOTIF */ + + set_wh_args[0].value = reply.width + add_w + (test_geometry == NULL ? 15 : (2 * bwidth)); + /* + FIXME: use real height of statusline here + Somehow I didn't manage to use XtVaCreateWidget in a call to + create_statusline() above, and XtManageChild() below. + In that case, we could do without global_statusline_h. + */ + set_wh_args[1].value = reply.height + (test_geometry == NULL ? (2 * bwidth + add_h) : 0); + XtSetValues(globals.widgets.top_level, set_wh_args, XtNumber(set_wh_args)); + set_wh_args[0].value -= add_w; + XtSetValues(globals.widgets.vport_widget, set_wh_args, XtNumber(set_wh_args)); + +#endif /* MOTIF */ + *ret_w = set_wh_args[0].value; + *ret_h = set_wh_args[1].value; + TRACE_FILES((stderr, "returning: w=%d, h=%d", *ret_w, *ret_h)); + } +} + +static void +net_wm_toggle_fullscreen(int flag) +{ + Atom NET_WM_FULLSCREEN = XInternAtom(DISP, "_NET_WM_STATE_FULLSCREEN", True); + + if (NET_WM_FULLSCREEN) { + XEvent ev; + Atom NET_WM_STATE = XInternAtom(DISP, "_NET_WM_STATE", False); + +/* XDVI_INFO((stdout, "trying _NET_WM_STATE_FULLSCREEN ...")); */ + + ev.type = ClientMessage; + ev.xclient.serial = 0; + ev.xclient.send_event = True; + ev.xclient.display = DISP; + ev.xclient.window = XtWindow(globals.widgets.top_level); + ev.xclient.message_type = NET_WM_STATE; + ev.xclient.format = 32; + ev.xclient.data.l[0] = flag; /* _NET_WM_STATE_REMOVE (0) or _NET_WM_STATE_ADD (1) */ + ev.xclient.data.l[1] = NET_WM_FULLSCREEN; + ev.xclient.data.l[2] = 0L; + + XSendEvent(DISP, DefaultRootWindow(DISP), False, + SubstructureNotifyMask, &ev); + } + else { + XDVI_INFO((stdout, "_NET_WM_STATE_FULLSCREEN not supported by this window manager.")); + } +} + +void +reconfigure_window(Boolean fullscreen, Dimension width, Dimension height, + Boolean save_position) +{ + static int x_old = 5, y_old = 15; +#ifdef SIZECONFIGURE_WORKS + int sizeconfiguremask; + XWindowChanges sizeconfigure; +#endif /* SIZECONFIGURE_WORKS */ +#ifdef MOTIF + static int save_wm_decorations; +#else + static struct PropMotifWmHints MWMHints = {MWM_HINTS_DECORATIONS, 0, 0, 0, 0}; + Atom WM_HINTS = XInternAtom(DISP, "_MOTIF_WM_HINTS", True); +#endif + int x, y; + +#ifdef SIZECONFIGURE_WORKS + sizeconfiguremask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth; + sizeconfigure.width = width; + sizeconfigure.height = height; +#endif /* SIZECONFIGURE_WORKS */ + + if (fullscreen) { +#if 0 + static Boolean first_time = True; + /* offsets between the raw window and the decorated window */ + static int wm_x_offset = 0; + static int wm_y_offset = 0; +#endif + Window dummy; + +#ifdef SIZECONFIGURE_WORKS + sizeconfigure.x = 0; + sizeconfigure.y = 0; + sizeconfigure.border_width = 0; +#endif /* SIZECONFIGURE_WORKS */ + + /* Note ZLB: avoid to call XTranslateCoordinates if the window is + not yet mapped since XTranslateCoordinates implicitly maps the + window (note: calling the function XGetWindowAttributes also + makes the window mapped). + + This effectively eliminates the flashing effect when xdvik is + started in fullscreen mode for the Motif version. For the Xaw + version we still get flashing effect (seems that the window is + already mapped). */ + + if (save_position) { + /* save current window coordinates so that we can change them back */ + (void)XTranslateCoordinates(DISP, XtWindow(globals.widgets.top_level), + RootWindowOfScreen(SCRN), + 0, 0, + &x_old, &y_old, + &dummy); +#if 0 + if (first_time) { + first_time = False; + /* This is a hack for finding out wm_x_offset, wm_y_offset */ + XMoveWindow(DISP, XtWindow(globals.widgets.top_level), 0, 0); + XSync(DISP, False); + (void)XTranslateCoordinates(DISP, XtWindow(globals.widgets.top_level), + RootWindowOfScreen(SCRN), + 0, 0, &wm_x_offset, &wm_y_offset, + &dummy); + fprintf(stderr, "wm offset = (%d,%d)\n", + wm_x_offset, wm_y_offset); + } + x_old -= wm_x_offset; + y_old -= wm_y_offset; +#endif + } + + x = y = 0; + +#ifdef MOTIF + XtVaGetValues(globals.widgets.top_level, XmNmwmDecorations, &save_wm_decorations, NULL); + /* FIXME: this doesn't work e.g. with KDE */ + XtVaSetValues(globals.widgets.top_level, + XmNmwmDecorations, 0, + XmNgeometry, "+0+0", + NULL); + XtVaSetValues(globals.widgets.main_window, XmNshadowThickness, 0, NULL); +#else + MWMHints.decorations = 0; + if (WM_HINTS != None) { + XChangeProperty(DISP, XtWindow(globals.widgets.top_level), + WM_HINTS, WM_HINTS, 32, + PropModeReplace, (unsigned char *)&MWMHints, + sizeof(MWMHints) / 4); + } +#endif + /* SU: apparently some new standard that is supposed to work + with some WMs ... but it doesn't with my versions of Gnome and KDE. */ + net_wm_toggle_fullscreen(1); + +#ifdef SIZECONFIGURE_WORKS + XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure); +#endif /* SIZECONFIGURE_WORKS */ + } + else { +#ifdef SIZECONFIGURE_WORKS + sizeconfiguremask = CWWidth | CWHeight | CWX | CWY; + sizeconfigure.x = x_old; + sizeconfigure.y = y_old; + sizeconfigure.border_width = 20; +#endif /* SIZECONFIGURE_WORKS */ + XtVaSetValues(globals.widgets.top_level, XtNx, x_old, XtNy, y_old, NULL); +#ifdef MOTIF + XtVaSetValues(globals.widgets.top_level, XmNmwmDecorations, save_wm_decorations, NULL); +#if USE_XAW_PANNER + XtVaSetValues(globals.widgets.main_window, XmNshadowThickness, g_save_shadow_thickness, NULL); +#endif +#else + MWMHints.decorations = MWM_DECOR_ALL; + if (WM_HINTS != None) { + XChangeProperty(DISP, XtWindow(globals.widgets.top_level), + WM_HINTS, WM_HINTS, 32, + PropModeReplace, (unsigned char *)&MWMHints, + sizeof(MWMHints) / 4); + } +#endif + net_wm_toggle_fullscreen(0); + + x = x_old; + y = y_old; + } + +#if 1 +#if 0 + XUnmapWindow(DISP, XtWindow(globals.widgets.top_level)); +#else + XWithdrawWindow(DISP, XtWindow(globals.widgets.top_level), XScreenNumberOfScreen(SCRN)); +#endif + + /* Note ZLB: Placing XResizeWindow before XUnmapWindow or after XMapWindow + makes the fullscreen window size smaller than the screen size when + using `mwm' of Lesstif */ + XSetWindowBorderWidth(DISP, XtWindow(globals.widgets.top_level), 0); + XResizeWindow(DISP, XtWindow(globals.widgets.top_level), width, height); + + XMapRaised(DISP, XtWindow(globals.widgets.top_level)); + + /* Note ZLB: XMapWindow might change the window position with some WMs + (like Sawfish), so we place the window position after it's mapped. */ + XMoveWindow(DISP, XtWindow(globals.widgets.top_level), x, y); +#endif /* 0 */ + + /* need to redraw the page to avoid artifacts */ + globals.ev.flags |= EV_NEWPAGE; + XFlush(DISP); +} + +/* + a custom error handler that makes it easier to catch X errors in the debugger + (by setting a breakpoint to this function, plus using the -sync option). + There was an X error reported by Svend Tollak Munkejord when running remotly + on OSF1/V5.1 alpha with display on SuSE 9.1, after selecting some text with the + mouse and releasing the mouse button, which I couldn't track down: + + X Error of failed request: BadValue (integer parameter out of range for operation) + Major opcode of failed request: 18 (X_ChangeProperty) + Value in failed request: 0x40 + Serial number of failed request: 518 + Current serial number in output stream: 519 + + From the trace: + + signal IOT/Abort trap at >*[__kill, 0x3ff800e8908] beq a3, 0x3ff800e8920 + (dbx) where + > 0 __kill(0x0, 0x5, 0x3ff00000000, 0x11fffb188, 0x3ff801a9c14) [0x3ff800e8908] + 1 (unknown)() [0x3ff801ee108] + 2 __tis_raise(0x3ff801a9c14, 0x11fffb620, 0x3ff801229d8, 0x3ff00000006, 0x3ff801869b4) [0x3ff801229d4] + 3 raise(0x3ff801229d8, 0x3ff00000006, 0x3ff801869b4, 0x0, 0x3ff801a9c44) [0x3ff801869b0] + 4 abort(0x12006f858, 0x406f28ae75776627, 0x0, 0x0, 0x100000000) [0x3ff801a9c40] + 5 do_abort() ["util.c":442, 0x12006f854] + 6 x_error_handler(display = 0x140088800, error = 0x11fffb620) ["xdvi.c":1972, 0x1200764c8] + 7 (unknown)() [0x3ff8086caf0] + 8 _XError(0x11fffb758, 0x0, 0x36c, 0x24, 0x20) [0x3ff8044f7f0] + 9 _XReply(0x0, 0x3, 0x0, 0x11fffba40, 0x100000000) [0x3ff8044cec8] + 10 XSync(0x14019ea40, 0x40036b0200, 0x19170b000120000, 0x12, 0x43197900000000) [0x3ff80444910] + 11 _XSyncFunction(0x19170b000120000, 0x12, 0x43197900000000, 0x0, 0x3ff80408994) [0x3ff804449f0] + 12 XChangeProperty(0x3ff8086c9c0, 0x0, 0x2c, 0xb6, 0x4) [0x3ff80408990] + 13 (unknown)() [0x3ff8086d2d0] + 14 (unknown)() [0x3ff8086d654] + 15 XtDispatchEventToWidget(0x3ff80852834, 0x11fffbde8, 0x3ff80852974, 0x11fffbde8, 0x0) [0x3ff80852060] + 16 (unknown)() [0x3ff80852990] + 17 XtDispatchEvent(0x801, 0x4, 0x11fffc018, 0x0, 0x100000000) [0x3ff80852fb0] + 18 read_events(ret_mask = 131070) ["events.c":5048, 0x120046fa4] + 19 do_pages() ["events.c":5290, 0x120047e58] + 20 run_dvi_file(filename = 0x14005f370 = "/auto/home/vsl175/a/svendm/latex/a.dvi", data = 0x14005f778) + ["xdvi.c":3852, 0x12007a5e8] + 21 main(argc = 2, argv = 0x11fffc018) ["xdvi.c":4231, 0x12007b780] + + Since it seemed to work regardless of this error, I decided to enable the custom + error handler by default, at least until we've figured this problem out. +*/ +static int +x_error_handler(Display *display, XErrorEvent *error) +{ + char buf[1024], req_buf[1024]; + + if (error->request_code < 128) { + char num[LENGTH_OF_INT]; + sprintf(num, "%d", error->request_code); + XGetErrorDatabaseText(display, "XRequest", num, "", req_buf, 1024); + } + else { + req_buf[0] = '\0'; + } + + XGetErrorText(display, error->error_code, buf, sizeof buf); + /* XtCloseDisplay(DISP); */ + if (error->error_code == BadWindow + || error->error_code == BadPixmap + || error->error_code == BadCursor + || error->error_code == BadFont + || error->error_code == BadDrawable + || error->error_code == BadColor + || error->error_code == BadGC + || error->error_code == BadIDChoice + || error->error_code == BadValue + || error->error_code == BadAtom) { + XDVI_WARNING((stderr, "X protocol error: %s\n X Request %d (%s), Value=0x%x.", + buf, error->request_code, req_buf, (unsigned int)error->resourceid)); + } + else { + XDVI_WARNING((stderr, "X protocol error: %s\n X Request %d (%s).", + buf, error->request_code, req_buf)); + } + return 0; +} + + +/* + * Parse colors from resource.{visited_}link_color, saving them + * to g_{visited_}link_color and {visited_}link_pix. +*/ +static void +get_link_colors(Pixel *link_pix, Pixel *visited_link_pix) +{ + XrmValue from1, from2, to1, to2; + + XColor exact, approx; + double r, g, b; + double factor = 65535.0; + int ret; + + /* get rgb values from color for links */ + if ((ret = XLookupColor(DISP, G_colormap, + resource.link_color, + &exact, &approx)) != 0) { + } + else { + XDVI_WARNING((stderr, "XLookupColor failed for resource.link_color \"%s\"\n" + "- using fallback color \"%s\".", + resource.visited_link_color, LINK_COLOR_FALLBACK)); + XLookupColor(DISP, G_colormap, LINK_COLOR_FALLBACK, &exact, &approx); + } + +#if 0 + fprintf(stderr, "lookup color for %s returned: %d, %d, %d\n", + resource.link_color, exact.red, exact.green, exact.blue); +#endif + r = exact.red / factor; + g = exact.green / factor; + b = exact.blue / factor; + g_link_color_rgb = xmalloc(strlen("push rgb 0.00 0.00 0.00") + 1); + sprintf(g_link_color_rgb, "push rgb %.2f %.2f %.2f", r, g, b); + + /* same for visited links */ + if ((ret = XLookupColor(DISP, G_colormap, + resource.visited_link_color, + &exact, &approx)) != 0) { + } + else { + XDVI_WARNING((stderr, "XLookupColor failed for resource.visited_link_color \"%s\"\n" + "- using fallback color \"%s\".", + resource.visited_link_color, VISITED_LINK_COLOR_FALLBACK)); + XLookupColor(DISP, G_colormap, VISITED_LINK_COLOR_FALLBACK, &exact, &approx); + } + +#if 0 + fprintf(stderr, "lookup color for %s returned: %d, %d, %d\n", + resource.visited_link_color, exact.red, exact.green, exact.blue); +#endif + r = exact.red / factor; + g = exact.green / factor; + b = exact.blue / factor; + g_visited_link_color_rgb = xmalloc(strlen("push rgb 0.00 0.00 0.00") + 1); + sprintf(g_visited_link_color_rgb, "push rgb %.2f %.2f %.2f", r, g, b); + + /* 2nd part: Create CG for the underlines. */ + from1.addr = resource.link_color; + from1.size = strlen(from1.addr) + 1; + to1.addr = (XtPointer)link_pix; + to1.size = sizeof(Pixel); + if (!XtConvertAndStore(globals.widgets.top_level, XtRString, &from1, XtRPixel, &to1)) { + XDVI_WARNING((stderr, "String to pixel conversion failed for resource.link_color \"%s\"\n" + "- using fallback color \"%s\".", + resource.link_color, LINK_COLOR_FALLBACK)); + from1.addr = LINK_COLOR_FALLBACK; + from1.size = strlen(from1.addr) + 1; + to1.addr = (XtPointer)link_pix; + to1.size = sizeof(Pixel); + XtConvertAndStore(globals.widgets.top_level, XtRString, &from1, XtRPixel, &to1); + } + from2.addr = resource.visited_link_color; + from2.size = strlen(from2.addr) + 1; + to2.addr = (XtPointer)visited_link_pix; + to2.size = sizeof(Pixel); + if (!XtConvertAndStore(globals.widgets.top_level, XtRString, &from2, XtRPixel, &to2)) { + XDVI_WARNING((stderr, "String to pixel conversion failed for resource.visited_link_color \"%s\"\n" + "- using fallback color \"%s\".", + resource.visited_link_color, VISITED_LINK_COLOR_FALLBACK)); + from2.addr = VISITED_LINK_COLOR_FALLBACK; + from2.size = strlen(from2.addr) + 1; + to2.addr = (XtPointer)visited_link_pix; + to2.size = sizeof(Pixel); + XtConvertAndStore(globals.widgets.top_level, XtRString, &from2, XtRPixel, &to2); + } +} + +/* Widget globals.widgets.main_row, globals.widgets.menu_bar; */ + + +#ifdef MOTIF +/* make sure the translations for the drawing area are properly set + (Motif 2.x seems to somehow overwrite them somewhere in the + initialization phase; bug #610206). +*/ +void +motif_translations_hack(void) +{ + static XtTranslations xlats = NULL; + const char *const translations = \ + "<Key>osfPageUp:back-page()\n" + "<Key>osfPageDown:forward-page()\n" + "Ctrl<Key>osfBeginLine:goto-page(1)\n" + "Ctrl<Key>osfEndLine:goto-page()\n" + "<Key>osfBeginLine:home-or-top()\n" + "<Key>osfEndLine:end-or-bottom()\n" +#if 0 + /* AFAIK the following don't have any effect with Motif */ +#ifdef XK_KP_Left + "<Key>KP_Home:home()\n" + "<Key>KP_End:down()\n" + "<Key>KP_Prior:back-page()\n" + "<Key>KP_Next:forward-page()\n" +#endif +#endif + ; + + if (xlats == NULL) { + xlats = XtParseTranslationTable(translations); + } + + ASSERT(globals.widgets.clip_widget != NULL, "globals.widgets.clip_widget must have been initialized"); + ASSERT(globals.widgets.draw_widget != NULL, "globals.widgets.draw_widget must have been initialized"); + XtOverrideTranslations(globals.widgets.clip_widget, xlats); +} +#endif /* MOTIF */ + + +/* + Initialize internal data (most of them global ...) according to the values + of resources/command-line arguments, warning user about illegal values + etc. +*/ +static void +init_check_resources(void) +{ + size_t i; + + if (resource.mfmode != NULL) { + char *p; + + p = strrchr(resource.mfmode, ':'); + if (p != NULL) { + unsigned int len; + char *p1; + + ++p; + len = p - resource.mfmode; + p1 = xmalloc(len); + memcpy(p1, resource.mfmode, len - 1); + p1[len - 1] = '\0'; + resource.mfmode = p1; + resource.pixels_per_inch = atoi(p); + } + } + if (currwin.shrinkfactor < 0) { + XDVI_ERROR((stderr, "Invalid shrink factor: %d.", currwin.shrinkfactor)); + usage(EXIT_FAILURE); + } + if (resource.density <= 0) { + XDVI_ERROR((stderr, "Invalid shrink density: %d.", resource.density)); + usage(EXIT_FAILURE); + } + if (resource.pixels_per_inch <= 0) { + XDVI_ERROR((stderr, "Invalid dpi value: %d.", resource.pixels_per_inch)); + usage(EXIT_FAILURE); + } + if (resource.link_style < 0 || resource.link_style > 3) { + XDVI_ERROR((stderr, "Unrecognized value %d for resource \"linkstyle\" (valid range is 0 - 3); assuming 3.", + resource.link_style)); + resource.link_style = 3; + } + if (currwin.shrinkfactor > 1) { + mane.shrinkfactor = currwin.shrinkfactor; /* otherwise it's 1 */ + } + +#ifdef RGB_ANTI_ALIASING +#warning Note: RGB Anti-aliasing enabled + /* subpixel rendering */ + resource.subpixel_order = SUBPIXEL_NONE; + if (resource.sub_pixels != NULL) { + int sum; + + if (memicmp(resource.sub_pixels, "rgb", 3) == 0) + resource.subpixel_order = SUBPIXEL_RGB; + else if (memicmp(resource.sub_pixels, "bgr", 3) == 0) + resource.subpixel_order = SUBPIXEL_BGR; + else if (memicmp(resource.sub_pixels, "none", 3) == 0) + resource.subpixel_order = SUBPIXEL_NONE; + else { + XDVI_ERROR((stderr, + "Unrecognized value \"%s\" for resource subpixels\n" + "(possible values are: \"rgb\" or \"bgr\").", + resource.sub_pixels)); + xdvi_exit(EXIT_FAILURE); + } + /* get the energy distribution */ + if (resource.subpixel_order == SUBPIXEL_RGB || resource.subpixel_order == SUBPIXEL_BGR) { + const char *ptr = resource.sub_pixels + 3; + while (isspace(*ptr)) + ptr++; + fprintf(stderr, "ptr: |%s|\n", ptr); + resource.subpixel_energy[0] = 33.333; + resource.subpixel_energy[1] = 33.333; + resource.subpixel_energy[2] = 0.0; + if (*ptr != '\0') { + if (sscanf(ptr, "%f %f %f", + &(resource.subpixel_energy[0]), + &(resource.subpixel_energy[1]), + &(resource.subpixel_energy[2])) + != 3) { + XDVI_ERROR((stderr, + "Illegal color mask `%s' for resource subpixels (should be: `n n n')\n", + ptr)); + } + } + + sum = (int)(resource.subpixel_energy[0] + + 2 * resource.subpixel_energy[1] + + 2 * resource.subpixel_energy[2]); + if (sum < 99 || sum > 100) { + XDVI_WARNING((stderr, "energy values %f + 2 * %f + 2 * %f don't sum up to 100%%!\n", + resource.subpixel_energy[0], resource.subpixel_energy[1], resource.subpixel_energy[2])); + exit(1); + } + + resource.subpixel_energy[0] /= 100.0; + resource.subpixel_energy[1] /= 100.0; + resource.subpixel_energy[2] /= 100.0; + fprintf(stderr, "subpixel order: %s = %d; [%f %f %f]\n", + resource.sub_pixels, resource.subpixel_order, + resource.subpixel_energy[0], resource.subpixel_energy[1], resource.subpixel_energy[2]); + } + } +#endif + + /* margins */ + if (resource.sidemargin) + resource.sidemargin_int = atopix(resource.sidemargin, False); + if (resource.topmargin) + resource.topmargin_int = atopix(resource.topmargin, False); + resource.xoffset_int = resource.xoffset ? atopix(resource.xoffset, True) + : resource.pixels_per_inch; + resource.yoffset_int = resource.yoffset ? atopix(resource.yoffset, True) + : resource.pixels_per_inch; + + /* paper type */ + if (!set_paper_type(resource.paper)) { + const char **p; + char *helpmsg = xstrdup("Possible paper types are:\n "); + for (p = paper_types; p < paper_types + XtNumber(paper_types); p += 2) { + if (**p == '\0') { /* next line of list */ + helpmsg = xstrcat(helpmsg, "\n "); + } + else { + helpmsg = xstrcat(helpmsg, *p); + helpmsg = xstrcat(helpmsg, " "); + } + } + helpmsg = xstrcat(helpmsg, + "\n(the names ending with `r' are `rotated' or `landscape' variants).\n" + "Alternatively, you can specify the dimensions as `WIDTHxHEIGHT', followed " + "by a dimension unit (one of: pt pc in bp cm mm dd cc sp)."); + /* also dump it to stderr ... */ + fprintf(stderr, + "Unrecognized value `%s' for paper type option; using a4 instead.\n%s\n", + resource.paper, helpmsg); + + popup_message(globals.widgets.top_level, + MSG_WARN, helpmsg, + "Unrecognized value `%s' for paper type option; using a4 instead.", resource.paper); + set_paper_type("a4"); + } + + /* magnifier sizes */ + for (i = 0; i < get_magglass_items(); ++i) { + if (resource.mg_arg[i] != NULL) { + char *s; + + mg_size[i].w = mg_size[i].h = atoi(resource.mg_arg[i]); + s = strchr(resource.mg_arg[i], 'x'); + if (s != NULL) { + mg_size[i].h = atoi(s + 1); + if (mg_size[i].h <= 0) + mg_size[i].w = 0; + } + } + } + +#ifdef PS + if (resource.safer) { + resource.allow_shell = False; +# ifdef PS_GS + resource.gs_safer = True; +# endif /* PS_GS */ + } +# ifdef PS_GS + { + const char *CGMcgm = "CGMcgm"; + const char *cgmp; + + cgmp = strchr(CGMcgm, resource.gs_palette[0]); + if (cgmp == NULL) + XDVI_FATAL((stderr, "Invalid value %s for gs palette option", resource.gs_palette)); + if (cgmp >= CGMcgm + 3) { + static char gsp[] = "x"; + + gsp[0] = *(cgmp - 3); + resource.gs_palette = gsp; + } + } +# endif /* PS_GS */ +#endif /* PS */ + + /* The old `-expert' flag overrides resource.expert_mode, `+expert' (or not + setting it) just uses expert_mode. + */ + if (resource.expert) + resource.expert_mode = XPRT_SHOW_NONE; +/* fprintf(stderr, "++++++++ initializing resource.expert_mode: %d\n", resource.expert_mode); */ + update_expert_mode(); +} + +static void +create_cursors(void) +{ + XColor bg_Color; + Pixmap temp; + Pixmap mask; + + /* first try colors by name, as fix for #804294; fall back on + WhitePixelOfScreen() etc. if this fails: + */ + if (resource.cr_Pixel != (Pixel)ULONG_MAX) { + m_cursor_color.pixel = resource.cr_Pixel; + XQueryColor(DISP, G_colormap, &m_cursor_color); + } + else { + if (XParseColor(DISP, G_colormap, "black", &m_cursor_color) == 0) { /* lookup failure */ + m_cursor_color.pixel = BlackPixelOfScreen(SCRN); + XQueryColor(DISP, G_colormap, &m_cursor_color); + } + } + if (XParseColor(DISP, G_colormap, "white", &bg_Color) == 0) { /* lookup failure */ + bg_Color.pixel = WhitePixelOfScreen(SCRN); + XQueryColor(DISP, G_colormap, &bg_Color); + } + + /* wait cursor */ +#if 0 /* this makes no big difference for #804294 */ + temp = XCreatePixmapFromBitmapData(DISP, RootWindowOfScreen(SCRN), + (char *)time16_bits, + time16_width, time16_height, + 1, 0, 1); + mask = XCreatePixmapFromBitmapData(DISP, RootWindowOfScreen(SCRN), + (char *)time16_mask_bits, + time16_mask_width, time16_mask_height, + 1, 0, 1); +#else + temp = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)time16_bits, + time16_width, time16_height); + mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)time16_mask_bits, + time16_mask_width, time16_mask_height); +#endif + globals.cursor.wait = XCreatePixmapCursor(DISP, temp, mask, + &m_cursor_color, &bg_Color, + time16_width / 2, time16_height / 2); + XFreePixmap(DISP, temp); + XFreePixmap(DISP, mask); + + /* ready cursor, magnifier by default */ + temp = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)magglass_bits, + magglass_width, magglass_height); + mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)magglass_mask_bits, + magglass_mask_width, magglass_mask_height); + + globals.cursor.ready = XCreatePixmapCursor(DISP, temp, mask, + &m_cursor_color, &bg_Color, + magglass_x_hot, magglass_y_hot); + XFreePixmap(DISP, temp); + XFreePixmap(DISP, mask); + + globals.cursor.corrupted = XCreateFontCursor(DISP, XC_watch); + +#if !COLOR + XRecolorCursor(DISP, globals.cursor.ready, &m_cursor_color, &bg_Color); + XRecolorCursor(DISP, globals.cursor.wait, &m_cursor_color, &bg_Color); +#endif + /* Cursor when page is paused */ +#ifdef VMS + temp = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)hand_bits, hand_width, hand_height); + mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)hand_mask_bits, hand_mask_width, hand_mask_height); + globals.cursor.pause = XCreatePixmapCursor(DISP, temp, mask, + &m_cursor_color, &bg_Color, 6, 6); + XFreePixmap(DISP, temp); + XFreePixmap(DISP, mask); +#else + globals.cursor.pause = XCreateFontCursor(DISP, XC_watch); +#endif + + /* cursors indicating dragging direction */ + temp = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)drag_vert_bits, + drag_vert_width, drag_vert_height); + mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)drag_vert_mask_bits, + drag_vert_mask_width, drag_vert_mask_height); + globals.cursor.drag_v = XCreatePixmapCursor(DISP, temp, mask, + &m_cursor_color, &bg_Color, + drag_vert_x_hot, drag_vert_y_hot); + XFreePixmap(DISP, temp); + XFreePixmap(DISP, mask); + + temp = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)drag_horiz_bits, + drag_horiz_width, drag_horiz_height); + mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)drag_horiz_mask_bits, + drag_horiz_width, drag_horiz_height); + globals.cursor.drag_h = XCreatePixmapCursor(DISP, temp, mask, + &m_cursor_color, &bg_Color, + drag_horiz_x_hot, drag_horiz_y_hot); + XFreePixmap(DISP, temp); + XFreePixmap(DISP, mask); + + temp = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)drag_omni_bits, + drag_omni_width, drag_omni_height); + mask = XCreateBitmapFromData(DISP, RootWindowOfScreen(SCRN), + (char *)drag_omni_mask_bits, + drag_omni_mask_width, drag_omni_mask_height); + globals.cursor.drag_a = XCreatePixmapCursor(DISP, temp, mask, + &m_cursor_color, &bg_Color, + drag_omni_x_hot, drag_omni_y_hot); + XFreePixmap(DISP, temp); + XFreePixmap(DISP, mask); + +#ifdef VMS + globals.cursor.link = globals.cursor.ready; + globals.cursor.rule = globals.cursor.ready; + globals.cursor.mag = globals.cursor.ready; + globals.cursor.text = globals.cursor.ready; +#else + globals.cursor.link = XCreateFontCursor(DISP, XC_hand2); + globals.cursor.rule = XCreateFontCursor(DISP, XC_crosshair); + globals.cursor.mag = XCreateFontCursor(DISP, XC_crosshair); + globals.cursor.text = XCreateFontCursor(DISP, XC_cross); + /* globals.cursor.text = XCreateFontCursor(DISP, XC_tcross); */ + XRecolorCursor(DISP, globals.cursor.mag, &m_cursor_color, &bg_Color); +#endif +} + +/* Initialize a forward search if the source_position argument is not NULL. */ +static void +do_forward_search(const char *source_position) +{ + /* parse the special to expand the filename */ + struct src_parsed_special data; + char *new_special = NULL; + char *expanded_filename = NULL; + + if (source_position == NULL) /* nothing to do */ + return; + + data.filename_len = 0; + data.filename = NULL; + + src_parse(source_position, strlen(source_position), &data); + + if (data.filename_len == 0) { /* malformed argument: tell user, and ignore it */ + popup_message(globals.widgets.top_level, + MSG_ERR, + /* helptext */ + "The format of the -sourceposition argument should be:\n" + "-sourceposition '<nn>[ ]*<filename'\n" + "with <nn> = linenumber, [ ]* = an arbitrary number of spaces, " + "and <filename> = TeX source file.", + /* error message */ + "Filename missing in `-sourceposition' argument \"%s\". " + "Could not perform forward search.", + source_position); + } + else { + TRACE_CLIENT((stderr, "got data: line %d, col %d, file |%s|, len %lu\n", + data.line, data.col, data.filename, (unsigned long)data.filename_len)); + + /* expand -sourceposition argument if it contains a path component, like above */ + if (strchr(data.filename, '/') != NULL + && (expanded_filename = expand_filename(data.filename, USE_CWD_PATH)) != NULL) { + char *tmp = canonicalize_path(expanded_filename); + free(data.filename); + free(expanded_filename); + expanded_filename = tmp; + } + else + expanded_filename = data.filename; + + TRACE_CLIENT((stderr, "expanded source_position: |%s|\n", expanded_filename)); + + new_special = xmalloc(2 * LENGTH_OF_INT + 2 /* 2 for `:' and separating space */ + + strlen(expanded_filename) + 1); + sprintf(new_special, "%d:%d %s", data.line, data.col, expanded_filename); + free(expanded_filename); + globals.src.fwd_string = new_special; + globals.ev.flags |= EV_SRC; + } +} + +static void +check_early_arguments(int argc, char **argv) +{ + /* This checks arguments that need to work before the X machinery is + * started (e.g. if no display is available, or for information that is + * needed before the X defaults are evaluated), so the `options' structure + * can't be used for them. + * + * We need to loop through all arguments in case xdvi is aliased, + * or called via a shell script (like in teTeX) that adds things + * like `-name' at the beginning of the arglist. + */ + int i; + Boolean install_err_handler = True; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-help") == 0 + || strcmp(argv[i], "-h") == 0 + || strcmp(argv[i], "+help") == 0 + || strcmp(argv[i], "--help") == 0) { + printf("%s version %s\n", XDVIK_PROGNAME, XDVI_VERSION_INFO); + printf("A DVI file previewer for the X window system.\n\n"); + display_licensing_info(); + display_bug_reporting_info(); + usage(0); + } + else if (strcmp(argv[i], "-license") == 0) { + display_long_licensing_info(); + xdvi_exit(EXIT_SUCCESS); + } + else if (strcmp(argv[i], "--version") == 0 + || strcmp(argv[i], "-version") == 0 + || strcmp(argv[i], "-v") == 0) { + display_version_info(); + xdvi_exit(EXIT_SUCCESS); + } + else if (strcmp(argv[i], "--default-xerr-handler") == 0) { /* hook to disable custom handler */ + install_err_handler = False; + } + } + + if (install_err_handler) { + (void)XSetErrorHandler(x_error_handler); + } +} + +static void +create_colormaps(void) +{ +#ifdef GREY + G_depth = (unsigned int)DefaultDepthOfScreen(SCRN); + G_visual = DefaultVisualOfScreen(SCRN); + G_colormap = DefaultColormapOfScreen(SCRN); +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- G_depth: %d\n", G_depth); +#endif + + if (resource.install != False && G_visual->class == PseudoColor) { + /* look for a TrueColor visual with more bits */ + XVisualInfo template; + XVisualInfo *list; + int nitems_return; +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- looking for a better TrueColor visual\n"); +#endif + + template.screen = XScreenNumberOfScreen(SCRN); + template.class = TrueColor; + list = XGetVisualInfo(DISP, VisualScreenMask | VisualClassMask, + &template, &nitems_return); + if (list != NULL) { + XVisualInfo *list1; + XVisualInfo *best = NULL; + + for (list1 = list; list1 < list + nitems_return; ++list1) { +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- checking %d\n", list1->depth); +#endif + if ((unsigned int)list1->depth > G_depth +# if PS_GS + /* patch by Toni Ronkko <tronkko@hytti.uku.fi>, fixes bug #458057: + * SGI supports additional depths of 12 and 30, but + * these are not supported by ghostscript (see + * xdev->vinfo->depth in gdevxcmp.c (ghostscript-6.51)), + * so we restrict the values to those supported by gs. + */ + && (list1->depth == 1 || list1->depth == 2 + || list1->depth == 4 || list1->depth == 8 + || list1->depth == 15 || list1->depth == 16 + || list1->depth == 24 || list1->depth == 32) +# endif + && (best == NULL || list1->depth > best->depth)) + best = list1; + } + if (best != NULL) { +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- best depth: %d\n", best->depth); +#endif + G_depth = best->depth; + G_visual = best->visual; + G_colormap = XCreateColormap(DISP, + RootWindowOfScreen(SCRN), + G_visual, AllocNone); + XInstallColormap(DISP, G_colormap); + temp_args1[0].value = (XtArgVal) G_depth; + temp_args1[1].value = (XtArgVal) G_visual; + temp_args1[2].value = (XtArgVal) G_colormap; + XtSetValues(globals.widgets.top_level, temp_args1, XtNumber(temp_args1)); + XtSetTypeConverter(XtRString, XtRPixel, + XdviCvtStringToPixel, + (XtConvertArgList) colorConvertArgs, 2, + XtCacheByDisplay, NULL); + { + /* This is needed so that popup windows have the right + visual and colormap. It is unnecessary for newer + versions of Motif (Motif 2.1.0, Solaris 9) but + needed for older versions (Motif 1.2.5, Solaris 2.6), + and for Xaw. + */ + XrmDatabase db = XtScreenDatabase(SCRN); + XrmValue val; + + val.size = sizeof G_visual; + val.addr = (XtPointer) &G_visual; + XrmPutResource(&db, "XDvi*visual", XtRVisual, &val); + + val.size = sizeof G_colormap; + val.addr = (XtPointer) &G_colormap; + XrmPutResource(&db, "XDvi*colormap", XtRColormap, &val); + } + } + XFree(list); + } + } + +#ifdef MOTIF + if (globals.debug & DBG_GUI) { + printf("Compiled with %s, runtime version %d.%d\n", + /* XmVERSION, XmREVISION, XmUPDATE_LEVEL, */ + XmVERSION_STRING, + xmUseVersion / 1000, xmUseVersion % 1000); + } +#endif + + if (resource.install == True && G_visual->class == PseudoColor) { + XColor tmp_color; +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- PseudoColor, trying to install colormap\n"); +#endif + + /* This next bit makes sure that the standard black and white pixels + are allocated in the new colormap. */ + tmp_color.pixel = BlackPixelOfScreen(SCRN); + XQueryColor(DISP, G_colormap, &tmp_color); + XAllocColor(DISP, G_colormap, &tmp_color); + + tmp_color.pixel = WhitePixelOfScreen(SCRN); + XQueryColor(DISP, G_colormap, &tmp_color); + XAllocColor(DISP, G_colormap, &tmp_color); + + G_colormap = XCopyColormapAndFree(DISP, G_colormap); + temp_args1[2].value = (XtArgVal) G_colormap; + XtSetValues(globals.widgets.top_level, temp_args1 + 2, 1); + } + + XtGetApplicationResources(globals.widgets.top_level, (XtPointer)&resource, + app_pixel_resources, XtNumber(app_pixel_resources), + (ArgList)NULL, 0); + +#endif /* GREY */ + + globals.gc.do_copy = resource.copy; + +#if GREY || COLOR + color_data[0].pixel = resource.fore_Pixel; + color_data[1].pixel = resource.back_Pixel; + XQueryColors(DISP, G_colormap, color_data, 2); +#endif + +#if COLOR + fg_initial.r = color_data[0].red; + fg_initial.g = color_data[0].green; + fg_initial.b = color_data[0].blue; + bg_initial.r = color_data[1].red; + bg_initial.g = color_data[1].green; + bg_initial.b = color_data[1].blue; + +#endif + +#if GREY + if (G_depth == 1) { +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- using depth 1\n"); +#endif + resource.use_grey = False; + } + if (resource.use_grey && G_visual->class != TrueColor) { +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- using grey, but not TrueColor\n"); +#endif + init_plane_masks(); + if (!globals.gc.do_copy) { + /* Retain color_data[1].pixel for psgs.c. */ + XColor tmp_color; +#ifdef XSERVER_INFO + if (globals.debug & DBG_ALL) + fprintf(stdout, "--- not using copy\n"); +#endif + + tmp_color = color_data[1]; + tmp_color.pixel = resource.back_Pixel; + XStoreColor(DISP, G_colormap, &tmp_color); + } + } +#endif +} + +static void +create_widgets( +#ifdef MOTIF + Widget tool_bar, Widget form, +#endif + int *add_w, int *add_h) +{ + static const char default_key_translations[] = + "\"0\":digit(0)\n" + "\"1\":digit(1)\n" + "\"2\":digit(2)\n" + "\"3\":digit(3)\n" + "\"4\":digit(4)\n" + "\"5\":digit(5)\n" + "\"6\":digit(6)\n" + "\"7\":digit(7)\n" + "\"8\":digit(8)\n" + "\"9\":digit(9)\n" + /* "\"-\":minus()\n" */ + "<Motion>:motion()\n"; + + static const char default_mouse_translations[] = + "<BtnUp>:release()"; + +#ifdef MOTIF + Widget status_line; + +#if 0 + { + int i, n, longest_page = 0; + Dimension width, height; + char tmpbuf[1024]; + char *fontname; + XmString tmpstring; + Widget dummy_list; + XmRendition rendition; + XmRenderTable rtable; + Arg args[10]; + /* + * Try to determine width of longest page string: + */ + for (i = 0; i < total_pages; i++) { + int curr = abs(pageinfo_get_number(i)); + if (curr > longest_page) + longest_page = curr; + } + fprintf(stderr, "longest page number: %d\n", longest_page); + sprintf(tmpbuf, "* %d", longest_page); + tmpstring = XmStringCreateLocalized(tmpbuf); + dummy_list = XtCreateWidget("PageList", xmListWidgetClass, form, NULL, 0); + fprintf(stderr, "rendition table\n"); + n = 0; +/* XtVaGetValues(globals.widgets.top_level, XmNfontList, &fontname, NULL); */ +/* fprintf(stderr, "fontname: |%s|\n", fontname); */ + XtSetArg(args[n], XmNfontName, "8x16"); n++; + XtSetArg(args[n], XmNfontType, XmFONT_IS_FONT); n++; + rendition = XmRenditionCreate(dummy_list, XmFONTLIST_DEFAULT_TAG, args, n); + rtable = XmRenderTableAddRenditions(NULL, &rendition, 1, XmMERGE_REPLACE); + XtVaSetValues(dummy_list, XmNrenderTable, rtable, NULL); + + /* rendition = XmRenditionCreate(globals.widgets.top_level, XmFONTLIST_DEFAULT_TAG, NULL, 0); */ + fprintf(stderr, "extent\n"); + XmStringExtent(rtable, tmpstring, &width, &height); + fprintf(stderr, "string %s has width %d, height %d\n", tmpbuf, width, height); + XtDestroyWidget(dummy_list); + XmRenditionFree(rendition); + XmStringFree(tmpstring); + } +#endif + { +#define ARG_LEN 20 + int n = 0; + Arg list_args[ARG_LEN]; + + XtSetArg(list_args[n], XmNlistSizePolicy, XmVARIABLE); n++; + XtSetArg(list_args[n], XmNwidth, resource.pagelist_width); n++; +#if defined(USE_PANNER) && USE_XAW_PANNER + XtSetArg(list_args[n], XmNheight, globals.page.h - 62); n++; +#else + XtSetArg(list_args[n], XmNheight, globals.page.h); n++; +#endif +/* XtSetArg(list_args[n], XmNspacing, 10); n++; */ +#if defined(USE_PANNER) && USE_XAW_PANNER + XtSetArg(list_args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; + XtSetArg(list_args[n], XmNtopWidget, panner); n++; +#else + XtSetArg(list_args[n], XmNtopAttachment, XmATTACH_FORM); n++; +#endif + XtSetArg(list_args[n], XmNbottomAttachment, XmATTACH_FORM); n++; + XtSetArg(list_args[n], XmNleftAttachment, XmATTACH_FORM); n++; + XtSetArg(list_args[n], XmNrightAttachment, XmATTACH_OPPOSITE_FORM); n++; + XtSetArg(list_args[n], XmNrightOffset, -resource.pagelist_width); n++; + XtSetArg(list_args[n], XmNresizable, True); n++; + XtSetArg(list_args[n], XmNtopOffset, 2); n++; + XtSetArg(list_args[n], XmNleftOffset, 2); n++; + ASSERT(n < ARG_LEN, "list_args too short"); +#undef ARG_LEN + /* TODO: Find a smart way to determine size of pagelist instead of using resource.pagelist_width, + and find a smart way of resizing it when switching to a file with larger page numbers! + */ + page_list = XmCreateScrolledList(form, "PageList", list_args, n); + } + + if (resource.expert_mode == XPRT_SHOW_NONE) { + XtUnmanageChild(XtParent(page_list)); + XtUnmanageChild(page_list); + } + + globals.widgets.main_window = XtVaCreateManagedWidget("mainWindow", + xmScrolledWindowWidgetClass, form, + XmNscrollingPolicy, XmAUTOMATIC, + XmNleftAttachment, XmATTACH_WIDGET, + /* lesstif balks if we just use page_list, so use its parent, + the xmScrolledWindow, for alignment: */ + XmNleftWidget, XtParent(page_list), + XmNallowResize, True, +/* XmNtopOffset, 2, */ + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + /* XmNleftOffset, 10, */ + XmNresizable, True, + XmNborderWidth, 0, + NULL); + XtManageChild(form); + + globals.widgets.x_bar = XtNameToWidget(globals.widgets.main_window, "HorScrollBar"); + globals.widgets.y_bar = XtNameToWidget(globals.widgets.main_window, "VertScrollBar"); + + +#ifdef TEST_SCROLLING + /* TODO: try the following to prevent `flashing' effect - still breaks + scrolling in its current form though */ + globals.widgets.draw_background = XtVaCreateManagedWidget("drawing_bg", + xmFormWidgetClass, globals.widgets.main_window, + XmNwidth, globals.page.w, + XmNheight, globals.page.h, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNhighlightThickness, 0, + XmNbackground, resource.back_Pixel, + XmNrubberPositioning, True, + NULL); +#endif + globals.widgets.draw_widget = XtVaCreateWidget("drawing", + xmDrawingAreaWidgetClass, +#ifdef TEST_SCROLLING + globals.widgets.draw_background, +#else + globals.widgets.main_window, +#endif + XmNwidth, globals.page.w, + XmNheight, globals.page.h, + XmNhighlightThickness, 0, + XmNrubberPositioning, True, + XtNbackground, resource.back_Pixel, + NULL); + +#if !FIXED_FLUSHING_PAGING + ASSERT(XtParent(globals.widgets.draw_widget) != NULL, ""); + XtVaSetValues(XtParent(globals.widgets.draw_widget), XtNbackground, resource.back_Pixel, NULL); +#endif + +#ifdef TEST_SCROLLING + fprintf(stderr, "globals.widgets.draw_widget is: %p\n", globals.widgets.draw_widget); +#endif + XtVaGetValues(globals.widgets.main_window, XmNclipWindow, &globals.widgets.clip_widget, NULL); + + XtVaSetValues(globals.widgets.main_row, + XmNmenuBar, globals.widgets.menu_bar, + XmNcommandWindow, XtParent(tool_bar), + XmNworkWindow, form, + NULL); + + XtVaSetValues(globals.widgets.main_window, + XmNworkWindow, globals.widgets.draw_widget, + NULL); + + XtManageChild(globals.widgets.draw_widget); + + status_line = create_statusline(globals.widgets.main_row); + XtVaSetValues(globals.widgets.main_row, + XmNmessageWindow, status_line, + NULL); + if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) { + XtUnmanageChild(status_line); + } + + XtManageChild(globals.widgets.main_row); + + if ((resource.expert_mode & XPRT_SHOW_TOOLBAR) != 0) { + if (resource.toolbar_unusable) + statusline_print(STATUS_LONG, + "Error creating the toolbar pixmaps - toolbar is disabled!"); + else + XtManageChild(XtParent(tool_bar)); + } + + if ((resource.expert_mode & XPRT_SHOW_MENUBAR) != 0) + XtManageChild(globals.widgets.menu_bar); + + XmAddTabGroup(globals.widgets.draw_widget); + + /* + note: a few more custom translations for page_list are defined in + pagesel.c, since the actions are only known there. + */ + { + size_t i, k = 0; +#define WIDGETS_SIZE 10 + Widget widgets[WIDGETS_SIZE]; + + widgets[k++] = globals.widgets.main_row; +/* widgets[k++] = globals.widgets.menu_bar; */ + widgets[k++] = tool_bar; + widgets[k++] = page_list; + widgets[k++] = globals.widgets.main_window; + widgets[k++] = globals.widgets.draw_widget; + widgets[k++] = globals.widgets.clip_widget; + + ASSERT(k < WIDGETS_SIZE, "widgets list too short"); +#undef WIDGETS_SIZE + for (i = 0; i < k; i++) { + XtOverrideTranslations(widgets[i], XtParseTranslationTable(base_key_translations)); + XtOverrideTranslations(widgets[i], XtParseTranslationTable(default_key_translations)); + if (i > 3) { /* widgets for which we want to use our own mouse translations */ + XtOverrideTranslations(widgets[i], XtParseTranslationTable(base_mouse_translations)); + XtOverrideTranslations(widgets[i], XtParseTranslationTable(default_mouse_translations)); + } + } + } + + if (resource.main_translations != NULL) { + XtOverrideTranslations(globals.widgets.draw_widget, XtParseTranslationTable(resource.main_translations)); + XtOverrideTranslations(globals.widgets.clip_widget, XtParseTranslationTable(resource.main_translations)); + /* don't do it for the page list, otherwise mouse customizations will break + the default list bindings too. */ + /* XtOverrideTranslations(page_list, XtParseTranslationTable(resource.main_translations)); */ + } + /* widgets for which wheel mouse should scroll the drawing area */ + if (resource.wheel_unit != 0 && resource.wheel_translations != NULL) { + XtOverrideTranslations(globals.widgets.main_row, XtParseTranslationTable(resource.wheel_translations)); + XtOverrideTranslations(tool_bar, XtParseTranslationTable(resource.wheel_translations)); + XtOverrideTranslations(globals.widgets.main_window, XtParseTranslationTable(resource.wheel_translations)); + XtOverrideTranslations(globals.widgets.draw_widget, XtParseTranslationTable(resource.wheel_translations)); +/* XtOverrideTranslations(globals.widgets.draw_background, XtParseTranslationTable(resource.wheel_translations)); */ + } + +#else /* MOTIF */ + + globals.widgets.form_widget = XtVaCreateManagedWidget("form", formWidgetClass, globals.widgets.top_level, + XtNdefaultDistance, 0, + NULL); + globals.widgets.vport_widget = XtVaCreateManagedWidget("vport", viewportWidgetClass, + globals.widgets.form_widget, + XtNborderWidth, 0, + XtNtop, XtChainTop, + XtNbottom, XtChainBottom, + XtNleft, XtChainLeft, + XtNright, XtChainRight, + XtNallowHoriz, True, + XtNallowVert, True, + NULL); + globals.widgets.clip_widget = XtNameToWidget(globals.widgets.vport_widget, "clip"); + + globals.widgets.draw_widget = XtVaCreateManagedWidget("drawing", drawWidgetClass, globals.widgets.vport_widget, + XtNwidth, globals.page.w, + XtNheight, globals.page.h, + XtNx, 0, + XtNy, 0, + XtNlabel, "", + NULL); + + XtOverrideTranslations(globals.widgets.form_widget, XtParseTranslationTable(base_key_translations)); + XtOverrideTranslations(globals.widgets.form_widget, XtParseTranslationTable(base_mouse_translations)); + XtOverrideTranslations(globals.widgets.form_widget, XtParseTranslationTable(default_key_translations)); + XtOverrideTranslations(globals.widgets.form_widget, XtParseTranslationTable(default_mouse_translations)); + + if (resource.wheel_unit != 0 && resource.wheel_translations != NULL) + XtOverrideTranslations(globals.widgets.form_widget, XtParseTranslationTable(resource.wheel_translations)); + + if (resource.main_translations != NULL) { + XtOverrideTranslations(globals.widgets.form_widget, XtParseTranslationTable(resource.main_translations)); + } + + + /* set background colors of the drawing widget */ + XtVaSetValues(globals.widgets.draw_widget, XtNbackground, resource.back_Pixel, NULL); + +#if !FIXED_FLUSHING_PAGING + XtVaSetValues(globals.widgets.clip_widget, XtNbackground, resource.back_Pixel, NULL); +#endif + + /* initialize add_w with width of button panel */ + if ((resource.expert_mode & XPRT_SHOW_BUTTONS) != 0) + create_menu_buttons(globals.widgets.form_widget, add_w); + else + *add_w = 0; +#endif /* MOTIF */ + + /* activate expert mode and related settings */ + toggle_statusline(); + toggle_scrollbars(); +#ifdef MOTIF + toggle_pagelist(); + toggle_toolbar(); + toggle_menubar(); +#else + toggle_buttons(); +#endif + +#ifdef MOTIF + *add_w = 0; + if (resource.expert_mode & XPRT_SHOW_PAGELIST) + *add_w += xm_get_width(page_list); +/* if (globals.widgets.y_bar != NULL) */ +/* add_w += xm_get_width(globals.widgets.y_bar); */ + *add_h = 0; + if (resource.expert_mode & XPRT_SHOW_MENUBAR) + *add_h += xm_get_height(globals.widgets.menu_bar); + if (resource.expert_mode & XPRT_SHOW_TOOLBAR) + *add_h += xm_get_height(tool_bar); + if (resource.expert_mode & XPRT_SHOW_STATUSLINE) + *add_h += xm_get_height(status_line); +/* if (globals.widgets.x_bar != NULL) */ +/* add_h += xm_get_width(globals.widgets.x_bar); */ +#else + /* add_w has been initialized by create_menu_buttons() call above */ + *add_h = 0; +#endif +} + + +static void +realize_widgets(Dimension main_win_w, Dimension main_win_h, int add_w) +{ + /* + * Realize the widgets (or windows). + */ + +#ifndef MOTIF + if ((resource.expert_mode & XPRT_SHOW_BUTTONS) != 0) { + set_button_panel_height(main_win_h); + } +#endif + XtAddEventHandler( +#ifdef MOTIF + globals.widgets.clip_widget, +#else + globals.widgets.vport_widget, +#endif + StructureNotifyMask, False, + handle_resize, (XtPointer) NULL); + + XtAddEventHandler(globals.widgets.top_level, PropertyChangeMask, False, + handle_property_change, (XtPointer) NULL); + XtAddEventHandler(globals.widgets.draw_widget, ExposureMask, False, handle_expose, + (XtPointer) &mane); + XtRealizeWidget(globals.widgets.top_level); + + mainDeleteWindow = XInternAtom(DISP, "WM_DELETE_WINDOW", False); + +#ifdef MOTIF + /* for Xaw, event handlers for scrollbars are added inside get_geom(), events.c */ + ASSERT(globals.widgets.x_bar != NULL, ""); + ASSERT(globals.widgets.y_bar != NULL, ""); + XtAddEventHandler(globals.widgets.x_bar, ButtonPressMask | ButtonReleaseMask, False, handle_x_scroll, NULL); + XtAddEventHandler(globals.widgets.y_bar, ButtonPressMask | ButtonReleaseMask, False, handle_y_scroll, NULL); + XmAddWMProtocolCallback(globals.widgets.top_level, mainDeleteWindow, xdvi_exit_callback, NULL); +#else + wmProtocols = XInternAtom(DISP, "WM_PROTOCOLS", False); + XSetWMProtocols(DISP, XtWindow(globals.widgets.top_level), &mainDeleteWindow, 1); + XtAddEventHandler(globals.widgets.top_level, NoEventMask, True, handle_delete_message, NULL); +#endif + + /* check whether we want to run in fullscreen mode */ + if (resource.fullscreen) { + reconfigure_window(resource.fullscreen, main_win_w + add_w, main_win_h, False); + } + +#ifdef MOTIF + XmProcessTraversal(globals.widgets.draw_widget, XmTRAVERSE_CURRENT); + TRACE_GUI((stderr, "toplevel: %p", (void *)globals.widgets.top_level)); + create_tips(globals.widgets.top_level); +#else + if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) { + create_statusline(); + } +#endif + + currwin.win = mane.win = XtWindow(globals.widgets.draw_widget); + + { + XWindowAttributes attrs; + + (void)XGetWindowAttributes(DISP, mane.win, &attrs); + G_backing_store = attrs.backing_store; + } + +#ifdef HAVE_X11_XMU_EDITRES_H + /* + * Enable editres protocol (see "man editres"). + * Usually will need to add -lXmu to the linker line as well. + */ + XtAddEventHandler(globals.widgets.top_level, (EventMask)0, True, _XEditResCheckMessages, + (XtPointer)NULL); +#endif +} + +/* + * Create colors and GCs. + * In color mode, color changes affect globals.gc.fore, globals.gc.fore2, + * and globals.gc.rule, but not globals.gc.copy or globals.gc.high. + */ +static void +create_gcs(void) +{ + +#if GREY + if (resource.gamma == 0.0) + resource.gamma = 1.0; +#endif + + if (!resource.rule_color) + resource.rule_pixel = resource.fore_Pixel; + +#if !COLOR + +#if GREY + if (resource.use_grey) + init_pix(); + else +#endif + { /* not #defined GREY, or not resource.use_grey */ + XGCValues values; + Pixel set_bits = (Pixel) (resource.fore_Pixel & ~resource.back_Pixel); + Pixel clr_bits = (Pixel) (resource.back_Pixel & ~resource.fore_Pixel); + Boolean copy_tmp = resource.copy; + + globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel); + if (copy_tmp || (set_bits && clr_bits)) { + globals.gc.rule = globals.gc.copy; + if (!resource.thorough) + copy_tmp = True; + } + if (copy_tmp) { + globals.gc.fore = globals.gc.rule; + if (!resource.copy) { + warn_overstrike(); + } + } + else { + if (set_bits) { + globals.gc.fore = set_or_make_gc(NULL, GXor, set_bits, 0); + } + if (clr_bits || !set_bits) + *(globals.gc.fore ? &globals.gc.fore2 : &globals.gc.fore) = set_or_make_gc(NULL, GXandInverted, clr_bits, 0); + if (!globals.gc.rule) + globals.gc.rule = globals.gc.fore; + } + } +#endif /* !COLOR */ + + { + Pixel link_pix, visited_link_pix; + get_link_colors(&link_pix, &visited_link_pix); + globals.gc.linkcolor = set_or_make_gc(NULL, GXcopy, link_pix, resource.back_Pixel); + globals.gc.visited_linkcolor = set_or_make_gc(NULL, GXcopy, visited_link_pix, resource.back_Pixel); + } + +#if COLOR + /* Not affected by color changes. */ + globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel); +#endif + globals.gc.high = set_or_make_gc(NULL, GXcopy, resource.hl_Pixel, resource.back_Pixel); + + globals.gc.ruler = set_or_make_gc(NULL, GXcopy, resource.rule_pixel, resource.fore_Pixel); + +#if XAW + /* + * There's a bug in the Xaw toolkit, in which it uses the + * DefaultGCOfScreen to do vertical scrolling in the Text widget. + * This leads to a BadMatch error if our visual is not the default one. + * The following kludge works around this. + */ + DefaultGCOfScreen(SCRN) = globals.gc.copy; +#endif +} + +static void +do_fork(void) +{ + TRACE_CLIENT((stderr, "no other instance of xdvi found, forking ...")); + /* + * No suitable xdvi found, so we start one by + * self-backgrounding. + */ + /* flush output buffers to avoid double buffering (i.e. data + waiting in the output buffer being written twice, by the parent + and the child) */ + fflush(stdout); + fflush(stderr); + XFlush(DISP); + if (fork()) /* if initial process (do NOT use vfork()!) */ + _exit(0); +} + +#if defined(MOTIF) && defined(USE_PANNER) && USE_XAW_PANNER +static void +panner_cb(Widget widget, XtPointer closure, XtPointer report_ptr) +{ + fprintf(stderr, "panner_cb called!\n"); +} +#endif + + +static XtIntervalId m_font_popup_id = 0; +static Widget m_font_popup = 0; + +static void +remove_font_popup(XtPointer client_data, XtIntervalId *id) +{ + UNUSED(client_data); + UNUSED(id); + + if (m_font_popup != 0) { + kill_message_window(m_font_popup); + } +} + +static void +remove_font_popup_exit_cb(XtPointer arg) +{ + UNUSED(arg); + xdvi_exit(EXIT_SUCCESS); +} + +static void +create_font_popup(XtPointer client_data, XtIntervalId *id) +{ + int *curr_timeout = (int *)client_data; + static int new_timeout = 0; + + UNUSED(client_data); + UNUSED(id); + + if (m_font_popup_id) { + if (*curr_timeout > 0) { + XtRemoveTimeOut(m_font_popup_id); + m_font_popup_id = XtAppAddTimeOut(app, *curr_timeout, create_font_popup, (XtPointer)&new_timeout); + } + else { + m_font_popup = choice_dialog(globals.widgets.top_level, + MSG_INFO, NULL, +#ifndef MOTIF + NULL, +#endif + NULL, NULL, /* no pre_callbacks */ + NULL, NULL, NULL, /* default arguments for `OK' */ + "Exit Xdvi", remove_font_popup_exit_cb, (XtPointer)NULL, + "Loading %s\n(may take some time creating fonts ...)", + globals.dvi_name); + } + } +} + +static void +register_font_popup(void) +{ + /* Use a two-step process, so that when the timeout is removed by unregister_font_popup(), + it will occur before new_timeout. create_font_popup() will call XtAppAddTimeOut() again + with new_timeout = 0. + */ + static int new_timeout = 50; + m_font_popup_id = XtAppAddTimeOut(app, 700, create_font_popup, (XtPointer)&new_timeout); +} + +static void +unregister_font_popup(void) +{ + if (m_font_popup_id) { + XtRemoveTimeOut(m_font_popup_id); + m_font_popup_id = 0; + /* FIXME: calling this directly crashes xdvi?? */ + /* m_font_popup_id = XtAppAddTimeOut(app, 1, remove_font_popup, (XtPointer)NULL); */ + remove_font_popup(NULL, NULL); + } +} + +/* initialize global variables with default values. */ +static void +init_globals(void) { + globals.program_name = NULL; + globals.dvi_name = NULL; + globals.xdvi_dir = xgetcwd(); + globals.orig_locale = NULL; + globals.debug = 0L; + globals.pageno_correct = 1; + + globals.curr_paper = NULL; + globals.curr_editor = NULL; + globals.curr_browser = NULL; + + globals.ev.flags = EV_IDLE; + globals.ev.ctr = 0; + + globals.pausing.num = 0; + globals.pausing.num_save = NULL; + globals.pausing.flag = False; + + globals.win_expose.min_x = 0; + globals.win_expose.max_x = 0; + globals.win_expose.min_y = 0; + globals.win_expose.max_y = 0; + + globals.gc.rule = NULL; + globals.gc.fore = NULL; + globals.gc.inverted = NULL; + globals.gc.high = NULL; + globals.gc.linkcolor = NULL; + globals.gc.visited_linkcolor = NULL; + globals.gc.fore2 = NULL; + globals.gc.fore2_bak = NULL; + globals.gc.fore2_bak1 = NULL; + globals.gc.copy = NULL; + globals.gc.ruler = NULL; + + globals.gc.do_copy = False; + + globals.cursor.flags = 0; + + globals.src.fwd_box_page = -1; /* -1 means no box */ + globals.src.fwd_string = NULL; + + globals.widgets.top_level = 0; + globals.widgets.draw_widget = 0; + globals.widgets.draw_background = 0; + globals.widgets.clip_widget = 0; + globals.widgets.x_bar = 0; + globals.widgets.y_bar = 0; +#ifdef MOTIF + globals.widgets.main_window = 0; + globals.widgets.main_row = 0; + globals.widgets.tool_bar = 0; + globals.widgets.top_row = 0; + globals.widgets.menu_bar = 0; +#else + globals.widgets.vport_widget = 0; + globals.widgets.form_widget = 0; + globals.widgets.paned = 0; +#endif + + globals.page.w = 0; + globals.page.h = 0; + globals.page.unshrunk_w = 0; + globals.page.unshrunk_h = 0; + + globals.dvi_file.dirname = NULL; + globals.dvi_file.dirlen = 0; + globals.dvi_file.bak_fp = NULL; + globals.dvi_file.time = 0; + +#if defined(LESSTIF_VERSION) + globals.broken_motif_event_handling = True; +#elif defined(MOTIF) /* was: && XmVersion <= 1002 - better use runtime information:*/ + if (xmUseVersion <= 1002) + globals.broken_motif_event_handling = True; + else + globals.broken_motif_event_handling = False; +#else + globals.broken_motif_event_handling = False; +#endif + +} + +/* revert resources */ +void +reload_app_resources(void) +{ +/* /\* reset some resources to built-in defaults *\/ */ +/* resource.browser = NULL; */ +/* resource.editor = NULL; */ +/* resource.gamma = 1; */ +/* resource.link_style = 3; */ +/* resource.link_color = LINK_COLOR_FALLBACK; */ +/* resource.visited_link_color = VISITED_LINK_COLOR_FALLBACK; */ +/* resource.expert_mode = 31; */ +/* resource.use_color = True; */ +/* resource.match_highlight_inverted = True; */ + + XtGetApplicationResources(globals.widgets.top_level, (XtPointer)&resource, + application_resources, XtNumber(application_resources), + (ArgList)NULL, 0); + XtGetApplicationResources(globals.widgets.top_level, (XtPointer)&resource, + app_pixel_resources, XtNumber(app_pixel_resources), + (ArgList)NULL, 0); +/* fprintf(stderr, "gamma: %f\n", resource.gamma); */ +} + +struct filehist_info { + int file_idx; + char *page_arg; +}; + + +/* + * Unfortunately this must be a callback, for the file selector ... + * This is the second part of Main: Create all widgets, initialize the DVI file, + * and enter the main event loop. + */ +static void +run_dvi_file(const char *filename, void *data) +{ + Boolean tried_dvi_ext = False; + struct filehist_info *cb = (struct filehist_info *)data; + +#ifdef MOTIF + Widget tool_bar = 0; + Widget form = 0; +#endif + + char *title_name = NULL; + char *icon_name = NULL; + dviErrFlagT errflag = NO_ERROR; + + int add_w, add_h; + Dimension main_win_w, main_win_h; + + UNUSED(data); + ASSERT(filename != NULL, "filename must have been initialized here!"); + + globals.dvi_name = xstrdup(filename); + file_history_push(globals.dvi_name); + + TRACE_FILES((stderr, "globals.dvi_name is: |%s| %p\n", globals.dvi_name, globals.dvi_name)); + + globals.dvi_file.dirname = get_dir_component(globals.dvi_name); + ASSERT(globals.dvi_file.dirname != NULL, "dvi_name must contain a dir component"); + globals.dvi_file.dirlen = strlen(globals.dvi_file.dirname); + + form_dvi_property(); + + /* + If `unique' is active, we may need to pass the file + to a different instance of xdvi: + */ + if (resource.unique) { + Window w1 = 0, w2 = 0; + if ((w1 = get_xdvi_window_id(True, NULL)) != 0 || (w2 = get_xdvi_window_id(False, NULL)) != 0) { + if (w1 != 0) { /* another xdvi, and same file: reload and raise */ + w2 = w1; + set_string_property("", atom_reload(), w2); + set_string_property("", atom_raise(), w2); + } + else { /* another xdvi, and different file: load new file and raise */ + set_string_property(globals.dvi_name, atom_newdoc(), w2); + set_string_property("", atom_raise(), w2); + } + if (cb->page_arg != NULL) { /* switch to different page and raise */ + if (strlen(cb->page_arg) == 0) /* special case: treat `+' as last page */ + set_string_property("+", atom_newpage(), w2); + else + set_string_property(cb->page_arg, atom_newpage(), w2); + set_string_property("", atom_raise(), w2); + } + xdvi_exit(EXIT_SUCCESS); + } + else if (resource.src_fork) { + do_fork(); + } + } + + /* + Similar for forward search or string search: + */ + if (resource.src_pos != NULL || resource.find_string != NULL) { + Window w; + if ((w = get_xdvi_window_id(True, NULL)) != 0) { + /* another instance of xdvi running, displaying the same file */ + TRACE_CLIENT((stderr, "Match; changing property of client and exiting ...")); + if (resource.src_pos != NULL) + set_sourceposition_property(resource.src_pos, w); + else + set_stringsearch_property(resource.find_string, w); + xdvi_exit(EXIT_SUCCESS); + } + else if (resource.src_fork) { + do_fork(); + } + } + + /* Needed for source specials and for calling ghostscript. */ + xputenv("DISPLAY", XDisplayString(DISP)); + + + if (globals.debug) { + fprintf(stderr, "%s %s, kpathsea: %s\n", XDVIK_PROGNAME, XDVI_VERSION_INFO, kpathsea_version_string); + fprintf(stderr, + "configured with: ppi=%d shrink=%d mfmode=%s alt_font=%s paper=%s\n", + resource.pixels_per_inch, + currwin.shrinkfactor, + resource.mfmode ? resource.mfmode : "<NONE>", + resource.alt_font, + resource.paper); + } + +#ifdef T1LIB + /* needed so that T1lib can produce tfm's e.g. for cm-super */ + kpse_set_program_enabled(kpse_tfm_format, True, kpse_src_compile); +#endif + kpse_set_program_enabled(kpse_any_glyph_format, resource.makepk, kpse_src_compile); + /* janl 16/11/98: I have changed this. The above line used to + say the settings in resource.makepk was supplied on the + commandline, resulting in it overriding _all other_ + settings, derived from the environment or texmf.cnf, no + matter what the value. The value in resource.makepk could + be the compile-time default... + + Personaly I like the environment/texmf.cnf to override + resources and thus changed the 'level' of this setting to + kpse_src_compile so the environment/texmf.cnf will override + the values derived by Xt. + + Previous comment here: + + ``Let true values as an X resource/command line override false + values in texmf.cnf/envvar.'' */ + + /* + * Step 2: Settle colormap issues. This should be done before + * other widgets are created, so that they get the right + * pixel values. (The top-level widget won't have the right + * values, but I don't think that makes any difference.) + */ + +#ifdef XSERVER_INFO + print_xserver_info(); +#endif + + create_colormaps(); + + +#ifdef TESTING_OPEN_FILES + fprintf(stderr, "open_max: %ld\n", OPEN_MAX); + for (i = 0; i < OPEN_MAX - 10; i++) { + FILE *fp; + if ((fp = fopen("/tmp/foo", "r")) == NULL) { + perror("fopen"); + xdvi_exit(EXIT_FAILURE); + } + } + fprintf(stderr, "opened %d files.\n", i); +#endif + + + /* toolbar code may open files, but we have no check close_a_file() in + the toolbar code; so do this before prescan() possibly opens lots of files. + */ +#ifdef MOTIF + globals.widgets.main_row = XmCreateMainWindow(globals.widgets.top_level, "main", NULL, 0); + + create_menu_buttons(globals.widgets.main_row, &globals.widgets.menu_bar); + + /* seems to be needed for enabling `XmNhighlightOnEnter' for the toolbar buttons + - is this the correct place to do it? */ + XtVaSetValues(globals.widgets.top_level, XmNkeyboardFocusPolicy, (XtArgVal)XmPOINTER, NULL); + + form = XtVaCreateWidget("form", xmFormWidgetClass, globals.widgets.main_row, + XmNshadowThickness, 0, + NULL); +#if defined(USE_PANNER) && USE_XAW_PANNER + panner = XtVaCreateWidget("panner", pannerWidgetClass, form, + XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 20, + XmNrightAttachment, XmATTACH_OPPOSITE_FORM, + XmNrightOffset, -resource.pagelist_width + 20, + XmNtopOffset, 2, + XmNleftOffset, 2, + XtNheight, 60, + XtNwidth, resource.pagelist_width - 50, + XtNsliderX, 5, + XtNsliderY, 7, + XtNinternalSpace, 0, + XtNshadowThickness, 0, + NULL); +#endif +#endif + + /* use bounding box for highlighting if our visual isn't TrueColor + (not worth the trouble ...) */ + if (G_visual->class != TrueColor) { + resource.match_highlight_inverted = False; + } + + /* + * Step 3: Initialize the dvi file and set titles. + */ + +#ifdef T1LIB + /* + At this point DISP, G_visual, G_depth and G_colormap must + be defined. Also, init_t1() must go before internal_open_dvi(), since + read_postamble will define some fonts and insert them into + fontmaps_hash, but we need a clean fontmaps_hash for detecting + duplicate entries in the map file. + */ + + if (resource.t1lib) { + init_t1(); + } +#endif /* T1LIB */ + + + setup_signal_handlers(); + + /* Notify users that fonts are being created. This is just a hack + and no replacement for true asynchronous font creation (see + EXPERIMENTAL_DELAYED_MTKEXPK in font-open.c for that approach) + since it doesn't give details (is just invoked if startup takes + somewhat longer) and freezes during font creation. + */ + register_font_popup(); + + /* open and initialize the DVI file, but don't read the fonts yet */ + if (!internal_open_dvi(globals.dvi_name, &errflag, +#ifdef EXPERIMENTAL_DELAYED_MTKEXPK + False +#else + True +#endif + )) { + if (tried_dvi_ext) + XDVI_FATAL((stderr, "Could not open %s: %s, and %s.dvi doesn't exist either - exiting.", + globals.dvi_name, get_dvi_error(errflag), globals.dvi_name)); + else + XDVI_FATAL((stderr, "Could not open %s: %s.", + globals.dvi_name, get_dvi_error(errflag))); + } + + unregister_font_popup(); + + if (cb->page_arg != NULL) { + if (cb->page_arg[0] == '\0') { /* empty page_arg -> goto last page */ + current_page = total_pages - 1; + page_history_insert(current_page); + } + else { + char *testptr; + current_page = strtoul(cb->page_arg, &testptr, 10) - 1; + if (*testptr != '\0') { + XDVI_FATAL((stderr, "Invalid page number: `%s'.", cb->page_arg)); + } + current_page = check_goto_page(current_page); + } + } + + file_history_set_page(current_page); + + ASSERT(globals.dvi_file.bak_fp != NULL, "Backup file pointer must have been initialized here"); + if (resource.prescan) { + prescan(globals.dvi_file.bak_fp); + } + + globals.page.unshrunk_w = pageinfo_get_page_width(current_page); + globals.page.unshrunk_h = pageinfo_get_page_height(current_page); + TRACE_FILES((stderr, "globals.page.unshrunk_w: %d, h: %d; window: %d, %d", + globals.page.unshrunk_w, globals.page.unshrunk_h, + pageinfo_get_window_width(current_page), + pageinfo_get_window_height(current_page))); + + init_page(); + + /* + * Step 4: Create widgets, and set initial window size. + */ + + /* currently these override expert mode - using this is deprecated + in favour of `-expertmode'; inform user about this: */ + if (resource.statusline) { + XDVI_WARNING((stderr, "The option/X resource `statusline' is obsolete; " + "use `-expertmode <flag>' instead, e.g. `-expertmode 1'\n" + "to switch on the status line, or `-expertmode 6'\n" + "to switch it off. See the xdvi man page for details.")); + resource.expert_mode |= XPRT_SHOW_STATUSLINE; + } + +/* XtRealizeWidget(globals.widgets.top_level); */ + +#ifdef MOTIF + tool_bar = create_toolbar(globals.widgets.main_row, globals.widgets.menu_bar); +#endif + + create_widgets( +#ifdef MOTIF + tool_bar, form, +#endif + &add_w, &add_h); + + /* fprintf(stderr, "geometry xdvirc: |%s|, orig: |%s|\n", resource.xdvirc_geometry, resource.geometry); */ + + + /* + * Set initial window size. + * This needs to be done before colors are assigned because if + * -s 0 is specified, we need to compute the shrink factor + * (which in turn affects whether init_pix is called). + */ + set_windowsize(&main_win_w, &main_win_h, add_w, add_h, False); + + realize_widgets(main_win_w, main_win_h, add_w); + + /* this needs to be done after total_pages is known (via internal_open_dvi) */ + get_icon_and_title(globals.dvi_name, &icon_name, &title_name); + add_icon(globals.widgets.top_level, title_name, icon_name); + /* this needs to be done after the widgets have been created */ + set_icon_and_title(icon_name, title_name); + free(icon_name); + free(title_name); + icon_name = title_name = NULL; + + + G_image = XCreateImage(DISP, G_visual, 1, XYBitmap, 0, + (char *)NULL, 0, 0, BMBITS, 0); + G_image->bitmap_unit = BMBITS; +#ifdef WORDS_BIGENDIAN + G_image->bitmap_bit_order = MSBFirst; +#else + G_image->bitmap_bit_order = LSBFirst; +#endif + { + short endian = MSBFirst << 8 | LSBFirst; + G_image->byte_order = *((char *)&endian); + } + + /* Store window id for use by src_client_check(). */ + { +#ifndef WORD64 + xuint32 data = XtWindow(globals.widgets.top_level); + XChangeProperty(DISP, DefaultRootWindow(DISP), + atom_xdvi_windows(), atom_xdvi_windows(), 32, + PropModePrepend, (unsigned char *)&data, 1); +#else + unsigned char data[4]; + set_window_id(XtWindow(globals.widgets.top_level), data); + XChangeProperty(DISP, DefaultRootWindow(DISP), + atom_xdvi_windows(), atom_xdvi_windows(), 32, + PropModePrepend, data, 1); +#endif + set_dvi_property(); + } + + /* + * Step 5: Assign colors and GCs. + * Because of the latter, this has to go after the widgets are realized. + */ + + create_gcs(); + + create_cursors(); + +#ifdef EXPERIMENTAL_DELAYED_MTKEXPK + /* Only now, we initialize the fonts. First update the window: */ + force_statusline_update(); + printlog_create("test", "Close", NULL, NULL, NULL, NULL); + printlog_popup(); + + printlog_append_str("\nTrying to create font(s)\n"); + if (!find_postamble(globals.dvi_file.bak_fp, &errflag) || !read_postamble(globals.dvi_file.bak_fp, &errflag, True)) { + XDVI_ERROR((stderr, "Couldn't read fonts from postamble: %s\n", get_dvi_error(errflag))); + } +#endif /* EXPERIMENTAL_DELAYED_MTKEXPK */ + +#ifdef MOTIF +#if defined(USE_PANNER) && USE_XAW_PANNER + XtVaSetValues(panner, XtNsliderWidth, globals.page.w / 2, + XtNsliderHeight, globals.page.h / 2, + XtNcanvasWidth, globals.page.w, + XtNcanvasHeight, globals.page.h, + NULL); + XtManageChild(panner); + XtAddCallback(panner, XtNreportCallback, panner_cb, (XtPointer)NULL); +#endif + create_pagelist(); +#endif + + /* trigger forward search */ + do_forward_search(resource.src_pos); + + /* trigger string search */ + if (resource.find_string != NULL) { + globals.ev.flags |= EV_FIND; + } + + /* trigger anchor search */ + if (resource.anchor_pos != NULL) { + g_anchor_pos = xstrdup(resource.anchor_pos); + g_anchor_len = strlen(g_anchor_pos); + globals.ev.flags |= EV_ANCHOR; + } + +#if defined(MOTIF) && HAVE_XPM + tb_check_navigation_sensitivity(current_page); +#endif + +#if CHECK_APP_FILEVERSION + check_app_defaults_fileversion(); +#endif + + /* can do this only after scrollbars have been realized */ + if (!BROKEN_RECONFIG && (resource.expert_mode & XPRT_SHOW_SCROLLBARS) == 0) { + toggle_scrollbars(); + } + + /* initialize file watching */ + if (resource.watch_file > 0.0) { +#if XDVI_XT_TIMER_HACK + watch_file_cb(NULL, NULL); +#else + XDVI_WARNING((stderr, "Could not redefine XtAppAddTimeOut(); `watchfile' not available.")); +#endif + } + + /* raise `early' message windows */ + raise_message_windows(); + + if (resource.mouse_mode == MOUSE_RULER_MODE) { + show_ruler(NULL); + } + + /* insert this page into the history */ + globals.ev.flags |= EV_PAGEHIST_INSERT; + + do_pages(); +} + +static char * +is_good_dvi_file(const char *filename, Boolean from_history) +{ + static char canonical_path[MAXPATHLEN + 1]; + Boolean tried_dvi_extension = False; + /* following allocates real_filename */ + char *real_filename = find_dvi_file(filename, &tried_dvi_extension, from_history); + char *ret; + FILE *f = NULL; + dviErrFlagT errflag; + + if (real_filename == NULL) + return NULL; + + if ((ret = REALPATH(real_filename, canonical_path)) == NULL) { + /* REALPATH failed, use real_filename */ + strncpy(canonical_path, real_filename, MAXPATHLEN); + canonical_path[MAXPATHLEN] = '\0'; + ret = canonical_path; + } + free(real_filename); + + /* check for correct DVI files */ + if ((f = XFOPEN(ret, OPEN_MODE)) != NULL) { + TRACE_EVENTS((stderr, "watching: new file opened successfully.")); + if (process_preamble(f, &errflag) + && find_postamble(f, &errflag) + && read_postamble(f, &errflag, False)) { + fclose(f); + return ret; + } + fclose(f); + if (!from_history) + XDVI_FATAL((stderr, "%s: %s.", filename, get_dvi_error(errflag))); + return NULL; + } + else { + if (!from_history) + XDVI_FATAL((stderr, "Could not open `%s': %s.", filename, strerror(errno))); + return NULL; + } +} + +static char * +get_filename_from_history(int *pageno) +{ + size_t i; + /* loop through history, trying to get a good file */ + for (i = 0; i < file_history_size(); i++) { + char *ret, *test; + + if ((test = file_history_get_elem(i, pageno)) == NULL) + return NULL; + TRACE_FILES((stderr, "HISTORY %lu: |%s|", (unsigned long)i, test)); + if ((ret = is_good_dvi_file(test, True)) != NULL) { + TRACE_FILES((stderr, "SUCCESS: |%s|", test)); + return ret; + } + } + return NULL; +} + + +/* + ************************************************************ + ************************************************************ + main routine + ************************************************************ + ************************************************************ +*/ + +int +main(int argc, char **argv) +{ + int i; + static struct filehist_info info; + const char *file_name = NULL; + const char *file_name2 = NULL; + + /* Hack to have command-line options override ~/.xdvirc stuff: + * Parse and merge them again from argv_bak, a copy of the command-line options, + * via XrmParseCommand(). I think the only alternative would be to merge in all + * resources manually instead of using XtInitialize(), similar to what's done in gv, + * but that looks like too much trouble. + */ +#define COMMANDLINE_OVERRIDE_HACK 1 + +#if COMMANDLINE_OVERRIDE_HACK + int argc_bak; + char **argv_bak; +#endif + + info.file_idx = 0; + info.page_arg = NULL; + + /* BEGIN_TIMER_LOOP; */ + + init_globals(); + + /* + * Step 1: Process command-line options and resources. + */ + + globals.program_name = xstrdup(argv[0]); + { /* get filename from program_name if it contains a path */ + char sep; + char *ptr; +#ifdef VMS + sep = ']'; +#else + sep = '/'; +#endif + if ((ptr = strrchr(globals.program_name, sep)) != NULL) { + globals.program_name = ++ptr; + } +#ifdef VMS + if ((ptr = strchr(globals.program_name, '.')) != NULL) + *ptr = '\0'; +#endif + } + +#if COMMANDLINE_OVERRIDE_HACK + /* create a copy of argv[] */ + argc_bak = argc; + argv_bak = xmalloc((1 + argc_bak) * sizeof *argv_bak); + for (i = 0; i < argc_bak; i++) { + argv_bak[i] = xstrdup(argv[i]); + } + argv_bak[i] = NULL; +#endif + + /* + Arguments that need to be checked early, like `help', `version' and `sync'. + The former don't even require an X connection. + */ + check_early_arguments(argc, argv); + + warn_about_prerelease_versions(); + + /* We need to set up SIGALRM before calling XtAppAddTimeOut() (inside sfSelFile, or + called from XtInitialize() in Motif), else and we'll die with the error message + `Alarm clock'. However, we mustn't install SIGPOLL before the forking is done + below, else xdvi may hang forever waiting for input. So the signal handler setup + is split in 2 parts: setup_sigalarm(), and setup_signal_handlers() below. + */ + setup_sigalarm(); + + /* get the debug value (if any) from the environment + (it's too early to get it from the command line) */ + globals.debug = parse_debugging_option(getenv("XDVIDEBUG")); + + /* to make input of non-latin characters work */ + XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL); + globals.widgets.top_level = XtInitialize(globals.program_name, "XDvi", options, XtNumber(options), + &argc, argv); + + app = XtWidgetToApplicationContext(globals.widgets.top_level); + + XtAppAddActions(app, get_actions(), get_num_actions()); + + create_magnifier(); + + if ((globals.orig_locale = setlocale(LC_ALL, "")) != NULL) + globals.orig_locale = xstrdup(globals.orig_locale); /* note: never free'd */ + else /* fallback */ + globals.orig_locale = xstrdup(setlocale(LC_ALL, NULL)); + + /* Override LC_NUMERIC, else sscanf(), strtod() etc. will stop working on floats + inside specials for locales like LANG=de_DE which uses `,' not `.' + as fractional part separator. (Strangely, using + LC_CTYPE | LC_COLLATE + above doesn't work?) + Regression: + xdvik/regression/special-pics/pictest.dvi + */ + setlocale(LC_NUMERIC, "C"); + + /* at this point, all known options will have been consumed; so the + only ones remaining should be: +pageno, and the dvi name. Exit with + usage message if this is not the case. The following rather complicated + looping logic ensures that the first unknown option is regarded as dvi_name, + unless it's followed by another option, in which case it will result in an + `Unrecognized option' error. + */ + for (i = 0; i < argc - 1; i++) { /* argc - 1 because we're going to look at + argv[i + 1] to skip argv[0] */ + if (*(argv[i + 1]) == '+') { + if (info.page_arg != NULL) { + XDVI_ERROR((stderr, "Unrecognized option `%s'.", argv[i + 1])); + usage(EXIT_FAILURE); + } + else { + info.page_arg = argv[i + 1] + 1; + } + } + else if (file_name == NULL) { + file_name = xstrdup(argv[i + 1]); /* LEAK */ + } + else { + XDVI_ERROR((stderr, "Unrecognized option `%s'.", argv[i])); + usage(EXIT_FAILURE); + } + } + + DISP = XtDisplay(globals.widgets.top_level); + SCRN = XtScreen(globals.widgets.top_level); + +#ifdef GREY + XtSetTypeConverter(XtRString, XtRBool3, XdviCvtStringToBool3, + NULL, 0, XtCacheNone, NULL); +#endif + +#ifdef MOTIF + /* we'll take care of that ourselves */ + XtVaSetValues(globals.widgets.top_level, XmNdeleteResponse, XmDO_NOTHING, NULL); + + { + /* Hack to work around #884290 (drag&drop freezes file selector, see comment + in xm_filesel.c): Disable drag&drop altogether (we don't need it). + Could also be done via Xdefaults as follows: + XDvi*dragInitiatorProtocolStyle: XmDRAG_NONE + XDvi*dragReceiverProtocolStyle: XmDRAG_NONE + */ + Widget display = XmGetXmDisplay(DISP); + XtVaSetValues(display, + XmNdragInitiatorProtocolStyle, XmDRAG_NONE, + XmNdragReceiverProtocolStyle, XmDRAG_NONE, + NULL); + } +#else + G_accels_cr = XtParseAcceleratorTable("<Key>Return:set()notify()unset()\n" + "<Key>q:set()notify()unset()\n" + "<Key>Escape: set()notify()unset()"); +#endif + + /* get the no_init_file resource first: This needs to be done + * before the call to XtGetApplicationResources() below, which populates + * the `resource' struct with the actual application resources (which + * may be merged from ~/.xdvirc). */ + XtGetApplicationResources(globals.widgets.top_level, (XtPointer)&resource, + xdvirc_resources, XtNumber(xdvirc_resources), + (ArgList)NULL, 0); + + if (!resource.no_init_file) { /* Read user preferences from ~/.xdvirc. */ + read_user_preferences(globals.widgets.top_level, ".xdvirc"); + } + +#if COMMANDLINE_OVERRIDE_HACK /* see above */ + { + XrmDatabase cmdline_db = XrmGetDatabase(DISP); + XrmParseCommand(&cmdline_db, options, XtNumber(options), + "xdvi", &argc_bak, argv_bak); + + for (i = 0; i < argc_bak; i++) { + free(argv_bak[i]); + } + free(argv_bak); + argc_bak = 0; + } +#endif /* COMMANDLINE_OVERRIDE_HACK */ + + XtGetApplicationResources(globals.widgets.top_level, (XtPointer)&resource, + application_resources, XtNumber(application_resources), + (ArgList)NULL, 0); + + if (resource.shrinkfactor == 0) /* protect against division by 0 */ + resource.shrinkfactor = 1; + currwin.shrinkfactor = resource.shrinkfactor; + globals.curr_use_color = resource.use_color; + globals.curr_gamma = resource.gamma; + globals.curr_paper = xstrdup(resource.paper); /* never free()d */ + globals.curr_editor = NULL; + globals.curr_browser = NULL; + + /* Initialize `globals.debug' as early as possible. Note: earlier + * calls to TRACE_* or tests for `if (globals.debug)' will only work if the + * XDVIDEBUG environment variable is set! + */ + globals.debug |= parse_debugging_option(resource.debug_arg); + kpathsea_debug = globals.debug / DBG_STAT; + + if (globals.debug) + fprintf(stderr, "KPATHSEA_DEBUG = %d\n", kpathsea_debug); + + kpse_init_prog("XDVI", resource.pixels_per_inch, resource.mfmode, resource.alt_font); + + kpse_set_program_name(argv[0], "xdvi"); + + + if (globals.debug & DBG_EXPAND) { + const char *texmfcnf = kpse_path_expand("$TEXMFCNF"); + const char *texmfmain = kpse_path_expand("$TEXMFMAIN"); + fprintf(stderr, "\n%s:%d: KPATHSEA variables:\n", __FILE__, __LINE__); + fprintf(stderr, "%s:%d: SELFAUTOLOC=\"%s\"\n", __FILE__, __LINE__, getenv("SELFAUTOLOC")); + fprintf(stderr, "%s:%d: SELFAUTODIR=\"%s\"\n", __FILE__, __LINE__, getenv("SELFAUTODIR")); + fprintf(stderr, "%s:%d: SELFAUTOPARENT=\"%s\"\n", __FILE__, __LINE__, getenv("SELFAUTOPARENT")); + fprintf(stderr, "%s:%d: TEXMFCNF=\"%s\"\n", __FILE__, __LINE__, texmfcnf); + fprintf(stderr, "%s:%d: TEXMFMAIN=\"%s\"\n\n", __FILE__, __LINE__, texmfmain); + } + + if (resource.regression) { + /* currently it just turns on everything; what we'd like here is + output that's usable for automatic diffs (e.g. independent + of window manager state) */ + globals.debug = DBG_ALL; + } + + /* Check early for whether to pass off to a different xdvi process + * (-sourceposition argument for reverse source special lookup). + */ + property_initialize(); + +#if 0 /* def RGB_ANTI_ALIASING */ + /* error checking and setting of resources according to command line arguments */ + if (resource.sub_pixels != NULL && memicmp(resource.sub_pixels, "unknown", 4) == 0) { +#ifdef __GNUC__ +#warning TODO: implement callbacks +#endif + choice_dialog_sized(globals.widgets.top_level, + MSG_QUESTION, + SIZE_MEDIUM, + NULL, +#ifndef MOTIF + NULL, /* TODO: xaw ret_action_str */ +#endif + NULL, NULL, /* pre callback */ + "Enable", NULL, NULL, + "Disable", NULL, NULL, + "This version of xdvi can optimize the anti-aliased font display " + "when running on an LCD monitor, such as a notebook screen or a TFT flat screen." + "\n\n" + "If you are using such a monitor, click `Enable' to enable optimized display; otherwise click `Disable'." + "\n\n" + "You can change this setting later via the Menu `Options -> Anti-Aliasing'."); + /* enter event loop */ + do_pages(); + } + else { +#endif + init_check_resources(); + + TRACE_FILES((stderr, "file history: |%s|", resource.file_history)); + file_history_init(); + + if (file_name == NULL) { /* no filename argument */ + + if (resource.no_file_arg_use_history) { + static char buf[LENGTH_OF_INT]; /* so that we can pass its address */ + int pageno; + if ((file_name = get_filename_from_history(&pageno)) != NULL) { + SNPRINTF(buf, LENGTH_OF_INT, "%d", pageno + 1); /* pageno is 0-based */ + info.page_arg = buf; + } + } + + TRACE_FILES((stderr, "got from history: |%s|", file_name)); + + if (file_name != NULL) { + run_dvi_file(file_name, &info); + } + else { /* get filename from file selector */ + static struct filesel_callback cb; /* static so that we can pass its address */ + cb.title = "Xdvi: Open file"; + cb.prompt = "Open file:"; + cb.ok = "OK"; + cb.cancel = "Cancel"; + cb.init_path = NULL; + cb.filemask = "*.dvi"; + cb.must_exist = True; + cb.exit_on_cancel = True; + cb.func_ptr = run_dvi_file; + cb.data = &info; + + XsraSelFile(globals.widgets.top_level, &cb); + /* enter event loop */ + do_pages(); + } + } + else if ((file_name2 = is_good_dvi_file(file_name, False)) != NULL) { + run_dvi_file(file_name2, &info); + } +#if 0 /* def RGB_ANTI_ALIASING */ + } +#endif + /* notreached */ + return 0; +} + + |