summaryrefslogtreecommitdiff
path: root/Build/source/texk/xdvik
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-17 21:41:51 +0000
committerKarl Berry <karl@freefriends.org>2006-01-17 21:41:51 +0000
commit487ca4806cc046076293cf6cc5fbba0db282bac7 (patch)
tree847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/xdvik
parenta3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff)
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvik')
-rw-r--r--Build/source/texk/xdvik/BUGS62
-rw-r--r--Build/source/texk/xdvik/CHANGES833
-rw-r--r--Build/source/texk/xdvik/FAQ248
-rw-r--r--Build/source/texk/xdvik/INSTALL132
-rw-r--r--Build/source/texk/xdvik/LESSTIF-BUGS35
-rw-r--r--Build/source/texk/xdvik/Makefile.in227
-rw-r--r--Build/source/texk/xdvik/README.t1fonts207
-rw-r--r--Build/source/texk/xdvik/README.t1mapper187
-rw-r--r--Build/source/texk/xdvik/acconfig.h386
-rw-r--r--Build/source/texk/xdvik/aclocal.m41036
-rw-r--r--Build/source/texk/xdvik/alloc-debug.h34
-rw-r--r--Build/source/texk/xdvik/browser.c273
-rw-r--r--Build/source/texk/xdvik/browser.h29
-rw-r--r--Build/source/texk/xdvik/c-auto.in460
-rw-r--r--Build/source/texk/xdvik/c-openmx.h37
-rwxr-xr-xBuild/source/texk/xdvik/configure6703
-rw-r--r--Build/source/texk/xdvik/configure.in289
-rw-r--r--Build/source/texk/xdvik/depend.mak0
-rw-r--r--Build/source/texk/xdvik/depend.mk536
-rw-r--r--Build/source/texk/xdvik/dvi-draw.c6794
-rw-r--r--Build/source/texk/xdvik/dvi-draw.h160
-rw-r--r--Build/source/texk/xdvik/dvi-init.c1620
-rw-r--r--Build/source/texk/xdvik/dvi-init.h193
-rw-r--r--Build/source/texk/xdvik/dvi.h64
-rw-r--r--Build/source/texk/xdvik/dvisel.c759
-rw-r--r--Build/source/texk/xdvik/dvisel.h42
-rw-r--r--Build/source/texk/xdvik/encodings.c3989
-rw-r--r--Build/source/texk/xdvik/encodings.h58
-rw-r--r--Build/source/texk/xdvik/events.c5645
-rw-r--r--Build/source/texk/xdvik/events.h236
-rw-r--r--Build/source/texk/xdvik/filehist.c395
-rw-r--r--Build/source/texk/xdvik/filehist.h40
-rw-r--r--Build/source/texk/xdvik/font-open.c496
-rw-r--r--Build/source/texk/xdvik/font-open.h32
-rw-r--r--Build/source/texk/xdvik/gf.c326
-rw-r--r--Build/source/texk/xdvik/gui/Makefile.in80
-rw-r--r--Build/source/texk/xdvik/gui/Panner.c1230
-rw-r--r--Build/source/texk/xdvik/gui/Panner.h108
-rw-r--r--Build/source/texk/xdvik/gui/PannerP.h104
-rw-r--r--Build/source/texk/xdvik/gui/Tip.c607
-rw-r--r--Build/source/texk/xdvik/gui/Tip.h62
-rw-r--r--Build/source/texk/xdvik/gui/TipP.h95
-rw-r--r--Build/source/texk/xdvik/gui/depend.mk528
-rw-r--r--Build/source/texk/xdvik/gui/help-window.c1094
-rw-r--r--Build/source/texk/xdvik/gui/help-window.h29
-rw-r--r--Build/source/texk/xdvik/gui/mag.c861
-rw-r--r--Build/source/texk/xdvik/gui/mag.h45
-rw-r--r--Build/source/texk/xdvik/gui/menu.c395
-rw-r--r--Build/source/texk/xdvik/gui/menu.h73
-rw-r--r--Build/source/texk/xdvik/gui/message-window.c1207
-rw-r--r--Build/source/texk/xdvik/gui/message-window.h134
-rw-r--r--Build/source/texk/xdvik/gui/pagesel.c1591
-rw-r--r--Build/source/texk/xdvik/gui/pagesel.h71
-rw-r--r--Build/source/texk/xdvik/gui/print-dialog.c2973
-rw-r--r--Build/source/texk/xdvik/gui/print-dialog.h44
-rw-r--r--Build/source/texk/xdvik/gui/print-log.c552
-rw-r--r--Build/source/texk/xdvik/gui/print-log.h46
-rw-r--r--Build/source/texk/xdvik/gui/search-dialog.c1072
-rw-r--r--Build/source/texk/xdvik/gui/search-dialog.h68
-rw-r--r--Build/source/texk/xdvik/gui/selection.c242
-rw-r--r--Build/source/texk/xdvik/gui/selection.h32
-rw-r--r--Build/source/texk/xdvik/gui/sfDir.c165
-rw-r--r--Build/source/texk/xdvik/gui/sfDir.h63
-rw-r--r--Build/source/texk/xdvik/gui/sfDraw.c819
-rw-r--r--Build/source/texk/xdvik/gui/sfDraw.h99
-rw-r--r--Build/source/texk/xdvik/gui/sfPath.c908
-rw-r--r--Build/source/texk/xdvik/gui/sfPath.h45
-rw-r--r--Build/source/texk/xdvik/gui/sfSelFile.c1071
-rw-r--r--Build/source/texk/xdvik/gui/sfSelFile.h46
-rw-r--r--Build/source/texk/xdvik/gui/sfinternal.h59
-rw-r--r--Build/source/texk/xdvik/gui/statusline.c531
-rw-r--r--Build/source/texk/xdvik/gui/statusline.h52
-rw-r--r--Build/source/texk/xdvik/gui/topic-window.c650
-rw-r--r--Build/source/texk/xdvik/gui/topic-window.h80
-rw-r--r--Build/source/texk/xdvik/gui/xaw_bitmaps.c82
-rw-r--r--Build/source/texk/xdvik/gui/xaw_bitmaps.h21
-rw-r--r--Build/source/texk/xdvik/gui/xaw_menu.c1449
-rw-r--r--Build/source/texk/xdvik/gui/xaw_menu.h62
-rw-r--r--Build/source/texk/xdvik/gui/xicon.c168
-rw-r--r--Build/source/texk/xdvik/gui/xicon.h29
-rw-r--r--Build/source/texk/xdvik/gui/xlwradio.c677
-rw-r--r--Build/source/texk/xdvik/gui/xlwradio.h119
-rw-r--r--Build/source/texk/xdvik/gui/xlwradioP.h140
-rw-r--r--Build/source/texk/xdvik/gui/xm_colorsel.c664
-rw-r--r--Build/source/texk/xdvik/gui/xm_colorsel.h43
-rw-r--r--Build/source/texk/xdvik/gui/xm_filesel.c195
-rw-r--r--Build/source/texk/xdvik/gui/xm_menu.c364
-rw-r--r--Build/source/texk/xdvik/gui/xm_menu.h45
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs.c590
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs.h39
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefsP.h125
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_appearance.c540
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_appearance.h37
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_fonts.c696
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_fonts.h37
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_helpers.c946
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_helpers.h35
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_page.c695
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_page.h38
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_scroll.c470
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_scroll.h34
-rw-r--r--Build/source/texk/xdvik/gui/xm_toolbar.c860
-rw-r--r--Build/source/texk/xdvik/gui/xm_toolbar.h50
-rw-r--r--Build/source/texk/xdvik/hypertex.c2165
-rw-r--r--Build/source/texk/xdvik/hypertex.h71
-rw-r--r--Build/source/texk/xdvik/image-magick.c1422
-rw-r--r--Build/source/texk/xdvik/image-magick.h34
-rw-r--r--Build/source/texk/xdvik/mime.c653
-rw-r--r--Build/source/texk/xdvik/mime.h29
-rwxr-xr-xBuild/source/texk/xdvik/mksedscript114
-rw-r--r--Build/source/texk/xdvik/my-snprintf.c59
-rw-r--r--Build/source/texk/xdvik/my-snprintf.h36
-rw-r--r--Build/source/texk/xdvik/my-vsnprintf.c92
-rw-r--r--Build/source/texk/xdvik/my-vsnprintf.h45
-rw-r--r--Build/source/texk/xdvik/pagehist.c547
-rw-r--r--Build/source/texk/xdvik/pagehist.h33
-rw-r--r--Build/source/texk/xdvik/pixmaps/drag_horiz.xbm8
-rw-r--r--Build/source/texk/xdvik/pixmaps/drag_horiz_mask.xbm8
-rw-r--r--Build/source/texk/xdvik/pixmaps/drag_omni.xbm10
-rw-r--r--Build/source/texk/xdvik/pixmaps/drag_omni_mask.xbm10
-rw-r--r--Build/source/texk/xdvik/pixmaps/drag_vert.xbm7
-rw-r--r--Build/source/texk/xdvik/pixmaps/drag_vert_mask.xbm7
-rw-r--r--Build/source/texk/xdvik/pixmaps/fist.xbm6
-rw-r--r--Build/source/texk/xdvik/pixmaps/fist_mask.xbm6
-rw-r--r--Build/source/texk/xdvik/pixmaps/hand.xbm6
-rw-r--r--Build/source/texk/xdvik/pixmaps/hand_mask.xbm6
-rw-r--r--Build/source/texk/xdvik/pixmaps/magglass.xbm10
-rw-r--r--Build/source/texk/xdvik/pixmaps/magglass_mask.xbm10
-rw-r--r--Build/source/texk/xdvik/pixmaps/time16.xbm8
-rw-r--r--Build/source/texk/xdvik/pixmaps/time16_mask.xbm6
-rw-r--r--Build/source/texk/xdvik/pixmaps/toolbar.xpm41
-rw-r--r--Build/source/texk/xdvik/pixmaps/toolbar2.xpm40
-rw-r--r--Build/source/texk/xdvik/pixmaps/xdvi16x16.xpm100
-rw-r--r--Build/source/texk/xdvik/pixmaps/xdvi32x32.xpm55
-rw-r--r--Build/source/texk/xdvik/pixmaps/xdvi48x48.xpm86
-rw-r--r--Build/source/texk/xdvik/pk.c387
-rw-r--r--Build/source/texk/xdvik/print-internal.c814
-rw-r--r--Build/source/texk/xdvik/print-internal.h78
-rw-r--r--Build/source/texk/xdvik/psdps.c858
-rw-r--r--Build/source/texk/xdvik/psdps.h28
-rw-r--r--Build/source/texk/xdvik/psgs.c1090
-rw-r--r--Build/source/texk/xdvik/psgs.h31
-rw-r--r--Build/source/texk/xdvik/psheader.txt313
-rw-r--r--Build/source/texk/xdvik/psnews.c951
-rw-r--r--Build/source/texk/xdvik/psnews.h28
-rw-r--r--Build/source/texk/xdvik/read-mapfile.c156
-rw-r--r--Build/source/texk/xdvik/read-mapfile.h28
-rw-r--r--Build/source/texk/xdvik/search-internal.c1734
-rw-r--r--Build/source/texk/xdvik/search-internal.h91
-rw-r--r--Build/source/texk/xdvik/special.c2776
-rw-r--r--Build/source/texk/xdvik/special.h79
-rw-r--r--Build/source/texk/xdvik/squeeze.c196
-rw-r--r--Build/source/texk/xdvik/stamp-auto.in1
-rw-r--r--Build/source/texk/xdvik/string-utils.c743
-rw-r--r--Build/source/texk/xdvik/string-utils.h81
-rwxr-xr-xBuild/source/texk/xdvik/t1mapper433
-rw-r--r--Build/source/texk/xdvik/t1mapper.1146
-rw-r--r--Build/source/texk/xdvik/texmf-alt/README31
-rw-r--r--Build/source/texk/xdvik/texmf-alt/charter2.map5
-rw-r--r--Build/source/texk/xdvik/texmf-alt/lucida.map110
-rw-r--r--Build/source/texk/xdvik/texmf-alt/marvosym.map2
-rw-r--r--Build/source/texk/xdvik/texmf-alt/xdvi.cfg90
-rw-r--r--Build/source/texk/xdvik/texmf-alt/xdvifont.map56
-rw-r--r--Build/source/texk/xdvik/texmf-alt/xypic.map18
-rw-r--r--Build/source/texk/xdvik/texmf/XDvi370
-rw-r--r--Build/source/texk/xdvik/texmf/xdvi.cfg61
-rw-r--r--Build/source/texk/xdvik/tfmload.c120
-rw-r--r--Build/source/texk/xdvik/tfmload.h31
-rw-r--r--Build/source/texk/xdvik/translations.h398
-rw-r--r--Build/source/texk/xdvik/util.c1839
-rw-r--r--Build/source/texk/xdvik/util.h241
-rw-r--r--Build/source/texk/xdvik/version.h19
-rw-r--r--Build/source/texk/xdvik/vf.c184
-rw-r--r--Build/source/texk/xdvik/withenable.ac149
-rw-r--r--Build/source/texk/xdvik/x_util.c1221
-rw-r--r--Build/source/texk/xdvik/x_util.h141
-rw-r--r--Build/source/texk/xdvik/xdvi-config.h37
-rw-r--r--Build/source/texk/xdvik/xdvi-debug.h218
-rw-r--r--Build/source/texk/xdvik/xdvi-search.el345
-rwxr-xr-xBuild/source/texk/xdvik/xdvi-sh.in46
-rw-r--r--Build/source/texk/xdvik/xdvi.1.in4284
-rw-r--r--Build/source/texk/xdvik/xdvi.c4342
-rw-r--r--Build/source/texk/xdvik/xdvi.h1128
-rw-r--r--Build/source/texk/xdvik/xdvi.icon27
-rwxr-xr-xBuild/source/texk/xdvik/xdvizilla134
-rw-r--r--Build/source/texk/xdvik/xdvizilla.1115
-rw-r--r--Build/source/texk/xdvik/xserver-info.c283
-rw-r--r--Build/source/texk/xdvik/xserver-info.h10
188 files changed, 92571 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/BUGS b/Build/source/texk/xdvik/BUGS
new file mode 100644
index 00000000000..01ff6f628da
--- /dev/null
+++ b/Build/source/texk/xdvik/BUGS
@@ -0,0 +1,62 @@
+
+For an up-to-date list of bugs, please visit:
+
+http://sourceforge.net/tracker/?group_id=23164&atid=377580
+
+This file records only bugs that have been tagged as `Wont fix' or
+`Later', i.e. bugs that couldn't be resolved so far.
+
+Please report new bugs to the above SourceForge URL, including as much
+information as possible (whatever may be relevant: platform, compiler,
+X version, output of xdpyinfo, sample .dvi file to reproduce the
+problem; see also: http://xdvi.sourceforge.net/#bugs).
+
+
+(A) X interface bugs:
+
+(A1) The current code to toggle to/from fullscreen mode via Ctrl-l, and to
+ remove the Xaw scrollbars for expert mode is an atrocious hack that won't
+ work with many window managers (see e.g. #814327). These should be fixed by
+ someone who knows X better than I do.
+
+(A2) The correct handling of XtAppAddTimeOut() and friends, used e.g. internally
+ by many Motif widgets, depends on xdvi redefining the XtAppAddTimeOut() and
+ related functions to use its own non-standard event handling routines.
+
+ If this is not possible (e.g. because your linker doesn't allow multiple
+ definitions - check for the corresponding warnings by ./configure),
+ some of the widgets (e.g. the print log window, tooltips, statusline
+ messages, hyperlink location markers) will not appear correctly or will
+ only be updated when the mouse is moved.
+
+(A3) Motif: Toggle buttons in print dialog (page range) may fail under
+ certain circumstances when button has been changed via marking pages.
+ (For details, see comment in gui/print-dialog.c, notify_dialog()).
+
+(A4) Motif 1.2: After opening a document at page 1 and changing to page
+ 2, an partial area of the highlighting of page 1 is not erased (#997080).
+
+(A5) Ctrl-l and the `fullscreen' option are hacks that may interact badly
+ with certain window managers (e.g. KDE; see #815020). In such cases it's
+ better to use the window manager's functions to enable fullscreen mode.
+
+(A6) Xaw: The page list scroll area (viewport) is not resized when switching to
+ a file with longer page numbers (e.g. from 2-digit ones to 5-digit ones).
+
+
+(B) Known features:
+
+(B1) Controll of font/file generation by X-resource and commandline is overridden
+ by controll by environment variable/texmf.cnf setting. This is a design
+ decision in kpathsea; if you want it to be resource/commandline controlled,
+ make sure there is no setting in the environment or texmf.cnf.
+
+(B2) Some of the optional compilation stuff (e.g. display postscript) hasn't been
+ tested for quite some time and may be broken.
+
+
+(C) Autoconfigure issues:
+
+(C1) GS_PATH cannot be set except by CFLAGS=-DGS_PATH=... Paul has a macro for
+ this. Must be compatible with kpathsea, but I haven't checked this yet.
+
diff --git a/Build/source/texk/xdvik/CHANGES b/Build/source/texk/xdvik/CHANGES
new file mode 100644
index 00000000000..17c4edc5d3c
--- /dev/null
+++ b/Build/source/texk/xdvik/CHANGES
@@ -0,0 +1,833 @@
+The xdvik development team tries to keep step with the changes in
+Paul Vojta's xdvi, but since we might not always manage to update
+xdvik in time, there may be `leaps' in the version numbers.
+Sometimes there are also intermediate or `patchlevel' releases of
+xdvik between two releases of xdvi; these are tagged with additional
+digits (e.g. `22.74.1'; up to 22.40, letters were used instead).
+
+Versions containing major changes are marked as `beta'; these
+may contain undetected bugs. Such versions shouldn't be used
+by distributors.
+
+ * 22.84.10 (2005/04/28):
+ + Fixed zero termination bug in t1lib version number check (t1lib.ac).
+ + Render an empty character instead of terminating with failed assertion
+ if T1lib doesn't return a usable glyph (e.g. at very small
+ \magnification factors; #1184087).
+ + Made gs_timeout in psgs.c a resource instead of #define it.
+ + Make file opening work with file descriptors too, as used in
+ Debian's Perl wrapper for xdvi (#1165497).
+
+ * 22.84.9 (teTeX-3.0):
+ + Applied Patch by Nobuyuki Tsuchimura (#1116871) to remove
+ code duplication in encodings.c.
+ + Changed --with-x-toolkit configure option to --with-xdvi-x-toolkit
+ for better interoperability with Metafont.
+ + Added a missing #if HAVE_X11_XMU_XMU_H in gui/selection.c.
+
+ * 22.84.8 (2004/12/02):
+ + Made text selection mode and ruler mode work correctly with
+ LessTif and Motif 1.2.4 (bugfix for #997073). Special thanks
+ to Svend Tollak Munkejord for helping me debugging this and
+ several of the other issues listed here.
+ + Fixed an `unaligned access' warning on 64-bit architectures
+ (OSF1/5.1), and some compiler warnings on Solaris/Ultrix/Tru64.
+ Many thanks to Bernhard Simon for extensive testing on Ultrix,
+ AIX and Tru64.
+ + Fixed a problem with non-default installation paths for libXpm,
+ with a lot of help from Sven de Vries.
+ + Fixed a formatting problem in the man page that showed up with
+ groff-1.17.2.
+ + Fixed a problem with window geometry when `-geometry' argument
+ specifies only x/y-offset, reported by Karl Berry here:
+ http://tug.org/mail-archives/tex-k/2004-November/001128.html
+ + Disabled virtual memory reallocation in T1lib (t1load.c,
+ ANSI_REALLOC_VM) that caused a segfault on OSF1/V5.1 alpha.
+ + Always install a custom X error handler which will print
+ warning messages instead of terminating the application.
+ + Create ~/.xdvirc with permissions 0600 instead of default ones.
+
+ * 22.84.6 (2004/11/08):
+ + Fixed a few compilation problems with HAVE_REGEX_H, strdup() vs.
+ xstrdup() and linkers not allowing multiple definitions (ULTRIX).
+
+ * 22.84.5 (2004/10/28):
+ + Fixed bug #968127 (recursive call to file loading code due to
+ read_events() in load_font(), which was supposed to update the
+ `loading file, may take a while' popup when fonts are created;
+ currently, this popup won't appear at all).
+
+ * 22.84.4 (2004/09/27):
+ + Fixed bug #1002688 (race condition when toggling expert mode
+ and marking pages).
+ + Fix bug #992179 (failed assertion when DVI had been removed),
+ reported again by Ulrich Scholz.
+ + Implemented feature request #995114 (prefix argument for Ctrl-o
+ opens recent files in history).
+ + Fixed bug #1029127 (map file parser didn't understand `<[' encoding
+ file syntax)
+ + Fixed a crasher bug on PowerPC related to multiple invocations of
+ v*printf() without matching va_start()/va_end() calls, reported to
+ the tex-live mailing list by Siep Kroonenberg
+ (http://tug.org/mailman/private/tex-live/2004-September/006780.html).
+
+ * 22.84.3 (2004/07/15):
+ + Printing to PS or PDF didn't really use the fallback temporary file
+ when current file was corrupted (#986009; thanks to Ulrich Scholz
+ for reporting this one).
+ + Fixed href length computation error when a href started with whitespace
+ (#988934, again reported by Ulrich Scholz).
+ + Removed t1x11.o from libs/t1lib/Makefile.in as in tetex 2.96.5.20040711
+ since it broke compilation with --with-x=no
+
+ * 22.84.1 (2004/06/26):
+ + Fixed a segfault if setlocale() call returns NULL for certain
+ locale/X library combinations (reported by Reiner Steib).
+ + Read the toolbar pixmap from build-in default (toolbar.xpm) if
+ no file is found in the search locations.
+ + Fixed a problem with the toolbar causing BadMatch errors with visuals
+ where the xdvi window has a different depth from the root window,
+ reported by Olaf Weber on tex-live
+ (http://tug.org/mailman/private/tex-live/2004-June/006112.html).
+ + Fixed a problem with incompatible vsnprintf() implementations that
+ don't return the length of the string actually needed, also reported
+ by Olaf Weber.
+ + Added a warning if configure detects LessTif because of the bugs
+ with LessTif.
+
+ * 22.84 (2004/06/01):
+ + Added a `Open Recent' entry to the files menu (file history is saved
+ to ~/.xdvirc). When xdvi is started without filename argument, the
+ most recent file from the history will be used (set the X resource
+ `noFileArgUseHistory' to false to get back the previous behaviour
+ of opening the file selector in that situation).
+ + Also enable the ruler lines when xdvi is started in ruler mode
+ (bug reported by Zhang Lin-Bo).
+ + Added `dvips options' field also to saving dialog (feature request
+ #942853, reported by Ulrich Scholz).
+ + Protect against integer overflow in prefix arguments (patch suggested
+ by Matt Swift in debian bug report #247848)
+ + Imported changes from non-k xdvi 22.83/22.84.
+ + Fixed another wrong string (printing vs. saving) for #939262
+ + Fixed a bug with UTF-8 conversion in text copy&paste.
+ + Fixed #940056 (Xaw version crashed when toggling expert mode and
+ at same time quickly changing pages)
+ + Added Ctrl-Home/End to forced Motif bindings for the drawing area.
+
+ * 22.82 (2004/04/21):
+ + Implemented a text selection mode, similar to xpdf: Use Mouse-1
+ to mark a rectangular region of text in a DVI file which is put
+ into the X selection.
+ + Added a Preferences dialog for the Motif version.
+ + Use $HOME/.xdvirc to save user customization from menus, dialogs
+ and Motif preferences; new `-q' option/`noUserFile' X resource
+ inhibits reading this file.
+ + Changed semantics of `browser' command-line option/`wwwBrowser'
+ X resource: Make it override the $BROWSER or the (obsolete)
+ $WWWBROWSER environment variable; use Netscape by default if no
+ browser is specified.
+ + Fixed #939262 (Bugs when saving/printing: Title of log window was
+ `Printing' also when saving, and outfile names weren't updated
+ correctly after loading a new file).
+ + Force vertical scrollbar for Motif Printing/Saving log window.
+ + Bugfixes for a potential crash if shrink factor is changed on a page
+ with color specials, as in non-k xdvi-22.82.
+ + Fixed a bug with the ESC key to close popup windows in Motif that
+ could cause crashes when opening new popups, and implemented ESC
+ to close Xaw popup windows (feature request #919501).
+ + Updates for kpathsea/withenable.ac by Olaf Weber.
+ + Made Ctrl-+ and Alt-Ctrl-+ case insensitive (suggested by Harald
+ Koenig).
+ + Fixed Motif 1.2 compile (XmEACH_SIDE), and added/fixed configure
+ checks for -lXmu, -lXp and -lXpm linker options.
+ + Removed Xaw file selector auto raising since it could send the
+ X server into a busy loop when the file selector was over a window
+ that should always stay on top.
+ + Removed t1mapper man page install (script wasn't installed either).
+ + Fixed #926055:
+ - Default printing target not set correctly when printing window
+ was initialized.
+ - `-t' paper options were just appended instead of replacing the
+ existing ones.
+ - Current directory of dvips was that of xdvi invocation instead
+ of DVI file path, causing e.g. problems with included EPS files.
+
+ * 22.81.1 (2004/03/17):
+ + Upgrade to kpathsea 3.5.2, and use lookup in new locations
+ kpse_enc_format and kpse_type1_format for .enc files and .pfa/.pfb
+ files, respectivly. (Lookup in old locations is preserved for
+ backwards compatibility).
+ + Upgrade to t1lib version 5.0.2, and and additional off-by-one bugfix
+ for MAXPATHLEN.
+ + Added support for libtool, as in teTeX-beta, and resync'ed with
+ the teTeX sources (many thanks to Thomas Esser for helping with
+ this!)
+ + Fixed a failed assertion when pressing `Shift-r' (reload) after
+ a DVI file had been deleted (also reported by Thomas Esser), and
+ a problem with the `-unique' option not always reloading the file
+ as it should (idem).
+ + Added <ESC> key bindings to close some dialogs (suggested by Bernhard
+ Walle in #912671).
+ + Close dependent windows when parent is closed (e.g. warning popups
+ for the save dialog).
+ + Made the `editor' X resource deal correctly with quoted arguments
+ (for arguments containing spaces; see #907714).
+ + Additinally support the paper formats `letter', `ledger' and `tabloid'
+ for better dvips compatibility, suggested by Dragan Milicic.
+
+ * 22.81 (2004/02/24):
+ + If no --with-toolkit option was given, check if Motif is available,
+ and use it if it is; else, use Xaw. (Use --with-toolkit=xaw to override
+ this default).
+ + Problem with flashing redraw of highlighted region when partially
+ obscured by another window reported and fixed by Zhang Lin-bo.
+ + Fixed #870323 (an error in the online help).
+ + Fixed #880550 (documented Ctrl-s; add default _pp suffix
+ to filenames only when saving partial files).
+ + Added an option '-findstring' for string search from the command
+ line, similar to inverse search.
+ + Improved character name detection in string search by using
+ T1lib function T1_GetCharName().
+ + Fixed #883708 (oversplitting of forward search markers).
+ + Fixed #876815 (closing search window failed under certain conditions).
+ + Fixed a race condition with hyperlinks and browser startup that might
+ lead to `unknown op-code' crashes, reported again by Zhang Lin-Bo.
+ + Workaround for #884290 (drag&drop in file selector freezes xdvi/X)
+ by disabling drag&drop. Thanks to Bernhard Walle for reporting the bug
+ and suggesting the workaround.
+ + Fixed #885464 (wrong parent window in message popups) by passing in parent
+ widget.
+ + Upgraded to t1lib version 5.0.1.
+ + Implemented a simple page history (feature request #884674).
+ + Implemented hyperref specials inserted by \usepackage[dvips]{hyperref}
+ (feature request #662096).
+ + Fixed wrong page number initialization when going back a hyperlink
+ to a different file (#902073).
+
+ * 22.78 (2003/12/12):
+ + Improved test for iconv lib to make it work on Mac OS X
+ (reported by Artemio Gonzalez Lopez,
+ http://sourceforge.net/mailarchive/forum.php?thread_id=3535253&forum_id=2244).
+ + Added more encodings for string extraction/search, reported
+ by Ulrich Scholz (#850787).
+ + Fixed a bug with redrawing the page after file had been reloaded
+ by `-watchfile', and a crash when using find while file was
+ reloaded (#850795), again reported by Ulrich Scholz (many thanks!)
+ + Force C locale when converting X resources to numbers, so that
+ `.' is used as decimal point (#855950 - many thanks to Martin Vaeth
+ for finding this bug).
+ + Fixed a bug when loading first file via the file selector,
+ reported by Dragan Milicic.
+ + Fixed a bug with inverted highlighting not working on Solaris,
+ again reported by Ulrich Scholz (#850788)
+ + Don't close file selector if opening the new DVI file failed
+ (feature request #851545, again by Ulrich Scholz).
+ + Implemented a0/a0r and other missing DIN A/B/C formats (feature
+ request #852431).
+ + Fixed wrong binding for XmDIALOG_OK_BUTTON instead of XmDIALOG_CANCEL_BUTTON
+ in create_dialogs().
+ + Fixed a bug with hyperlinks that wrapped across several lines
+ and pointed to another page: these were highlighted as visited
+ only when region was exposed the second time.
+ + Fixed a compatibility problem with fork/vfork on Mac OS X, as in
+ xdvi-22.78.
+ + Added a `creating fonts' info window before main window is mapped
+ (just a preliminary hack, no replacement for truly asynchronous
+ font creation, since that window also feezes during font creation;
+ see also feature request #614708).
+ + Fixed a bug with width computation of initial window with
+ `-expertmode 0'
+ + Workaround by Zhang Lin-Bo for bug #856547 (presumably a
+ race condition with GS_PIXMAP_CLEARING_HACK and scanned_page_*
+ global variables).
+
+ * 22.77.3 (2003/11/25):
+ + Fixed a few compilation problems on Solaris (#827454, and
+ headers in print-internal.c).
+ + Added an option `ignore hyphenation/linebreaks' for string search.
+ + Use inverse highlighting instead of drawing bounding box,
+ as in Acroread/xpdf, implemented by Zhang Lin-Bo.
+ + Make the pagelist use physical pages by default, unless
+ `UseTeXPages' option is used.
+ + Made search settings honour the X resources for setting
+ checkboxes (suggested by Reiner Steib).
+ + Made the `Home' and `End' buttons go to the top and bottom
+ of the page, and Ctrl-Home and Ctrl-End to the first and last
+ page of a document, respectively.
+ + Added the forgotten directory texk/xdvik/texmf-alt for
+ non-current-teTeX systems.
+ + Fixed an X error with toggling fullscreen mode when
+ -fullscreen option had been used (thanks to Zhang Lin-Bo
+ for reporting it).
+ + Fixed an off-by-one error in string backwards search that
+ had made it skip every second match for matches of length 1.
+ + Removed the -DOmega define and made Omega a runtime option that
+ is enable by default and can be disabled via the -noomega
+ command-line option or the `Omega' X resource.
+ + Removed the --disable-htex compilation option.
+ + Added support for CJK fonts when saving a file as UTF-8,
+ and when searching in a file with such fonts (many thanks
+ to Zhang Lin-Bo for providing the patches).
+ + Made toolbar.xpm obey the current window background colors.
+ + Fixed a crash when saving a DVI file with empty pages
+ in text format (again reported and fixed by Zhang Lin-Bo).
+ + Fixed a crash when opening nonexisting files via the file
+ selector in Motif (again reported by Zhang Lin-Bo).
+ + Fixed a crash with GS_PIXMAP_CLEARING_HACK when toggling
+ gs_alpha on a page with PS graphics (again reported by
+ Zhang Lin-Bo).
+ + Fixed broken `Print to file' option, and wrong page numbers
+ passed to dvips when `P' has been used to assign a different
+ page number to the current page
+ + Added string `physical pages' to print popup (#841434)
+
+
+ * 22.77.2 (2003/10/18):
+ + Implemented support for additional file formats in save dialog:
+ PS, PDF, DVI, and plain text (in ISO-8859-1 and UTF-8).
+ + Implemented string search in DVI files (feature request
+ #470389).
+ + Fixed an incompatibility with X11R5 (#803642; thanks to
+ Ulrich Scholz for his help with debugging this).
+ + Fixed a problem with the cursor masks on some X displays
+ (#804294, again reported and debugged by Ulrich Scholz).
+ + Fixed a problem with the initial tooltip window having
+ the wrong (too large) size on some systems (#802806; thanks
+ to Kostas Oikonomou for help with debugging this).
+ + Also dump PS header files (e.g. psfrag.pro) to partially saved
+ or printed files.
+ + Fixed a security problem (tmp race) with xdvizilla (#812600;
+ thanks very much to Thomas Esser for help with fixing this).
+ + Used another workaround for the Ghostscript `alpha' driver
+ problem with not erasing previous images: Call `erasepage'
+ explicitly for pages with PS graphics (#633420; many thanks
+ to John Bowman for providing a patch).
+ + Fixed a bug with --datadir or --prefix being overwritten by
+ default TEXMFMAIN if they didn't contain a valid texmf tree
+ (#814004; thanks to Han-Wen Nienhuys for reporting this).
+ + Fixed a typo in the Motif menu accelerator for set-gs-alpha()
+ (`V', not `0v', also reported by Han-Wen Nienhuys).
+ + Fixed bug #814328 (prevent Ctrl-l from changing position
+ when switching back from fullscreen mode).
+ + Fixed bug #810501 (`keep position' value was lost when resizing
+ to fullscreen had removed the scrollbars). Thanks again to
+ Ulrich Scholz for reporting these bugs.
+ + Fixed a typo in the manpage, and broken redrawing of page
+ (again reported by Ulrich Scholz, #819937).
+ + Also resolve symbolic links in the main DVI name; this should
+ improve the behaviour with inverse search, cf. #768817,
+ and the search for e.g. embedded graphics or hyperlinks.
+ + Use ',' as separator for command-line debugging options
+ instead of `|'.
+ + Fixed a linker problem with multiple definitions on Cygwin.
+
+
+ * 22.77.1 (2003/09/06):
+ + Fixed the support for the window manager `delete' protocol
+ for Xaw.
+ + Fixed bug #797171 (BadValue X error when toggling expert
+ mode on Solaris; thanks to Erik Frisk for helping me with
+ debugging this).
+ + Fixed a bug introduced in 22.76 with wrong argument to
+ kpse_set_program_name(), which results in kpathsearch
+ not finding font files etc. properly if SELFAUTODIR is used.
+ Reported by Erik Frisk. (And a fix to that fix, reported
+ by Dragan Milicic.)
+ + Fixed obsolete link in the `New Features' Help menu entry.
+
+ * 22.77 (2003/08/25):
+ + Fixed bug #784204 (failed assertion with Motif at startup)
+ + Removed the check for the DVI file inode number in forward
+ search, since (as opposed to original xdvi) xdvik expands the
+ DVI filename to a full path, so it's sufficient to match the
+ full path.
+ + Fixed bug #779521 (crashes when printing with temporary file
+ enabled; thanks to Bernhard Walle for spotting this).
+ + Fixed bug #769025 (saving the DVI file may result in a corrupted
+ copy; thanks to Ulrich Scholz for reporting and help with
+ debugging it).
+ + Always dump `literal' PS specials (starting with `!') to
+ the output file, otherwise things like draftcopy won't work
+ for partially saved DVI files.
+ + New application icons (lion with `X').
+
+ * 22.76.1 (2003/06/28):
+ + Implemented a -watchfile option, as in gv (#547137).
+ + Implemented feature request #759865: To avoid `DVI file
+ corrupted' messages (and some race conditions with the
+ drawing routines that might result in `bad opcode' errors
+ when paging through a DVI file while it is being written by
+ TeX), xdvik now creates a backup version of the file being
+ viewed. This file is swapped with a fresh version of the
+ original each time the original file has been written
+ completely by TeX. The command line option `-notempfile'
+ can be used to revert to the previous behaviour (no
+ temporary file).
+ + Fixed a bug with up-or-previous() and down-or-next()
+ ignoring keep flag (which broke gs display, since that
+ relied on home()).
+ + Enabled XtAppAddTimeout() for Xaw, just like for Motif.
+ + Removed the STATUSLINE conditional compilation (which was
+ broken).
+ + Added a `pixels' ruler unit.
+ + Implemented a workaround for the `stale pixmaps' problem
+ with the gs x11alpha driver (#633420), by first drawing a
+ rectangle in background color of the size of the bounding
+ box to clear the pixmap.
+ + Fixed bugs #762621 (-sourceposition and -unique didn't fork
+ properly) and #762765 (printing/saving of marked pages was
+ broken) in the (withdrawn) version 22.76; thanks to
+ Zhang Lin-Bo and Bernhard Walle for reporting these bugs.
+ + Removed the XPM application icon used since xdvik-22.74, after it
+ became apparent that it was a plagiarized version of OzTeX's icon
+ (in an older version). Reported by OzTeX's author Andrew Trevorrow;
+ our sincere apologies to him.
+
+ * 22.74.3 (2003/06/17):
+ + Security fix for MIME types: Escape all special characters
+ (e.g. backticks) in the filename argument to prevent execution
+ of malicious shell code when launching a MIME viewer.
+ + Fixed a bug in the up-or-previous() action (#754805; thanks
+ to Bernhard Walle), and changed the behaviour of the `keep'
+ flag so that up-or-previous() and down-or-next() ignore it
+ (after all, the ordinary up() and down() actions will already
+ keep the position, so they can be used instead if you don't
+ want the scrolling).
+ + Made XBell honour the bell volume (set e.g. by xset; #751763;
+ thanks to Bernhard Walle for reporting this).
+
+ * 22.74.2 (2003/06/01):
+ + Fixed a bug with `.dvi' extension not being added if file had a
+ `.' in it (#743876; thanks to Markus Kohm for noting it). Now
+ the algorithm is the same as in non-k xdvi for files passed on
+ the command line. For files opened via hyperlinks, no extension
+ is added.
+ + Fixed a bug with wrong topic name in `Help' pulldown menu
+ (#743280; thanks to Bernhard Walle for reporting this).
+ + Fixed another bug with Omega .vf font searching (#746551;
+ thanks to Alexej Kryukov for reporting it).
+
+ * 22.74.1 (2003/05/25):
+ + Fixed bug with misplaced link underlining when first character in
+ the link is an accented composite character (#737643; thanks to
+ Christian Ullrich for spotting this).
+ + Made forward search also work when file had been changed
+ and not yet reloaded (#738387).
+ + Fixed typos in `-expertmode' description in man page
+ (followups to #737019).
+ + Fixed a compilation problem when --disable-t1lib is used
+ (thanks to Ross Alexander for providing patches).
+ + Fixed a bug with `-s n' argument not working when -fullscreen
+ is given as well, reported by Zhang Lin-Bo.
+ + Fixed a bug with forward search not warning when it hadn't found
+ the file name in the specials.
+ + Made forward search canonicalize all `../', `./' and `//' in
+ the `-sourceposition' argument and in the source specials.
+ + Fixed a bug with window size not being reset correctly when
+ activating expert mode in fullscreen mode (Xaw).
+ + Added a help topic for `ruler mode'.
+ + Fixed a bug with the icon and Xaw menu code causing
+ BadMatch X errors (#740982).
+ + Setting mouse translations in Motif's `mainTranslations'
+ erroneously disabled the default pagelist translations (reported
+ by Zhang Lin-Bo).
+ + Made usage() output the options in sorted order (thanks to
+ Nelson Beebe for the patch).
+ + Added a `-unique' option (as in KDVI) for loading a new file
+ into a running instance of xdvik.
+ + Fixed a bug with the Motif `PS' options menu (#743085; thanks to
+ Bernhard Walle for finding this).
+ + Fixed a bug with xdvi always appending a `.dvi' extension even if
+ the file already had an extension (#743182; thanks to David Feest
+ for noting this).
+ + Fixed two bugs with compilation under Cygwin (-lXpm linker option
+ too early, and MAX() not defined in xaw_men.c; thanks to Geoffrey
+ Vallis for reporting these).
+ + Fixed a bug with scroll_page_if_needed() being called with wrong
+ arguments if forward search hadn't found a glyph and used the
+ special hotspot instead.
+
+ * 22.74 (2003/05/14):
+ + New option/X resource `-expertmode <n>' option replaces
+ `-statusline', `-toolbar' (and effectively also
+ `-expert', which is only supported for backwards
+ compatibility). This should fix bug #737019 and make
+ the interoperation of the various expert settings more
+ evident.
+
+ * 22.74-beta4 (2003/05/13):
+ + Fixed a bug with Omega and T1fonts (thanks to Hossein
+ Movahhedian for reporting it).
+ + Fixed a bug with t1lib not correctly setting dvi_adv
+ for .notdef chars (thanks to Zhang-Lin Bo for spotting it
+ and providing a patch).
+ + Added configure check for including `-lXpm' option.
+ + Fixed a bug with tooltips sometimes popping up without
+ the pointer being over them.
+ + Fixed a bug with the -statusline option causing a segfault
+ when toggling -expert mode (#721807, thanks to Axel Riese).
+ + Expert mode now also removes the scrollbars (#718224);
+ menu bar/status line are togglable independently.
+
+ * 22.74-beta2 (2003/03/27):
+ + Added Paul's fix for the Solaris core dump problem, and
+ re-enabled the Motif timer fix for #674992. (Special thanks
+ to Dragan Milicic for help with debugging this.)
+ + Fixed a bug with the NumLock key disabling lowercase
+ key accelerators (#708935; thanks to Diego Santa Cruz
+ for spotting this.)
+ + Replaced MIMELIBDIR and MAILCAPDIR by the more standard
+ path definitions EXTENSIONMAPS and MAILCAPS (RFC 1343).
+ Mailcap parsing now honours the `test=' and `needsterminal'
+ fields.
+ + Improved `Usage' output by showing the option that hadn't
+ been recognized (suggested by Gabriel Zachmann).
+ + Fixed bug that instance that last had focus wasn't used for
+ forward search when there were several instances of xdvi
+ displaying the same file (#619070).
+ + Fixed xdvizilla permissions on install (#705158).
+ + Fixed a bug with the OLD_XAW detection in the configure script
+ (reported by Reiner Steib).
+ + Made hyperlinks also work with image anchors. (Thanks to
+ Gabriel Zachmann for spotting this.)
+
+ * 22.74-beta1 (2003/03/20):
+ + Reverted change for bug #674992 since it causes core dumps
+ on Solaris.
+ + Fixed wrong values for b6(r) and b7(r) paper sizes.
+ + Added warning about not implemented `hdvips' specials
+ + Fixed bug with PgUp/PgDown key (#610206; thanks to
+ Ingo Krabbe for finding the fix).
+ + Fixed a const/_Xconst mismatch (#693647; thanks to
+ Matthias Koeppe for spotting it).
+ + fixed a few hyperref bugs with links of the form
+ file:foo#target not working properly (#693306; thanks
+ to Kostas Oikonomou for finding this), and a memory
+ corruption caused by the -anchorposition argument.
+ + Upgraded to kpathsea 3.4.5.
+ + New layout for help window (topics list in left pane).
+
+ * 22.73-beta1 (2003/02/23):
+ + Fixed bug with Motif print log hanging (#674992, as in
+ xdvi-22.72), and another race condition with the print
+ process (as in xdvi-22.73).
+ + Fixed segfault that happened when starting without PS rendering
+ and switching it on later (#684880)
+ + Fixed a bug with underlines positioned too low on wrapped hyperlinks
+ (#685652)
+ + Made text fields in print dialog resize when window is resized.
+ + Made popups respect the window manager closing/destroy action
+ + Print command now may contain pipes (#685235).
+ + Added resources `dvipsHangTime' and `dvipsFailHangTime' for
+ customizing the time the dvips print log remains open
+ (#684620).
+ + Implemented simple but hopefully efficient `ruler mode'
+ (feature request #525129).
+ + Removed the old `grid' mode, which didn't have any real
+ purpose at all.
+ + Fixed description of the `-pause' option in the man page.
+
+ * 22.71-beta1 (2003/02/10):
+ + New Xaw GUI layout: pulldown menus instead of buttons,
+ added a page list for easier navigation.
+ + New Motif GUI layout, including a toolbar and a page list.
+ + Removed libwww; use web browser instead to retrieve
+ remote documents.
+ + Added support for color specials (as in xdvi-22.50), and
+ colored hyperlinks.
+ + Added support for papersize specials (as in xdvi-22.66).
+ + Added page list for easier navigation.
+ + Added `Print' (as in xdvi-22.53) and `Save' dialogs.
+ + Added a fullscreen mode (works reliably with Motif only)
+ and a simple `pause' feature
+ + Added string debugging options (e.g. `-debug T1').
+ + Swapped the DBG_PS (64) and DBG_OPEN (32) debugging options,
+ so that the kpathsea options now are a continuous range.
+
+ * 22.40y1 (2003/08/24):
+ + Fixed a typo in xdvi.c and in the man page (X resource is
+ called t1lib, not not1lib). Reported to debian-tetex-maint
+ by Matt Swift.
+ + Fixed a segfault occuring when loading nonexistent graphics
+ files if the filename or PSfile special contains `:' (#793395;
+ many thanks to Frank Küster for helping me debugging this).
+ + NOTE: 22.40y is now considered `frozen' and will not be further
+ developed; only major bugs (which we don't expect at this point)
+ will be fixed. Users and distributors are asked to switch to the
+ 22.7x branch instead.
+
+ * 22.40y (2003/06/06):
+ + Fixed a bug with Omega .vf font searching (#746551);
+ as in 22.74.2.
+
+ * 22.40x (2003/04/23):
+ + Fixed a bug with .tfm files not being produced for
+ Type1 fonts for which mf sources exist, posted to dctt
+ (<slrnbaaj4g.1h4.Bernhard.Walle@news.bwalle.de>).
+
+ * 22.40w (2003/04/06):
+ + Fixed wrong values for b6(r) and b7(r) paper sizes
+ + Added warnings about not implemented `hdvips' specials,
+ and when requesting .notdef glyphs from a type1 font
+ + Added executable permissions to xdvizilla (#705158)
+ + Fixed a memory corruption bug when opening links to
+ local files fails (#715793)
+
+ * 22.40v (2003/02/01):
+ + Replaced all strdup() instances by xstrdup().
+ + Fixed a compatibility problem with AIX3 in xserver-info.c.
+ + Some documentation changes (README.t1fonts, README.t1mapper).
+
+ * 22.40u (2003/01/18):
+ + Fixed bug #669426 (scrolling the message popups could
+ result in BadMatch X Errors in case xdvi's color depth was
+ larger than the default depth of the screen).
+ + Updated to kpathsea 3.4.4.
+ + Some minor changes in documentation and status messages.
+
+ * 22.40t (2002/12/27):
+ + Fixed some prototype declarations.
+ + Made shell command in xdvi-search.el also work with (t)csh
+ (#649173).
+
+ * 22.40s (2002/11/30):
+ + Update for changed EPS handling in ghostscript 8.00,
+ which had caused previous xdvi(k) versions to hang (#644702).
+ + Replaced the startxdvi script by internal subshell handling
+ in xdvi-search.el, as suggested by Thomas Gerds
+ <gerds@paracelsus.fdm.uni-freiburg.de>.
+
+ * 22.40r (2002/11/14):
+ + Prevent the magnifier from popping up in the button panel.
+ + Removed vsnprintf() from wwwfetch.c.
+ + Fixed return value in xdvi_exit().
+
+ * 22.40q (2002/11/12):
+ + Fixed broken configure check for memicmp().
+ + Fixed a glitch in the fontname hash table lookup.
+ + Fixed a broken prototype with display postscript.
+
+ * 22.40p (2002/11/10):
+ + Fixed --version and --help options (#626569).
+ + Fixed a bug with TT fonts in X giving an error with the file
+ selector (#627607)
+ + Used kpathsea hash table to speed up processing of large .map
+ files.
+ + Added help page on mouse buttons.
+ + Added X server info for ease of debugging.
+
+ * 22.40o (2002/10/17):
+ + More changes for ANSI C; fixed a few compilation problems
+ on Tru64 v5.1, HP-UX-10.20 and Mac OS X.
+ + Upgraded to kpathsea v.3.3.8, and libwww version 5.4.0.
+ + Show numerical prefix in the statusline.
+ + Fixed a bug with `FIXME_ps_lock' not being defined when
+ configuring "with-ps=dps" (thanks to Norman Wattenberg
+ for reporting and fixing it).
+ + Improved warnings about incorrect papersize options.
+ + New actions do-href() and do-href-newwindow() to allow
+ binding a mouse event independent of magnifier binding.
+ + Some additions to the man page.
+ + Fixed bug #518761: Xdvik won't exit(1) any more when
+ there had been a problem parsing a Type1 encoding or font file.
+ + Fixed bug #619632: try Type1 fallback first, then PK
+ fallback, and generate PK fallback if it's not already present.
+ + Added a wrapper script `xdvizilla' that makes xdvi act as a
+ Mozilla helper application, which can also deal with .tar files.
+
+ * 22.40n (2002/09/15):
+ + Fixed a few bugs in xdvi-search.el (thanks to Reiner Steib
+ for spotting them, and suggesting patches)
+ + Merged in changes for libs and configure from teTeX-beta
+ (had been planned only for HEAD, but the situation became
+ too messy) - thanks to Thomas Esser for the great work in
+ teTeX that made this much easier ;-)
+ This means that --with-system-wwwlib and --with-system-t1lib
+ now finally work properly.
+ + Removed K&R compatibility macros to address bugs with gcc 3.2
+ on Solaris, and simplify the setup.
+ Users who really need K&R support should look at Paul Vojta's
+ version of xdvi instead: http://math.berkeley.edu/~vojta/xdvi.html
+ + Added progress indicator for file downloads
+
+ * 22.40m (2002/09/14):
+ + Same as 22.40n, except that the depend.mk file had contained
+ references to locally installed libwww headers that had made it
+ unusable.
+ For that reason, 22.40m was withdrawn and replaced by 22.40n.
+
+ * 22.40l (2002/09/01):
+ + Fixed a memory leak (#599082, discovered and patched by
+ Nobuyuki Tsuchimura)
+ + Updated configure to deal with Mac OS X (bug #597977)
+ + Change rules for multiple entries in .map files: Now later entries
+ override previous ones, which is the same behaviour as dvips. Also,
+ xdvik now gives a warning if such a case occurs.
+ + Fixed a memory corruption bug that could occur when
+ switching from a file for which PK font creation failed to
+ another file in the file selection dialog
+ + Documentation changes and minor GUI changes (button positions,
+ re-introduce `First' and `Last' buttons that had been lost
+ in some previous change, de-iconify window on forward search)
+ + Fixed a bug with values <= 0 for the `+page' option causing
+ xdvi to exit ungracefully (#601722, again discovered and patched by
+ Nobuyuki Tsuchimura)
+
+ * 22.40k (2002/05/21):
+ + Fixed bug #559113 (segfault with large .map files)
+ + Fixed a bug in 22.40j with magnifier sometimes not
+ appearing for files opened via the file selection dialog
+
+ * 22.40j (2002/04/30):
+ + Fix the compatibility problems with Ghostview v.7.04 and
+ 7.20 (see the thread "xdvi 22.40i status" in the tex-k
+ mailing list, and feature request #525127).
+ + Fix bug #550357 that might cause segfaults when doing a forward
+ search on a corrupted DVI file.
+ + Replace grid1, grid2 and grid3 resources/options by
+ rulecolor resource/option, and make grid and magnifier
+ window use this resource.
+ + Fix a typo in lucida.map (replaced 850 by .850)
+
+ * 22.40i (2002/04/08):
+ + Fixed buffer overflow bug in hypertex.c that broke opening
+ a new xdvi instance with Mouse-2 on hyperlink
+
+ * 22.40h (2002/03/19):
+ + Removal of t1lib documentation and sample fonts reduces
+ package size from 3MB to 2MB.
+ + Fix hyperref bugs #505100 and #473361, and a failed assertion
+ when starting a command (e.g. the EDITOR) fails with no output.
+ + Additional configure options for xaw3d and neXtaw.
+
+ * 22.40g (2002/01/08):
+ + Upgrade to t1lib v1.3.1.
+ + Fix bug with XInternAtoms not available in X11R5.
+ + Fix bug #478034 (shell escapes were incorrectly treated as URLs).
+ + Fix bug #500386 (wrong scaling of faked small caps fonts).
+ + Don't exit with usage message when n in the `+n' command line
+ option (for goto-page) exceeds the total number of pages, but go to
+ the last page instead.
+
+ * 22.40f (2001/11/02):
+ + Updgrade to t1lib v1.2.
+ + Fix a t1lib rendering bug with mfmodes different from 600dpi (#474213).
+
+ * 22.40e (2001/10/09):
+ + fixed a serious bug in previous version: libwww_wrapper_HTLoadToFile
+ (use of xfopen) caused an infinite recursion when saving a remote file
+ to disk.
+ + minor change in README files
+
+ * 22.40d (2001/10/08):
+ + Use libwww_wrapper_HTLoadToFile to make xdvik more immune to libwww bugs
+ and interface changes.
+
+ * 22.40c (2001/08/06):
+ + Fix some T1 font sizing problems when switching between
+ documents (#441029, #443743)
+ + Fix a memory leak with popup windows
+ + Fix a libwww bug (segfault with invalid URIs, #434836)
+ + Improve error messages when fetching remote files fails
+ * 22.40b (2001/06/18):
+ + Fix bug with popup windows causing BadMatch X errors
+ under certain color settings (reported by T. Esser; patch from
+ xdvi-22.42).
+ * 22.40a (2001/06/07):
+ + Speed up T1 font loading by disabling afm files.
+ + Change .enc file handling to use same format as dvips
+ (requires update of xdvi.cfg).
+ + Fix a bug with `OK' button not working when several popups
+ are active.
+ * 22.40 (2001/06/01):
+ + Fix some segfaults with font generation and popup
+ windows on Solaris (thanks to T. Esser for reporting and helping
+ to fix).
+ * 22.39 (2001/05/28):
+ + Direct rendering of T1 Postscript(TM) fonts with t1lib.
+ + Source special support (forward + backward search) as in
+ xdvi.
+ + New GUI elements: statusline, message windows, help window.
+ + New event and action handling (from xdvi), with configurable
+ buttons.
+ + New actions: drag canvas with mouse, smooth scrolling with
+ arrow keys, and minor adjustments of other actions.
+ + Minor changes in hyperref and mime handling code to make it
+ more robust.
+ * 22.15 (1999/08/22):
+ + Compiles and works on SunOS 4.
+ * 22.08c (1999/06/15):
+ + The message 'Not a DVI file' accompanied by
+ xdvi terminating should be a lot more rare now. The mime-typing
+ and href mechanism was fixed somewhat.
+ * 22.08b (1999/06/12):
+ + Compressed PS files on more than one page
+ works better. Gets rid of /tmp/xdviXXXXX0: file exists messages
+ and the wrong PS graphics on the wrong page.
+ * 22.08 (1999/06/11):
+ + The "Help" button reappears.
+ * 22.05b (8/5/1999):
+ + Prototype and variable declaration fixups.
+ * 22.04 (1999/02/11):
+ + Adapt cleanup code to the k version. xdvik uses
+ a directory for tmp files, xdvi does not. Other tmp file cleanups;
+ it should be possible to access documents with more than 3
+ included figures by http now.
+ * 22.01 (1999/02/15):
+ Beta release again.
+ + Fix for (rare?) file-descriptor overflow.
+ + Fix for compilation warning about urlocalize
+ + Added `tags' target in top Makefile
+ + 22 would always use the antialiasing device of gs. Fixed.
+ * 22 (1999/02/05):
+ + Stable release. Sync with Paul Vojtas xdvi-22.
+ There are no functional changes since the last release, only some
+ tidying up.
+
+ Changes made during the xdvik-21 cycle:
+ * Documentation updates
+ * Numerous porting enhancements: In particular native and addon CCs
+ of AIX, HP-UX and Solaris now works.
+ * Several small cosmetical fixes.
+ * Clearification of copyright and licesing terms in documentation
+ and --version information.
+ * The percent lables on the shrink buttons are back. They also have
+ good shrink factors for both 300 and 600 dpi resolutions. Anyone
+ using 1200 dpi fonts with xdvi are welcome to contribute a patch
+ for that.
+ * Percent labels on user specified shrink buttons.
+ * Got rid of SIGSEGV when showing figures in dvi files whose path
+ contains / (ie. other than in .)
+ * Got rid of SIGSEGV when showing figures in remote (http:, ftp:)
+ files. Doing
+ xdvi http://www.math.uio.no/~janl/tex/tex.dvi
+ now works, with figures and all. Except if they're compressed.
+ * On IRIX and DEC-Unix, if your X libs are in a nonstandard place,
+ so that -L/path/X11 is needed, you also need -Wl,-rpath,/path/X11.
+ Autoconf already supported Solaris' -R.
+ * The Reopen button and automatic redisplay when the dvi file was
+ updated was broken. This will also make it reopen web retrived
+ files. If it will serve as the reload button in a WWW browser is
+ another matter entierly though.
+ * xdvi could not open the old file if Cancel was selected in the
+ selfile dialogue.
+ * The filename returned from the selfile dialogue was not being
+ URLized as it should.
+ * Use tempnam(3) to generate temporary directory name
+ * Reorganized to same hierarchy as upcomming teTeX 0.9 and tex-k 7.3
+ releases, by Thomas Esser.
+ * Update of libwww and kpathsea also by Thomas Esser.
+ * The shrink buttons work better. Patch by Keith Refson.
+ * Missing / in xfilepath in xdvi-sh
+ * Omega xdvik compilation problems fixed
+ * Selfile fix from Dr. Werner Fink helps the CANCEL button to work.
+ * mime.c patch from Allin Cottrell makes hypertex browsing more
+ reliable.
+ * xdvik always assumed that #foo is a URL fragment reference and
+ removed it unconditionaly. Emacs uses # as temporary file prefix
+ (and infix) and so emacs' TeX mode produced .tex and thus .dvi
+ files with # in the name. Problem found by many and solutions
+ suggested by many. Only remove #foo if the dvi name is an URL. To
+ open local files you had better not use URL format ;-)
+ * xdvik 21.21 was produced from xdvik 20c and xdvi-21.21. Two whole
+ days of work to get the merge sane.
diff --git a/Build/source/texk/xdvik/FAQ b/Build/source/texk/xdvik/FAQ
new file mode 100644
index 00000000000..bf0414cdbf0
--- /dev/null
+++ b/Build/source/texk/xdvik/FAQ
@@ -0,0 +1,248 @@
+This is an adapted version of Paul Vojta's FAQ for (non-k) xdvi, which is
+available from <URL:http://math.berkeley.edu/~vojta/xdvi_faq.txt>.
+
+This file answers the following questions about installing xdvi:
+
+ 1. Why do I get the message, ``Caution: overstrike characters may be
+ incorrect'' when running netscape and xdvi simultaneously, and why
+ does the screen output look so grainy?
+ 2. I have font files cmr10.tfm, etc. Why can't xdvi use them?
+ 3. I can't seem to set the font path correctly. Can you help me?
+ 4. Whenever I run xdvi, it prints out things like:
+ - mktexpk --mfmode cx --bdpi 300 --mag 'magstep(0)' --dpi 300 cmr7 '>&3'
+ mktexpk: /var/cache/fonts/pk/cx/public/cm/cmr7.300pk already exists.
+ Why is this?
+ 5. Why can't xdvi correctly display metapost files containing text?
+ 6. Why do I get weird vertical color stripes when using xdvi on my S3
+ Virge video card?
+ 7. What does the message "gs: No such file or directory" mean, and why
+ does xdvi need to call ghostscript?
+ 8. I am using gs 5.50 to render PostScript figures, and I find that
+ sometimes characters appear on the wrong page. Why is that?
+ 9. I am using gs 3.33 to render PostScript figures, but find that it
+ cuts some off below or to the right of a certain point, and others
+ are omitted entirely.
+ 10. I am trying to display PostScript specials with -DPS_GS, but
+ instead I get the message `gs: gs: Malformed ghostview color property.'
+ 11. What is this "_get_wmShellWidgetClass undefined" error?
+
+Last modified: 2002/08/23
+
+----------
+
+1. Why do I get the message, ``Caution: overstrike characters may be
+ incorrect'' when running netscape and xdvi simultaneously, and why
+ does the screen output look so grainy?
+
+This is because your video setup has only a limited number (typically 256)
+of different colors that can be displayed at any given time, and netscape
+is using most of them. There are several ways around this problem:
+
+ o Start xdvi before netscape. This should eliminate the problem for
+ that copy of xdvi (only).
+ o Invoke netscape via "netscape -ncols 130" This limits netscape's
+ color usage to 130. Other numbers may be used as well.
+ o Invoke netscape via "netscape -install" This causes netscape to run
+ with its own colormap. A disadvantage of this approach is that
+ netscape's colors will be bizarre when the cursor is outside netscape's
+ window, and conversely all other colors on the screen will look funny
+ when the cursor is in the netscape window.
+
+The screen output looks so grainy because xdvi is not able to use its
+anti-aliasing features without enough colors.
+
+----------
+
+2. I have font files cmr10.tfm, etc. Why can't xdvi use them?
+
+tfm files contain only minimal information about the characters
+in a font: just the height, width, depth, and kerning and ligature
+information. To obtain information about the shapes of the
+characters, xdvi needs pk, gf or pfb files. (pxl files also contain
+this information, but are obsolete. There are utilities to convert
+them to pk files though.)
+
+----------
+
+3. I can't seem to set the font path correctly. Can you help me?
+
+Try
+ xdvi -debug 4000 file.dvi
+to find out where xdvi is looking for the fonts.
+
+----------
+
+4. Whenever I run xdvi, it prints out things like:
+ - mktexpk --mfmode cx --bdpi 300 --mag 'magstep(0)' --dpi 300 cmr7 '>&3'
+ mktexpk: /var/cache/fonts/pk/cx/public/cm/cmr7.300pk already exists.
+ Why is this?
+
+It means either that:
+
+ (1) Your ls-R database is not up to date (fix this by running texhash), or
+ (2) Your font path is not set correctly (see #3, above).
+
+----------
+
+5. Why can't xdvi correctly display metapost files containing text?
+
+The problem is that the PS files created by MP are (normally) not
+self-contained. xdvi delegates the display of PS files to
+ghostscript, which fails to handle those files.
+
+A solution is to instruct MP to create true EPS files, by including
+ prologues:=2;
+at the top of the document. If you have the CM postscript fonts
+installed so that ghostscript can find them, you can continue to use
+the CM fonts, otherwise you'll have to switch to Times or such for the
+illustrations.
+
+Switching the fonts can be done setting 'defaultfont' to something
+like "ptmr8r" (for Times). For the TeX material in 'btex .. etex'
+blocks, it is best to set up the fonts once in a 'verbatimtex .. etex'
+block. (And same for LaTeX of course.)
+
+This answer courtesy of Olaf Weber.
+
+----------
+
+6. Why do I get weird vertical color stripes when using xdvi on my
+ S3 Virge video card?
+
+This is a bug in the XF86_S3V X server. It has been reported to XFree86.
+The response from them is that the XF86_S3V server is being phased out
+and that users should use the XF86_SVGA server instead (which also, as of
+XFree86 3.3.3, supports the S3 Virge chipset).
+
+----------
+
+7. What does the message "gs: No such file or directory" mean, and why
+ does xdvi need to call ghostscript?
+
+The message "gs: No such file or directory" means that xdvi needs to call
+ghostscript, but does not find it on your system. Ghostscript is a program
+used for rendering PostScript. It is needed by xdvi (1) for displaying
+PostScript specials in documents, and (2) for rendering PostScript fonts
+occurring in documents. In the latter case, xdvi calls a script (usually
+named mktexpk) which in turn calls the program gsftopk to render the font
+in a form usable by xdvi.
+
+----------
+
+8. I am using gs 5.50 to render PostScript figures, and I find that
+ sometimes characters appear on the wrong page. Why is that?
+
+This is a bug in ghostscript 5.50. The following patch will fix it:
+
+*** gdevx.c.orig Fri Jul 17 07:31:27 1998
+--- gdevx.c Sat Oct 17 23:42:50 1998
+***************
+*** 59,65 ****
+ ((gx_device_X *)(dev))->up_area = 0,\
+ ((gx_device_X *)(dev))->up_count = 0
+ #define update_flush(dev)\
+! if ( ((gx_device_X *)(dev))->up_area != 0 ) update_do_flush(dev)
+ private void update_do_flush(P1(gx_device *));
+
+ #define flush_text(dev)\
+--- 59,66 ----
+ ((gx_device_X *)(dev))->up_area = 0,\
+ ((gx_device_X *)(dev))->up_count = 0
+ #define update_flush(dev)\
+! if ( ((gx_device_X *)(dev))->up_area != 0 || IN_TEXT((gx_device_X *)(dev)) )\
+! update_do_flush(dev)
+ private void update_do_flush(P1(gx_device *));
+
+ #define flush_text(dev)\
+
+
+----------
+
+9. I am using gs 3.33 to render PostScript figures, but find that it
+ cuts some off below or to the right of a certain point, and others
+ are omitted entirely.
+
+You should apply the following patch. This will also fix similar errors
+with ghostview. This patch supersedes a previous patch I have suggested
+to some people.
+
+*** gdevxini.c.orig Sun Nov 6 13:46:42 1994
+--- gdevxini.c Mon Jun 5 15:40:18 1995
+***************
+*** 319,344 ****
+
+ /* The following sets the imageable area according to the */
+ /* bounding box and margins sent by ghostview. */
+! { float m[4];
+! m[0] = (llx - left_margin) / 72.0; /* left */
+! m[1] = (lly - bottom_margin) / 72.0; /* bottom */
+! m[2] = xdev->width / xdev->x_pixels_per_inch -
+! (urx + right_margin) / 72.0; /* right */
+! m[3] = xdev->height / xdev->y_pixels_per_inch -
+! (ury + top_margin) / 72.0; /* top */
+!
+! /******
+! ****** For reasons I don't understand,
+! ****** we have to set the margins to zero here
+! ****** in order for Ghostview to do landscape display right.
+! ******/
+! #if 0
+! m[0] = m[1] = m[2] = m[3] = 0;
+! #endif
+!
+! gx_device_set_margins((gx_device *)xdev, m, false);
+! }
+!
+ } else if (xdev->pwin == (Window)None) {
+ eprintf("gs: Cannot get ghostview property.\n");
+ exit(1);
+--- 319,329 ----
+
+ /* The following sets the imageable area according to the */
+ /* bounding box and margins sent by ghostview. */
+! xdev->ImagingBBox[0] = llx - left_margin;
+! xdev->ImagingBBox[1] = lly - bottom_margin;
+! xdev->ImagingBBox[2] = urx + right_margin;
+! xdev->ImagingBBox[3] = ury + top_margin;
+! xdev->ImagingBBox_set = true;
+ } else if (xdev->pwin == (Window)None) {
+ eprintf("gs: Cannot get ghostview property.\n");
+ exit(1);
+
+----------
+
+10. I am trying to display PostScript specials with -DPS_GS, but
+ instead I get the message `gs: gs: Malformed ghostview color property.'
+
+xdvi needs at least version 2.6.2 of ghostscript. It will also run with
+ghostscript 2.6.1, provided you have applied fixes 1-4. This particular
+error message means that you are running gs 2.6.1 without fixes 1-4.
+Probably you should get a newer version of ghostscript.
+
+----------
+
+11. What is this "_get_wmShellWidgetClass undefined" error?
+
+ In SunOS 4.1.2 Sun fixed a shared-library bug in ld which conflicts
+with the way X builds the shared Xmu library, causing these symbols, notably,
+to be undefined when building some X11 clients on SunOS 4.1.[23]:
+ _get_wmShellWidgetClass
+ _get_applicationShellWidgetClass
+Compiling "-Bstatic -lXmu -Bdynamic" is overkill; be sure to set
+OSTeenyVersion correctly in the config/sun.cf file and rebuild X11R5.
+
+To solve the problem if you are using OpenWindows 3.0 (X11R4-based Xt), please
+contact your local Sun office and request the following patches:
+
+Patch i.d. Description
+100512-02 4.1.x OpenWindows 3.0 libXt Jumbo patch
+100573-04 OpenWindows 3.0: xstdcmap fails to set XStandardColomap for
+ 24-bit machines [this also fixes bug 1087332, "With patched
+ ld and libc, customer is getting undefined symbols"]
+
+[Greg Earle, earle@Sun.COM; 7/92]
+
+A source patch for use with the X11R4 libraries was developed by Conrad
+Kimball (cek@sdc.boeing.com); it retrofits into R4 some fixes made in R5 to
+get around this problem. The patch is on ftp.x.org in [1/93]
+ contrib/X11R4_sunos4.1.2_patch_version3.Z
diff --git a/Build/source/texk/xdvik/INSTALL b/Build/source/texk/xdvik/INSTALL
new file mode 100644
index 00000000000..a642493ba31
--- /dev/null
+++ b/Build/source/texk/xdvik/INSTALL
@@ -0,0 +1,132 @@
+
+Compiling and Installing Xdvik
+==============================
+
+Xdvik is the kpathsea-enhanced version of xdvi. The program
+invocation name is still `xdvi' for compatibility reasons.
+
+Please submit bug reports, suggestions etc. to the sourceforge
+xdvik project page:
+
+ http://sourceforge.net/projects/xdvi/
+
+
+Note for users of older versions of teTeX (<= teTeX-1.0):
+=========================================================
+
+ Please consult the README file in the texk/xdvik/texmf-alt/
+ directory of the source distribution.
+
+
+Note for users of non-teTeX installations:
+==========================================
+
+ Please consult the files texk/xdvik/texmf-alt/README and
+ texk/xdvik/README.t1fonts for information on how to configure
+ xdvik for direct Type1 font rendering.
+
+
+1. Required Software
+
+ - X11R5 or newer and the Xt libraries
+
+ and one of:
+
+ - Xaw (Athena widgets)
+
+ - Motif >= 1.2 or newer
+ LessTif has a few bugs and restrictions that will result in limited
+ functionality (see the file texk/xdvik/LESSTIF-BUGS for details).
+ For best results, use OpenMotif 2.x.
+
+ You need both the headers and the runtime libraries to compile and run
+ xdvik (note that some Linux distributors put the headers into separate
+ `X development' pacakges).
+
+2. Configuring:
+
+ In the top-level directory (the directory in which this INSTALL
+ file is located), invoke:
+
+ ./configure
+
+ You can also specify a toolkit via the --with-x-toolkit option
+ (the default is to check if Motif is available and use it if it is):
+
+ ./configure --with-x-toolkit=xaw [other-options]
+
+ will compile with Xaw (Athena widgets) instead. You can set
+ the search paths for Motif header/library files with the
+ --with-motif-include and --with-motif-libdir options.
+
+ If configure gives you errors about the main texmf tree not being
+ found, specify its directory via the `--datadir' option.
+ On a standard teTeX system, use the output of the command:
+
+ kpsewhich --expand-path='$TEXMFMAIN'
+
+ *without* the `texmf' component as value for `--datadir'
+ (/usr/share or /usr/local/teTeX/share are possible values).
+
+ For all configuration options available, see the output of:
+ ./configure --help
+
+
+
+3. Compiling:
+
+ In the top-level directory, invoke:
+
+ make
+
+ This should compile the executable texk/xdvik/xdvi-TOOLKIT.bin,
+ where TOOLKIT is the value of the `--with-x-toolkit' specified
+ in the configure step, e.g. `xaw' or `motif' (the default).
+
+ If you set the environment variable XDVIINPUTS to the path
+ containing the files xdvi.cfg and ps2pk.map, you should be
+ able to test xdvi without actually installing it.
+
+
+
+4. Installation:
+
+ Usually, the binary xdvi-TOOLKIT.bin is invoked by a shell wrapper
+ `xdvi' which sets XDVIINPUTS and some other variables, like the X
+ search path.
+
+ If you only want to upgrade an existing version of xdvik, it should
+ be sufficient to copy xdvi-TOOLKIT.bin into a directory in your PATH
+ and check that the shell wrapper invokes the correct toolkit version.
+ (You may also want to update the man page from xdvi.1). These files
+ are located in the texk/xdvik subdirectory.
+
+ To install a new version from scratch, invoke:
+
+ make install
+
+ in the top-level directory to install all executable and data files.
+ This will not install the files in the texk/kpathsea subdirectory,
+ which is not required if you already have a working TeX installation
+ (and actually could overwrite your existing setup). If you don't have
+ kpathsea installed yet, you'll need to install it manually; basically
+ by doing `cd texk/kpathsea; make install'. Please see the file
+ texk/kpathsea/INSTALL for more information.
+
+
+
+5. Setup:
+
+ Make sure that the XDVIINPUTS variable (set in the system-wide
+ texmf.cnf file or in the environment, e.g. in your .profile)
+ contains the path to the directory DATADIR/texmf/xdvi, and
+ to the file ps2pk.map (usually in DATADIR/texmf/dvips);
+ e.g. by setting:
+
+ export XDVIINPUTS='.;$TEXMF/{xdvi,dvips}//'
+
+ If xdvik is still generating PK versions of fonts that you think
+ you have Type1 versions of, please consult texk/xdvik/README.t1fonts
+ for more information on how to configure xdvik correctly for Type1
+ fonts.
+
diff --git a/Build/source/texk/xdvik/LESSTIF-BUGS b/Build/source/texk/xdvik/LESSTIF-BUGS
new file mode 100644
index 00000000000..288421cc6de
--- /dev/null
+++ b/Build/source/texk/xdvik/LESSTIF-BUGS
@@ -0,0 +1,35 @@
+
+Bugs of current xdvik with LessTif
+==================================
+
+This is a list of known bugs if current xdvik is compiled with
+lesstif-0.93.18 (in decreasing severity).
+
+Some of them may be bugs in xdvik, others bugs with LessTif. Currently
+I don't have time and/or deeper knowledge of X to look into them.
+People who want a working verion should use either OpenMotif, or
+the Xaw version of xdvik instead. Ideas and tips are welcome ...
+-- S.U.
+
+- Page list: Toggling expert mode or the page list produces strange
+ results when page list is switched on again: List appears too wide
+ (hides part of horizontal scrollbar) and too short.
+
+- Main window layout: window is too narrow when starting in expert
+ mode (e.g. 80x900) and too wide (entire screen) in non-expert mode.
+ Workaround: Use -geometry argument to force a sensible window size.
+
+- Removing the scrollbars in expert mode doesn't work.
+
+- Newline character `\n' in LabelGadget texts doesn't cause a line
+ break. Workaround: Xdvi uses shorter labels when compiled with LessTif.
+
+- Spinbox replacement in LessTif looks ugly. Workaround: Xdvi
+ doesn't use Spinbox when compiled with LessTif.
+
+- Preferences window: Headings list (left window) is a few pixels
+ too small, cutoff of longest title. The list has a horizontal
+ scrollbar even though it's not needed, and the part that is
+ cut off can't be scrolled to. Workaround: Use extra trailing
+ whitespace for longest title in LessTif.
+
diff --git a/Build/source/texk/xdvik/Makefile.in b/Build/source/texk/xdvik/Makefile.in
new file mode 100644
index 00000000000..38f30271fd8
--- /dev/null
+++ b/Build/source/texk/xdvik/Makefile.in
@@ -0,0 +1,227 @@
+# Makefile for xdvik
+#
+# - 1999/05/08: janl: Removed submakes for libwww and kpathsea. That's what
+# the top makefile is for!
+#
+
+kpse_include ../make/paths.mk
+kpse_include ../make/common.mk
+kpse_include ../make/programs.mk
+kpse_include ../make/cross.mk
+
+all_subdirs = gui
+
+CPP = @CPP@
+
+# Make `#include <X11/...>' and `-lX...' work.
+# This matches web2c (needed only for Metafont).
+x_cppflags=@X_CFLAGS@ @iconv_includes@
+x_ldflags=@X_LIBS@ @x_linker_options@ @iconv_libpath@
+x_pre_libs=@X_PRE_LIBS@
+x_extra_libs=@X_EXTRA_LIBS@ @iconv_libs@
+x_tool_libs=@x_tool_libs@
+x_xmu_lib=@x_xmu_lib@
+x_xpm_libs=@x_xpm_libs@
+# -lXp and -lXext
+x_ext_lib=@x_ext_lib@
+
+# Follow the library order used in X11R6 itself.
+# It seems that on Cygwin, libXaw needs _XpmReadFileToPixmap, so we put
+# x_xpm_libs after the tool_libs -- but before -lX11, since on MacOSX it
+# uses XGrabServer and XUngrabServer, which would otherwise be
+# unresolved with static libraries.
+# Xmu needs to come before Xt and after the toolkit libs.
+x_link = $(LDLIBT1) $(x_ldflags) $(x_tool_libs) $(x_xmu_lib) -lXt $(x_pre_libs) $(x_ext_lib) $(x_xpm_libs) -lX11 $(x_extra_libs)
+
+LDLIBT1=@LDLIBT1@
+LIBT1CPPFLAGS=@LIBT1CPPFLAGS@
+LIBT1DEP=@LIBT1DEP@
+LIBT1DIR = ../../libs/t1lib
+LIBTYPE1DIR = $(LIBT1DIR)/../type1
+LIBT1SRCDIR = $(srcdir)/$(LIBT1DIR)
+
+# various xdvik GUI elements
+LIBGUI=./gui/libgui.a
+LIBGUIDEP=$(LIBGUI)
+
+
+# Extra xdvi-specific compiler options.
+# ps_def = @PS_DEF@ -DXSERVER_INFO -DNEW_MENU_CREATION
+# ps_def = @PS_DEF@ -DRGB_ANTI_ALIASING
+ps_def = @PS_DEF@
+prog_cflags = @XTRA_WARN_CFLAGS@ $(LIBT1CPPFLAGS) $(ps_def) \
+-I$(srcdir)/gui -I../../libs/t1lib/lib/t1lib -I../kpathsea $(x_cppflags)
+
+# Note: to be able to use one depend.mk file for both Motif/Xaw (which
+# is needed since only maintainers are supposed to invoke `make depend')
+# we include *all* object files and have tests for #ifdef MOTIF/XAW inside
+# the files.
+objects = \
+ browser.o \
+ dvi-draw.o \
+ dvi-init.o \
+ dvisel.o \
+ encodings.o \
+ events.o \
+ filehist.o \
+ font-open.o \
+ gf.o \
+ hypertex.o \
+ image-magick.o \
+ mime.o \
+ my-snprintf.o \
+ my-vsnprintf.o \
+ pagehist.o \
+ pk.o \
+ print-internal.o \
+ psdps.o \
+ psgs.o \
+ psheader.o \
+ psnews.o \
+ read-mapfile.o \
+ search-internal.o \
+ special.o \
+ string-utils.o \
+ tfmload.o \
+ util.o \
+ vf.o \
+ xdvi.o \
+ xserver-info.o \
+ x_util.o
+
+# t1mapper or its man page are currently not being installed, since they
+# aren't needed on most current (teTeX) systems
+perlprog = t1mapper
+manpage = xdvi
+
+default all: libguibuild @final_exec_name@ $(manpage).1
+
+$(LIBGUI):
+ cd gui; $(MAKE) $(makeargs) libgui.a
+
+### we need this additional target so that libgui is always checked to be up-to-date ...
+libguibuild:
+ cd gui; $(MAKE) $(makeargs) libgui.a
+
+@final_exec_name@: $(kpathsea) $(objects) $(LIBT1DEP) $(LIBGUIDEP)
+ $(kpathsea_link) $(objects) $(LIBGUI) $(x_link) $(LOADLIBES)
+
+squeeze.o: squeeze.c
+ $(build_compile) -c $<
+squeeze: squeeze.o
+ $(build_link_command) squeeze.o
+
+psheader.c: psheader.txt squeeze
+ ./squeeze $(srcdir)/psheader.txt $@
+
+$(manpage).1: xdvi.1.in sedscript
+ sed -f sedscript <$(srcdir)/xdvi.1.in >$@
+
+sedscript: mksedscript c-auto.h
+ $(SHELL) $(srcdir)/mksedscript $(srcdir) pkpath sizes vfpath \
+ figpath headerpath $(DEFS) $(prog_cflags) >$@
+
+install: install-exec install-data
+uninstall: uninstall-exec uninstall-data
+
+install-exec: @final_exec_name@
+ $(SHELL) $(top_srcdir)/../mkinstalldirs $(bindir)
+ $(INSTALL_LIBTOOL_PROG) @final_exec_name@ $(bindir)
+ $(INSTALL_SCRIPT) xdvi-sh $(scriptdir)/@wrapper_script@
+ rm -f $(scriptdir)/o@wrapper_script@
+ ln -s @wrapper_script@ $(scriptdir)/o@wrapper_script@
+### fix wrong CVS permissions for shell script
+ $(INSTALL_SCRIPT) $(srcdir)/xdvizilla $(scriptdir)/xdvizilla
+ chmod +x $(scriptdir)/xdvizilla
+
+uninstall-exec:
+ for p in @final_exec_name@; do rm -f $(bindir)/$$p; done
+ for p in @wrapper_script@ o@wrapper_script@; do rm -f $(scriptdir)/$$p; done
+
+install-data: $(manpage).1 pixmaps/toolbar.xpm pixmaps/toolbar2.xpm
+ $(SHELL) $(top_srcdir)/../mkinstalldirs $(man1dir)
+ $(SHELL) $(top_srcdir)/../mkinstalldirs $(texmf)/xdvi/pixmaps
+ $(INSTALL_DATA) $(manpage).1 $(man1dir)/$(manpage).$(manext)
+ rm -f $(man1dir)/o$(manpage).$(manext)
+ ln -s $(manpage).$(manext) $(man1dir)/o$(manpage).$(manext)
+ $(INSTALL_DATA) $(srcdir)/texmf/XDvi $(texmf)/xdvi/XDvi
+ $(INSTALL_DATA) $(srcdir)/pixmaps/toolbar.xpm $(srcdir)/pixmaps/toolbar2.xpm $(texmf)/xdvi/pixmaps
+ if \
+ grep 'original xdvi.cfg --' $(texmf)/xdvi/xdvi.cfg >/dev/null 2>&1 \
+ || test ! -r $(texmf)/xdvi/xdvi.cfg; \
+ then \
+ $(INSTALL_DATA) $(srcdir)/texmf/xdvi.cfg $(texmf)/xdvi/xdvi.cfg; \
+ else \
+ true; \
+ fi
+ $(INSTALL_DATA) $(srcdir)/xdvizilla.1 $(man1dir)/xdvizilla.$(manext)
+
+uninstall-data:
+ rm -f $(man1dir)/$(manpage).$(manext) $(man1dir)/xdvizilla.$(manext) \
+ $(scriptdir)/xdvizilla \
+ $(texmf)/xdvi/pixmaps/toolbar.xpm $(texmf)/xdvi/pixmaps/toolbar2.xpm \
+ $(texmf)/xdvi/XDvi
+ if \
+ head -n 1 $(texmf)/xdvi/xdvi.cfg | grep 'original xdvi.cfg --' >/dev/null 2>&1 \
+ || test ! -r $(texmf)/xdvi/xdvi.cfg; \
+ then \
+ rm -f $(texmf)/xdvi/xdvi.cfg; \
+ else \
+ true; \
+ fi
+ rmdir $(texmf)/xdvi/pixmaps
+
+distname = xdvik
+program_files = *.1.in *.ac xdvi.icon xdvi.FAQ psheader.txt mksedscript \
+ MOTIF
+version_files = xdvi.c
+
+pre-dist-$(distname):
+post-dist-$(distname):
+ cd $(top_distdir); rm -f xdvik/psheader.c
+
+kpse_include ../make/dist.mk
+kpse_include ../make/config.mk
+
+info dvi check:
+
+kpse_include ../make/clean.mk
+
+mostlyclean::
+ test ! -r gui/Makefile \
+ || for d in $(all_subdirs); do (cd $$d && $(MAKE) $@); done
+clean::
+ test ! -r gui/Makefile \
+ || for d in $(all_subdirs); do (cd $$d && $(MAKE) $@); done
+distclean::
+ test ! -r gui/Makefile \
+ || for d in $(all_subdirs); do (cd $$d && $(MAKE) $@); done
+extraclean::
+ test ! -r gui/Makefile \
+ || for d in $(all_subdirs); do (cd $$d && $(MAKE) $@); done
+maintainer-clean::
+ test ! -r gui/Makefile \
+ || for d in $(all_subdirs); do (cd $$d && $(MAKE) $@); done
+
+depend::
+ test ! -r gui/Makefile \
+ || for d in $(all_subdirs); do (cd $$d && $(MAKE) $@); done
+
+clean::
+ rm -f $(manpage).1 *.flc @final_exec_name@
+
+distclean::
+ rm -f psheader.c krheader.h sedscript $(manpage).1 *.flc *~ @final_exec_name@ xdvi-sh
+ test -f $(LIBTYPE1DIR)/Makefile && { cd $(LIBTYPE1DIR); $(MAKE) distclean; } || true
+ test -f $(LIBT1DIR)/Makefile && { cd $(LIBT1DIR); $(MAKE) distclean; } || true
+
+$(LIBT1DIR)/libt1.a:
+ cd $(LIBT1DIR); $(MAKE) $(makeargs) libt1.a
+
+$(LIBTYPE1DIR)/libtype1.a:
+ cd $(LIBTYPE1DIR); $(MAKE) $(makeargs) libtype1.a
+
+
+kpse_include ../make/tkpathsea.mk
+kpse_include ../make/rdepend.mk
+kpse_include depend.mk
diff --git a/Build/source/texk/xdvik/README.t1fonts b/Build/source/texk/xdvik/README.t1fonts
new file mode 100644
index 00000000000..0aa9ff538f0
--- /dev/null
+++ b/Build/source/texk/xdvik/README.t1fonts
@@ -0,0 +1,207 @@
+
+README for using Postscript Type1 fonts with xdvik
+==================================================
+
+Starting from version 22.39, xdvik supports direct display of
+Postscript Type1 fonts via t1lib. Unlike the bitmapped TeX PK fonts
+that xdvik used to depend upon, Type1 fonts only need to be stored in
+one size on disk. This means no more waiting for mktexpk runs when
+viewing DVI files with previously unused fonts or at a different
+resolution, less hassle with temporary directories filling up with
+PK files, etc.
+
+To be able to support Type1 fonts, xdvi needs a xdvi.cfg file. The
+standard `make install' process will copy the file from texmf/xdvi.cfg
+which is suitable for recent teTeX distributions (starting from teTeX
+>= 1.0). (If the file exists already and has been modified from the
+original, the modified file will not be overwritten). Apart from the
+section `Debugging your font setup', this README contains mostly
+instructions for versions of teTeX older than 1.0.x or non-teTeX
+systems; users of teTeX >= 1.0.x should ignore these instructions,
+and only consult the `Debugging' section in case of problems with
+the Type1 fonts setup.
+
+Note that xdvi can always use a TeX bitmap (PK) font as a fallback
+(produced via mktexpk, which in turn invokes ps2pk or gsftopk), so
+it's not vital that xdvi is configured for Type1 fonts. However, for
+the reasons mentioned above, setting up xdvi properly for Type1 fonts
+is usually preferable.
+
+
+==========================================================
+Instructions for users of older teTeX versions (< 1.0), or
+non-teTeX systems:
+==========================================================
+
+Xdvi needs to load all Type1 fonts from disk, which means that it
+(just like dvips) needs to translate the TeX names for fonts to
+filenames, load encoding vectors according to map files and so on.
+But unlike dvips, which produces Postscript code for printers with
+built-in fonts, xdvi has _no_ builtin fonts, and thus cannot share
+all font maps with dvips.
+The main difference is that fontmaps for xdvi always need to contain
+the name of a `real' Type1 font file (a .pfa or .pfb file) at the end
+of the line, e.g. `utmr8a.pfb' in the following case:
+
+ ptmr8r NimbusRomNo9L-Regu "TeXBase1Encoding ReEncodeFont" <8r.enc <utmr8a.pfb
+
+whereas dvips would only need the font file name for embedding the font
+into the PS file; otherwise, the font will be treated as `printer
+resident'.
+
+If you don't want to use Type1 fonts, simply create a empty xdvi.cfg
+file in the location pointed to by the XDVIINPUTS environment variable
+(this variable can also be defined in texmf.cnf).
+
+Otherwise, the xdvi.cfg file should list the map files (.map extension)
+that can be used by xdvi. The file `xdvi.cfg' in the texk/xdvik/texmf-alt/
+subdirectory of the xdvik distribution contains a default configuration
+that can be used for your own customizations. The xdvi.cfg file
+installed by the standard `make install' process is only suitable for
+more recent versions of teTeX, as mentioned above, so you'll need to
+copy this file manually into the directory pointed to by XDVIINPUTS.
+
+The sections `Fontmap file format' below and the dvips documentation
+contain more information on the fontmap file format.
+
+
+=================
+Font Search Order
+=================
+
+The order in which xdvi tries to load a font file is:
+1. Virtual fonts
+2. Type1 fonts
+3. PK fonts
+4. (If xdvi was compiled with gf support:) GF fonts
+
+For example, consider the search for TeX's default font `cmr10'. In
+most texk/teTeX installations the file cmr10.pfb is present in the
+texmf tree. This means that it is found at step 2 in the search and
+the Type1 font is used. Currently xdvi handles fonts with no
+"implied" encoding (such as cmr10) without configuration. Most texk and
+teTeX installations come with the Blue Sky Research/Y&Y Type1 versions
+of Knuths fonts, and xdvi will be able to use them with no further
+action.
+
+For fonts with an "implicit" encoding such as ptmr8r (Postscript Times
+Roman, 8r encoded), xdvi also needs to know about the 8r encoding,
+and be able to find a Type1 font file called ptmr (ptmr.pfa or
+ptmr.pfb). The file xdvi.cfg contains a list of these encodings and
+the corresponding dvips encoding files, which can be used by xdvi
+as well.
+
+The 35 `standard Postscript fonts', such as Times Roman, are are
+usually available under a different name for previewing the file with
+ghostscript. These font files can be used by xdvi, too, but they need
+to be copied to a place where xdvi can find them. This is already
+the case by default in newer TeX distributions such as teTeX-beta or
+teTeX >= 1.0 or TeXLive >= 6b. Users of older systems can use the
+`t1mapper' script to copy/symlink the required files to a directory
+where xdvi can find them; please see the file README.t1mapper and the
+manual page of t1mapper for more information.
+
+
+===================
+Fontmap file format
+===================
+
+In principle Xdvi only accepts a subset of the fontmaps used by dvips
+and pdftex. In practice the restrictions are not very restraining.
+For a description of the font map file syntax, see the `psfonts.map'
+section of the dvips manual (dvips.{texi,dvi,pdf}).
+
+Xdvi accepts fontmaps that obey these rules:
+
+1. The vector files must have a .enc extention or be included by the
+ <[ ... syntax in the fontmap. Encoding is optional. The ReEncodeFont
+ keyword and its argument is tolerated, but it is _ignored_. xdvi
+ looks for a <foo.enc or <[foo to determine the encoding vector, and
+ re-encode the font.
+
+2. The other file in the map line must be a font file in pfa or pfb
+ format. The extention need not be included for the sake of xdvi,
+ but dvips and pdftex might need it, so better include it when using
+ shared fontmap files. An explicit font file name is required by
+ xdvi since xdvi does not have any builtin fonts.
+
+3. There may not be any other input files on a fontmap line.
+
+ Xdvi is not a printer and cannot accept arbitrary postscript
+ prologues or setup things in fontmaps.
+
+4. Xdvi decodes the ExtendFont and SlantFont commands in the quoted
+ postscript code and the extention factor and slanting is applied
+ to the font when displayed. Any other magic done by the quoted
+ postscript code won't be understood by xdvi.
+
+
+=========================
+Debugging your font setup
+=========================
+
+If your Type1 font setup doesn't work, please check the following:
+
+1. Make sure that xdvi finds your xdvi.cfg file (it will print a warning
+ to stderr if it doesn't). The file should be located in a directory
+ referenced by the XDVIINPUTS variable, which can be either set in your
+ shell environment, or in your texmf.cnf file.
+
+2. Make sure that xdvi can find the map files listed in your xdvi.cfg
+ file (in the `dvipsmap' entries). Use the `-debug 3968' option for
+ xdvi to see where it searches for the files. E.g., with the (ba)sh
+ shell:
+
+ $ xdvi -debug 3968 ~/test.dvi 2>&1 | grep xyz.map
+
+ For a successful search, the end of the grep'ed output should
+ look like this:
+ kdebug:fopen(/some/paht/xyz.map, r) => 0x81cccd8
+
+ If the search is not successful, look at the debugging output in
+ more detail, checking which variable settings contribute to the
+ path where a file is searched.
+
+3. Make sure that xdvi finds the Type1 versions of your fonts. E.g.
+ if your texmf tree is located in /usr/local/share/texmf,
+ for a minimal LaTeX file like
+
+ \documentclass{minimal}
+ \begin{document}test\end{document}
+
+ the command
+ $ xdvi -debug 3968 ~/test.dvi 2>&1 | grep cmr10.pfb
+
+ should contain a line at the bottom that looks similar to this:
+ kdebug:search(cmr10.pfb) => /usr/local/share/texmf/fonts/type1/bluesky/cm/cmr10.pfb
+
+ Check the settings of TEXMFMAIN, TEXMF and T1FONTS in your
+ texmf.cnf file if this doesn't work.
+
+
+See also kpathsea.dvi and TETEXDOC.dvi for more information on the
+how kpathsea works.
+
+
+Some common sources of problems:
+
+- You have several texmf.cnf files on your system, and xdvi isn't
+ using the one you expect. Use the following command to find out
+ which:
+ $ xdvi -debug 3968 ~/test.dvi 2>&1 | grep texmf.cnf | grep fopen
+
+- The SELFAUTO... variables are used to define one of the TEXMF or
+ XDVIINPUTS variables in texmf.cnf, but xdvi.bin hasn't been
+ installed in a path that is compatible with SELFAUTO....
+ For example, if your texmf tree is
+ /usr/share/texmf/web2c/
+ and the search path contains
+ {$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}:
+ then xdvi.bin should be contained 2 directories below
+ /usr, e.g. in /usr/local/bin/xdvi.bin. ($SELFAUTOPARENT is
+ a misnomer in that it actually denotes the grand-parent
+ of the current directory, i.e. 2 levels up in the directory
+ hierarchy).
+
+ As a fix, either set XDVIINPUTS in your shell environment, or install
+ xdvi.bin in its proper place.
diff --git a/Build/source/texk/xdvik/README.t1mapper b/Build/source/texk/xdvik/README.t1mapper
new file mode 100644
index 00000000000..925600b415e
--- /dev/null
+++ b/Build/source/texk/xdvik/README.t1mapper
@@ -0,0 +1,187 @@
+
+README for t1mapper
+===================
+
+T1mapper is a utility for mapping/copying PostScript(tm) Type1 fonts
+from various sources (e.g. an existing ghostscript installation) into
+the texmf source tree to make them available for xdvik.
+
+The instructions in this README do not apply to users of recent teTeX
+(teTeX-beta or teTeX >= 1.0) or TeXLive (>= 6b) distributions; these
+already contain the required fonts within the texmf tree.
+
+For general information on the use of t1fonts with xdvik, please
+see the file README.t1fonts.
+
+
+
+T1mapper is written in Perl, and it should make it rather easy to
+install type1 fonts in a way such that xdvik can use them. The manual
+page of t1mapper(1) gives a short command overview, and the following
+sections describe the font installation in more detail.
+
+1. Installing the "standard" postscript fonts
+
+Have gs (ghostscript) version >= 4.x installed (or downloaded and
+unpacked), including both font packages ('std' and 'other'). If you
+have gs on your machine already you can check what version you have
+with the command 'gs -help'; this also tells you where the installed
+gs stores its fonts. Find the Fontmap file and the fonts. If you
+can't find them, pretend you don't have them and follow the
+instructions in the next paragraph.
+
+If you don't have gs installed you need to get it and and the font
+packages. A likely source of a recent ghostscript is
+
+http://sourceforge.net/projects/ghostscript/
+http://www.gnu.org/software/ghostscript/ghostscript.html
+
+
+You'll need to download the 2 font directories (`std' and `other')
+and the source package. From the latter, t1mapper only needs the file
+'Fontmap' or 'Fontmap.GS'.
+Install the files somewhere, e.g. to /usr/local/share/ghostscript/fonts.
+If you wonder about the contents of the Ghostscript font packages, and
+their relation to the "real" type1 fonts used in printers, please look
+at the GS docs.
+
+Decide where to install the font files for xdvi;
+/usr/local/teTeX/share/texmf/fonts/type1/gs is a likely place. Now
+run t1mapper (probably as root) to install the fonts:
+
+ t1mapper -lns -gs /usr/local/share/ghostscript/5.50/Fontmap \
+ /usr/local/share/ghostscript/fonts \
+ /usr/local/teTeX/share/texmf/fonts/type1/gs
+
+Notes:
+- For the meaning of -lns -gs and other t1mapper options, see below.
+- If you unpacked the gs packages and installed them by hand, please
+ correct the Fontmap path.
+- The directory
+ /usr/local/teTeX/share/texmf/fonts/type1/gs
+ will be created if it does not already exist.
+- With ghostscript >= 6.51, `Fontmap' is only a wrapper for `Fontmap.GS'.
+ Use `Fontmap.GS' instead of `Fontmap' in the invocation of t1mapper.
+
+In some versions of Linux, such as Red Hat Linux 7.x, the files have
+been split into two directories. Listing the contents of the gs related
+font packages reveals that they have been put in both
+/usr/share/fonts/default/ghostscript and
+/usr/share/fonts/default/Type1. If you use such a distribution, this
+might be the commands to use:
+
+ t1mapper -lns -gs /usr/share/ghostscript/5.50/Fontmap \
+ /usr/share/fonts/default/ghostscript \
+ /usr/share/texmf/fonts/type1/gs
+ t1mapper -lns -gs /usr/share/ghostscript/5.50/Fontmap \
+ /usr/share/fonts/default/Type1 \
+ /usr/share/texmf/fonts/type1/gs
+
+When the command is complete, all the fonts gs knows about will have
+been copied to /usr/local/teTeX/share/texmf/fonts/type1/gs. This will
+give you the standard PostScript fonts as well as some others.
+
+2. Installing Other Postscript Fonts
+
+If you already have some type1 fonts (other than the ones from
+ghostscript), you might want to add them as well. Some sites have
+extensive postscript font collections. All these fonts can be used.
+
+Additionaly, if you use a machine with a comercial Unix version (such
+as IRIX, Solaris, AIX, HP-UX, ...) it is quite likely that some type1
+fonts are installed on the machine. These can be used by ghostscript
+and xdvi. If you don't know where they are search for filenames such
+as '*.pfa', '*.pfb', and 'Times-Roman*' and you should be able to find
+them.
+
+To add the fonts found on a Solaris machine, use this command:
+
+t1mapper -lns /usr/local/teTeX/share/texmf/fonts/type1/gs \
+ /usr/openwin/lib/X11/fonts/Type1/*.pfa
+
+Run the command on all the type1 fonts you want to be able to use in
+xdvi.
+
+Notes:
+- Do not run t1mapper on the TeX type1 fonts (cm* and so on).
+- Fonts from the `Lucida' family have a rather difficult structure
+ and might be difficult to install. Please see the files xdvi.cfg and
+ lucida.map.
+
+Copying/linking them all to the same directory will ensure that only
+one version of each font is available to xdvi. t1mapper will remove
+any font version already available in the target directory before
+moving a font there.
+
+The -lns option will cause t1mapper to symlink the fonts instead of
+copying them, saving a good deal of disk space. Here's a quick summary
+of the options that can be used to customize what t1mapper does with
+the files:
+
+ -cp copy the font files, this is the default and will always work
+ and never break down on you.
+ -ln make hard links, this requires all the fonts to be on the same disk.
+ -lns make symbolic links, this requires that you do not remove the fonts
+ linked, or xdvi will not be able to use them anymore.
+ -lnlns attempt hard-link first, if it fails make symbolic link.
+ -lncp attempt hard-link first, if it fails copy the file. This is a way
+ to save some diskspace if possible, with no risk of files
+ disapearing.
+
+3. AFM files
+
+AFM files are not needed by xdvik. TFM files have more accurate width
+data and *must* be used to get correct alignment.
+
+
+4a. Standard TeX fonts in postscript version
+
+If you don't have cmr10.pfb, i.e., the type1 version of the
+traditional TeX fonts you need to get them from CTAN, e.g.,
+ftp.tex.ac.uk:/tex-archive/fonts/cm/ps-type1/bluesky/pfb/. Just drop
+them in a texmf directory, such as fonts/type1/bluesky/cm/. No
+further configuration should be needed to use these fonts.
+
+4b. AMS TeX fonts in postscript version
+
+Additionaly, get
+/tex-archive/fonts/amsfonts/ps-type1/amsps-unix.tar.gz and install the
+pfb files in fonts/type1/bluesky/ams.
+
+4c. More TeX fonts in postscript version
+
+There are some more type1 fonts in
+/tex-archive/fonts/cm/ps-type1/bakoma/pfb. As with the bluesky fonts
+drop them in a directory, such as fonts/type1/bakoma. There is a
+large overlap between the bakoma and bluesky fonts, you can save some
+confusion and diskspace by removing the bakoma fonts that have bluesky
+equivalents.
+
+(Side note: There are licensing restrictions on the use of the bakoma
+fonts which might prevent you from using them; one of them being the
+inclusion in finished documents. However, DVI files are not `finished'
+documents in this sense, since they don't contain the font shapes
+themselves; instead, xdvi needs to locate the fonts on disk.)
+
+If you do not want dvips to use the bakoma fonts, make sure that they are
+not referenced in any of the dvips fontmaps.
+
+5. Xdvi config files
+
+If you did not do 'make install' you will want to copy
+texk/xdvik/texmf/* from the source distribution into
+/usr/local/teTeX/share/texmf/xdvi. This copies some important
+configuration files describing encoding vectors and fonts to xdvi (see
+above).
+
+6. Almost finished
+
+All the font files are now where they should be. If you use a file
+database it's time to update it. TeTeX users run 'texhash' to obtain
+this effect.
+
+Xdvi can now find all the nice files and will not need pk versions of
+all those fonts.
+
+If you experience problems, please see the section `Debugging your
+font setup' in the file README.t1fonts.
diff --git a/Build/source/texk/xdvik/acconfig.h b/Build/source/texk/xdvik/acconfig.h
new file mode 100644
index 00000000000..5f4f8c98b93
--- /dev/null
+++ b/Build/source/texk/xdvik/acconfig.h
@@ -0,0 +1,386 @@
+/* regenerate c-auto.in from acconfig.h with:
+ /usr/bin/autoheader -m ../etc/autoconf
+ then run:
+ /usr/bin/autoconf -m ../etc/autoconf
+*/
+/* c-auto.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the ANSI # stringizing operator in cpp. */
+#undef HAVE_STRINGIZE
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the ANSI # stringizing operator in cpp. */
+#undef HAVE_STRINGIZE
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* c-auto.in. Generated from configure.in by autoheader. */
+/* Define to determine the integer type to be used in bitmaps. The type used
+ will be "unsigned BMTYPE". */
+#define BMTYPE int
+
+/* Define to the length (in bytes) of the above type. */
+#define BMBYTES 4
+
+/* Define if your system has STREAMS (and if X uses it). */
+#undef HAVE_STREAMS
+
+/* Define if you are using SunOS 4.x. */
+#undef SUNOS4
+
+/* Define if you are using Linux 2.1.xxx -- 2.2.8,
+ or if you find it necessary. */
+#undef FLAKY_SIGPOLL
+
+/* Define if your system has <poll.h> and poll(). */
+#undef HAVE_POLL
+
+/* Define to use the Xaw toolkit. */
+#undef XAW
+
+/* Define to use the Motif toolkit. */
+#undef MOTIF
+
+/* Define to enable greyscale anti-aliasing for shrunken bitmaps. */
+#undef GREY
+
+/* Define to enable support for color specials. */
+#undef COLOR
+
+/* Define to enable gf format files (in addition to pk format). */
+#undef USE_GF
+
+/* Define to use A4 as the default paper size. */
+#undef A4
+
+/* Define to use hypertex */
+#undef HTEX
+
+/* Define to use ImageMagick */
+#undef MAGICK
+
+/* ??? */
+#undef LDT1LIB
+
+/* Define to compile in t1lib */
+#undef T1LIB
+
+/* Define to compile in t1lib */
+#undef T1LIB
+
+/* Define if your C compiler can do string concatenation */
+#undef HAVE_CC_CONCAT
+
+/* Define if the memicmp() function is in <string.h> */
+#undef HAVE_MEMICMP
+
+/* Define to point to the default command to use for printing (optional). */
+#undef DEFAULT_DVIPS_PATH
+
+/* Define to point to the default command to use for printing (optional). */
+#undef DEFAULT_PS2PDF_PATH
+
+/* Define if you have an old version of the Xaw library */
+#undef HAVE_OLD_XAW
+
+/* Define if you want to use the Xpm library */
+#undef USE_XPM
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* Define to 1 if cpp supports the ANSI # stringizing operator. */
+#undef HAVE_STRINGIZE
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define if you have the fchdir function. */
+#undef HAVE_FCHDIR
+
+/* Define if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getcwd function. */
+#undef HAVE_GETCWD
+
+/* Define if you have the getpwnam function. */
+#undef HAVE_GETPWNAM
+
+/* Define if you have the getpwuid function. */
+#undef HAVE_GETPWUID
+
+/* Define if you have the getuid function. */
+#undef HAVE_GETUID
+
+/* Define if you have the isinf function. */
+#undef HAVE_ISINF
+
+/* Define if you have the lstat function. */
+#undef HAVE_LSTAT
+
+/* Define if you have the memcpy function. */
+#undef HAVE_MEMCPY
+
+/* Define if you have the mkstemp function. */
+#undef HAVE_MKSTEMP
+
+/* Define if you have the realpath function. */
+#undef HAVE_REALPATH
+
+/* Define if you have the setenv function. */
+#undef HAVE_SETENV
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the snprintf function. */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the ulltostr function. */
+#undef HAVE_ULLTOSTR
+
+/* Define if you have the vsnprintf function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if the vsnprintf function works. */
+#undef HAVE_GOOD_VSNPRINTF
+
+/* Define if your system allows setsid() within vfork(). */
+#undef HAVE_GOOD_SETSID_VFORK
+
+/* Define if your system allows multiple definitions of functions. */
+#undef LD_ALLOWS_MULTIPLE_DEFINITIONS
+
+/* Define if you have the waitpid function. */
+#undef HAVE_WAITPID
+
+/* Define if you have the <X11/Xmu/Editres.h> header file. */
+#undef HAVE_X11_XMU_EDITRES_H
+
+/* Define if you have the <X11/Xosdefs.h> header file. */
+#undef HAVE_X11_XOSDEFS_H
+
+/* Define if you have the <X11/xpm.h> header file. */
+#undef HAVE_X11_XPM_H
+
+/* Define if you have the <Xm/XpmP.h> header file. */
+#undef HAVE_XM_XPMP_H
+
+/* Define if you have the <xpm.h> header file (not in X11, e.g. Solaris 5.8). */
+#undef HAVE_XPM_H
+
+/* Define if you have the <iconv.h> header file. */
+#undef HAVE_ICONV_H
+
+/* Define if you have the iconv function. */
+#undef HAVE_ICONV
+
+/* Define the type of the iconv input string (char ** or const char **) */
+#undef ICONV_CHAR_PPTR_TYPE
+
+/* Define if you have the <ieeefp.h> header file. */
+#undef HAVE_IEEEFP_H
+
+/* Define if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <regex.h> header file. */
+#undef HAVE_REGEX_H
+
+/* Define if you have the <select.h> header file. */
+#undef HAVE_SELECT_H
+
+/* Define if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if the CODESET argument to nl_langinfo works. */
+#undef HAVE_WORKING_NL_LANGINFO_CODESET
+
+/* Define to use Xaw panner. */
+#undef USE_XAW_PANNER
+
+/* Define to use libXp. */
+#undef HAVE_LIB_XP
+
diff --git a/Build/source/texk/xdvik/aclocal.m4 b/Build/source/texk/xdvik/aclocal.m4
new file mode 100644
index 00000000000..023354bc00e
--- /dev/null
+++ b/Build/source/texk/xdvik/aclocal.m4
@@ -0,0 +1,1036 @@
+dnl ### Check whether iconv takes a 'const char **' or a 'char **' input argument.
+dnl ### According to EEE 1003.1, `char **' is correct, but e.g. librecode
+dnl ### uses `const char **'.
+dnl ### We use C++'s built-in function overloading to distinguish between the two.
+AC_DEFUN([XDVI_ICONV_CHAR_PPTR_TYPE],
+[
+AC_LANG_SAVE AC_LANG_CPLUSPLUS
+# AC_LANG_PUSH(C++) # in newer autoconf
+#
+xdvi_iconv_save_libs="$LIBS"
+xdvi_iconv_save_cxxflags="$CXXFLAGS"
+xdvi_iconv_save_ldflags="$LDFLAGS"
+#
+LIBS="$LIBS $iconv_libs"
+CXXFLAGS="$CXXFLAGS $iconv_includes"
+LDFLAGS="$LDFLAGS $iconv_libpath"
+#
+AC_MSG_CHECKING([for iconv input type])
+AC_CACHE_VAL(xdvi_iconv_char_pptr_type,
+[AC_TRY_RUN(
+[
+/* iconv() definitions may differ depending on following macros ... */
+#ifdef __hpux
+/* On HP-UX 10.10 B and 20.10, compiling with _XOPEN_SOURCE + ..._EXTENDED
+ * leads to poll() not realizing that a file descriptor is writable in psgs.c.
+ */
+# define _HPUX_SOURCE 1
+#else
+# ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+# endif
+# define _XOPEN_SOURCE_EXTENDED 1
+# define __EXTENSIONS__ 1 /* needed to get struct timeval on SunOS 5.5 */
+# define _SVID_SOURCE 1 /* needed to get S_IFLNK in glibc */
+# define _BSD_SOURCE 1 /* needed to get F_SETOWN in glibc-2.1.3 */
+#endif
+
+#include <iconv.h>
+
+ // Define two iconv_adapter() functions, one with a const char **, the other with
+ // a char ** argument. The compiler will figure out which one to use, and we can
+ // check the exit value to see which it was.
+ // Idea taken from http://gcc.gnu.org/ml/libstdc++/2000-11/msg00127.html
+
+ typedef const char ** ConstCharPtrT;
+ typedef char ** CharPtrT;
+
+ inline int
+ iconv_adapter(size_t(*iconv_func)(iconv_t, ConstCharPtrT, size_t *, char**, size_t*),
+ iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+ {
+ return 1; // 1 = false = const char **
+ }
+
+
+ inline int
+ iconv_adapter(size_t(*iconv_func)(iconv_t, CharPtrT, size_t *, char**, size_t*),
+ iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+ {
+ return 0; // 0 = true = char **
+ }
+
+
+ int main(void)
+ {
+ iconv_t testconv = (iconv_t)-1;
+ char *ptr1 = 0;
+ char *ptr2 = 0;
+ size_t len1 = 0;
+ size_t len2 = 0;
+
+ return iconv_adapter(iconv, testconv,
+ (char**)&ptr1, &len1,
+ (char**)&ptr2, &len2);
+ }
+],
+xdvi_iconv_char_pptr_type="char_pptr",
+xdvi_iconv_char_pptr_type="const_char_pptr",
+# `correct' default for cross-compiling ...
+xdvi_iconv_char_pptr_type="char_pptr")])
+#
+LIBS="$xdvi_iconv_save_libs"
+CXXFLAGS="$xdvi_iconv_save_cxxflags"
+LDFLAGS="$xdvi_iconv_save_ldflags"
+#
+if test $xdvi_iconv_char_pptr_type = "const_char_pptr"; then
+ AC_DEFINE(ICONV_CHAR_PPTR_TYPE, const char **)
+ AC_MSG_RESULT([const char **])
+else
+ AC_DEFINE(ICONV_CHAR_PPTR_TYPE, char **)
+ AC_MSG_RESULT([char **])
+fi
+AC_LANG_RESTORE]
+#AC_LANG_POP(C++) # in newer autoconf
+)
+
+dnl ### Check for whether setsid() is allowed within vfork()
+dnl (Mac OS X 10.3 (Panther, 11/2003) is one O/S which does not allow this.)
+
+AC_DEFUN([XDVI_FUNC_SETSID_IN_VFORK],
+[if test $ac_cv_func_vfork_works = yes; then
+AC_CACHE_CHECK([for whether setsid() is allowed within vfork()],
+xdvi_cv_setsid_in_vfork,
+[AC_TRY_RUN(
+[/* Test adapted from Gnu autoconf */
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+int
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ child = vfork ();
+
+ if (child == 0) {
+ if (setsid () == -1)
+ _exit(1);
+ _exit(0);
+ } else {
+ int status;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+ );
+ }
+}],
+xdvi_cv_setsid_in_vfork=yes,
+xdvi_cv_setsid_in_vfork=no,
+# safe value for cross-compiling
+xdvi_cv_setsid_in_vfork=no)])
+if test $xdvi_cv_setsid_in_vfork = yes; then
+ AC_DEFINE(HAVE_GOOD_SETSID_VFORK)
+fi]
+fi)
+
+dnl ### Check if the --allow-multiple-definition linker flag is
+dnl ### available (assuming that we need to use it if it is).
+dnl ### If it isn't, check if the linker accepts multiple definitions,
+dnl ### and if it doesn't, don't define LD_ALLOWS_MULTIPLE_DEFINITIONS.
+
+AC_DEFUN([XDVI_LINKER_MULTIPLE_DEFNS],
+[AC_CACHE_CHECK([whether linker supports the --allow-multiple-definition flag],
+xdvi_linker_multiple_defns,
+xdvi_save_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Xlinker --allow-multiple-definition"
+x_linker_options=""
+[AC_TRY_LINK(
+ [#include <stdio.h>
+ ],
+ [void foo(void);
+ ],
+ xdvi_linker_multiple_defns=yes, xdvi_linker_multiple_defns=no
+)]
+)
+if test $xdvi_linker_multiple_defns = yes; then
+ x_linker_options="-Xlinker --allow-multiple-definition"
+ LDFLAGS="$xdvi_save_LDFLAGS"
+ AC_DEFINE(LD_ALLOWS_MULTIPLE_DEFINITIONS)
+else
+ LDFLAGS="$xdvi_save_LDFLAGS"
+
+ xdvi_ld_save_LIBS="$LIBS"
+ xdvi_ld_save_CFLAGS="$CFLAGS"
+ xdvi_ld_save_CPPFLAGS="$CPPFLAGS"
+ xdvi_ld_save_LDFLAGS="$LDFLAGS"
+
+ LIBS="$X_PRE_LIBS -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+ CFLAGS="$X_CFLAGS $CFLAGS"
+ CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+ LDFLAGS="$X_LIBS $LDFLAGS"
+
+ AC_MSG_CHECKING([whether linker supports multiple definitions by default])
+
+ AC_TRY_LINK(
+ [#include <X11/Intrinsic.h>
+
+ XtIntervalId XtAppAddTimeOut(XtAppContext app,
+ unsigned long interval,
+ XtTimerCallbackProc proc,
+ XtPointer closure)
+ {
+ (void)app; (void)interval; (void)proc; (void)closure;
+ return (XtIntervalId)0;
+ }
+ ],[
+ XtIntervalId i = 0;
+ XtRemoveTimeOut(i);
+ ],
+ xdvi_linker_multiple_defns=yes, xdvi_linker_multiple_defns=no
+ )
+
+ if test $xdvi_linker_multiple_defns = yes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(LD_ALLOWS_MULTIPLE_DEFINITIONS)
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN([Linker does not allow multiple definitions.
+ *****************************************************************
+ * Warning: Your linker does not allow multiple definitions. *
+ * This does not make xdvik unusable, but it will cause problems *
+ * with event handling: Some widgets, e.g. the print log window, *
+ * tooltips, statusline messages and hyperlink location markers *
+ * will not be updated until the mouse is moved. *
+ *****************************************************************])
+ fi
+ LIBS="$xdvi_ld_save_LIBS"
+ CFLAGS="$xdvi_ld_save_CFLAGS"
+ CPPFLAGS="$xdvi_ld_save_CPPFLAGS"
+ LDFLAGS="$xdvi_ld_save_LDFLAGS"
+fi
+AC_SUBST(x_linker_options)])
+
+
+dnl ### Determine integer type to use for bitmaps
+
+AC_DEFUN([XDVI_C_BITMAP_TYPE],
+[AC_MSG_CHECKING(for integer type to use in bitmaps)
+AC_CACHE_VAL(xdvi_cv_bitmap_type,
+[AC_TRY_RUN(
+[#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ if ((sizeof(unsigned long) == 4 || sizeof(unsigned long) == 2)
+ && sizeof(unsigned long) != sizeof(unsigned int))
+ fprintf(f, "BMTYPE=long BMBYTES=%d\n", sizeof(unsigned long));
+ if (sizeof(unsigned int) == 4 || sizeof(unsigned int) == 2)
+ fprintf(f, "BMTYPE=int BMBYTES=%d\n", sizeof(unsigned int));
+ else if (sizeof(unsigned short) == 4 || sizeof(unsigned short) == 2)
+ fprintf(f, "BMTYPE=short BMBYTES=%d\n", sizeof(unsigned short));
+ else fprintf(f, "BMTYPE=char BMBYTES=%d\n", sizeof(unsigned char));
+ exit(0);
+}],
+xdvi_cv_bitmap_type="`cat conftestval`",
+AC_MSG_ERROR(could not determine integer type for bitmap))])
+eval "$xdvi_cv_bitmap_type"
+AC_DEFINE_UNQUOTED(BMTYPE, $BMTYPE)
+AC_DEFINE_UNQUOTED(BMBYTES, $BMBYTES)
+AC_MSG_RESULT([unsigned $BMTYPE, size = $BMBYTES])])
+
+
+dnl ### Check for whether the C compiler does string concatenation
+
+AC_DEFUN([XDVI_CC_CONCAT],
+[AC_CACHE_CHECK([whether C compiler supports string concatenation], xdvi_cc_concat,
+[AC_TRY_COMPILE(
+[#include <stdio.h>
+], [puts("Testing" " string" " concatenation");
+], xdvi_cc_concat=yes, xdvi_cc_concat=no)])
+if test $xdvi_cc_concat = yes; then
+ AC_DEFINE(HAVE_CC_CONCAT)
+fi])
+
+
+dnl ### Check for at-least-pretend Streams capability
+
+AC_DEFUN([XDVI_SYS_STREAMS],
+[AC_CACHE_CHECK([for stropts.h and isastream()], xdvi_cv_sys_streams,
+[AC_TRY_LINK(
+[#include <stropts.h>
+], [#ifndef I_SETSIG
+choke me
+#else
+isastream(0);
+#endif], xdvi_cv_sys_streams=yes, xdvi_cv_sys_streams=no)])
+if test $xdvi_cv_sys_streams = yes; then
+ AC_DEFINE(HAVE_STREAMS)
+fi])
+
+
+dnl ### Check for poll()
+
+AC_DEFUN([XDVI_FUNC_POLL],
+[AC_CACHE_CHECK([for poll.h and poll()], xdvi_cv_func_poll,
+[AC_TRY_LINK(
+[#include <poll.h>
+], [poll((struct pollfd *) 0, 0, 0);],
+xdvi_cv_func_poll=yes, xdvi_cv_func_poll=no)])
+if test $xdvi_cv_func_poll = yes; then
+ AC_DEFINE(HAVE_POLL)
+else
+ AC_CHECK_HEADERS(sys/select.h select.h)
+fi])
+
+
+dnl ### Check for SunOS 4
+
+AC_DEFUN([XDVI_SYS_SUNOS_4],
+[AC_CACHE_CHECK([for SunOS 4], xdvi_cv_sys_sunos_4,
+[case "`(uname -sr) 2>/dev/null`" in
+"SunOS 4."*)
+ xdvi_cv_sys_sunos_4=yes ;;
+*) xdvi_cv_sys_sunos_4=no ;;
+esac])
+if test $xdvi_cv_sys_sunos_4 = yes; then
+ AC_DEFINE(SUNOS4)
+fi])
+
+dnl ### Check for certain broken versions of Linux
+
+AC_DEFUN([XDVI_SYS_OLD_LINUX],
+[AC_CACHE_CHECK([for certain old versions of Linux], xdvi_cv_sys_old_linux,
+[case "`(uname -sr) 2>/dev/null`" in
+"Linux 2."[[01]].* | "Linux 2.2."[[0-8]] | "Linux 2.2."[[0-8]]-*)
+ xdvi_cv_sys_old_linux=yes ;;
+*) xdvi_cv_sys_old_linux=no ;;
+esac])
+if test $xdvi_cv_sys_old_linux = yes; then
+ AC_DEFINE(FLAKY_SIGPOLL)
+fi])
+
+dnl ### Process a string argument
+
+dnl XDVI_ARG_STRING(PACKAGE, HELP-STRING, VARIABLE, DEFAULT_VALUE)
+AC_DEFUN([XDVI_ARG_STRING],
+[AC_ARG_WITH($1, [$2], [AC_DEFINE_UNQUOTED($3, "$withval")
+], [AC_DEFINE($3, [$4])
+])])
+
+
+dnl dnl ### Check for vsnprintf() added by SU 2000/03/07
+dnl AC_DEFUN([AC_FUNC_VSNPRINTF],
+dnl [AC_CACHE_CHECK([for vsnprintf], xdvi_cv_vsnprintf,
+dnl [AC_TRY_LINK(
+dnl [#include <stdio.h>
+dnl ], [(void)vsnprintf((char *)NULL, 0, (char *)NULL, NULL);],
+dnl xdvi_cv_vsnprintf=yes, xdvi_cv_vsnprintf=no)])
+dnl if test $xdvi_cv_vsnprintf = yes; then
+dnl AC_DEFINE(HAVE_VSNPRINTF)
+dnl fi])
+
+dnl ### Check for a working implementation of (v)snprintf()
+dnl ### which should either return a negative result or the size actually needed
+dnl ### (latter is C99 standard).
+AC_DEFUN([XDVI_FUNC_WORKING_VSNPRINTF],
+[AC_CACHE_CHECK([for a working implementation of (v)snprintf()],
+xdvi_cv_func_good_vsnprintf,
+[AC_TRY_RUN(
+[
+#ifdef IRIX
+#define _XOPEN_SOURCE 500
+#endif
+#include <stdio.h>
+int main()
+{
+ char s[2];
+ int retval = snprintf(s, 2, "test");
+ if (retval > -1 && retval != 4) /* neither negative nor desired size, not OK */
+ return 1;
+ return 0;
+}],
+xdvi_cv_func_good_vsnprintf=yes,
+xdvi_cv_func_good_vsnprintf=no,
+# safe value for cross-compiling
+xdvi_cv_func_good_vsnprintf=no)])
+if test $xdvi_cv_func_good_vsnprintf = yes; then
+ AC_DEFINE(HAVE_GOOD_VSNPRINTF)
+fi])
+
+dnl ### Check for memicmp(), which some installations have in string.h
+AC_DEFUN([AC_FUNC_MEMICMP],
+[AC_CACHE_CHECK([for memicmp], xdvi_cv_memicmp,
+[AC_TRY_LINK(
+[#include <string.h>
+], [(void)memicmp((char *)NULL, (char *)NULL, 0);],
+xdvi_cv_memicmp=yes, xdvi_cv_memicmp=no)])
+if test $xdvi_cv_memicmp = yes; then
+ AC_DEFINE(HAVE_MEMICMP)
+fi])
+
+dnl dnl ### Check for realpath() added by SU 2002/04/10
+dnl AC_DEFUN([AC_FUNC_REALPATH],
+dnl [AC_CACHE_CHECK([for realpath], xdvi_cv_realpath,
+dnl [AC_TRY_LINK(
+dnl [#include <stdlib.h>
+dnl ], [(void)realpath((const char *)NULL, NULL);],
+dnl xdvi_cv_realpath=yes, xdvi_cv_realpath=no)])
+dnl if test $xdvi_cv_realpath = yes; then
+dnl AC_DEFINE(HAVE_REALPATH)
+dnl fi])
+
+
+dnl ### for Xpm libraries and headers.
+dnl Put Xpm include directory in xpm_includes,
+dnl put Xpm library directory in xpm_libraries,
+dnl and add appropriate flags to X_CFLAGS and X_LIBS.
+dnl
+AC_DEFUN([XDVI_FIND_XPM],
+[
+AC_REQUIRE([AC_PATH_XTRA])
+xpm_includes=
+xpm_libraries=
+AC_ARG_WITH(xpm,
+[ --without-xpm Do not use the Xpm library (will disable the toolbar)])
+dnl Treat --without-xpm like
+dnl --without-xpm-includes --without-xpm-libraries.
+if test "$with_xpm" = "no"
+then
+xpm_includes=no
+xpm_libraries=no
+fi
+AC_ARG_WITH(xpm-includes,
+[ --with-xpm-include=DIR
+ Specify the location of Xpm include files],
+xpm_includes="$withval")
+AC_ARG_WITH(xpm-libraries,
+[ --with-xpm-libdir=DIR
+ Specify the location of Xpm libraries],
+xpm_libraries="$withval")
+AC_MSG_CHECKING(for Xpm)
+#
+#
+# Search the include files. XPM can either be in <X11/xpm.h> (as in X11R6),
+# which is dealt with by AC_CHECK_HEADERS(X11/xpm.h), or in <xpm.h> if installed locally;
+# this is what this test is for.
+#
+if test "$xpm_includes" = ""; then
+AC_CACHE_VAL(xdvi_cv_xpm_includes,
+[
+xdvi_xpm_save_LIBS="$LIBS"
+xdvi_xpm_save_CFLAGS="$CFLAGS"
+xdvi_xpm_save_CPPFLAGS="$CPPFLAGS"
+xdvi_xpm_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXpm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+AC_TRY_COMPILE([
+#include <X11/xpm.h>
+],[int a;],
+[
+# X11/xpm.h is in the standard search path.
+xdvi_cv_xpm_includes="default"
+],
+[
+# X11/xpm.h is not in the standard search path.
+# Locate it and put its directory in `xpm_includes'
+#
+# /usr/include/Motif* are used on HP-UX (Motif).
+# /usr/include/X11* are used on HP-UX (X and Xaw).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Xaw).
+# Other directories are just guesses.
+for dir in "$x_includes" "${prefix}/include" /usr/include /usr/local/include \
+ /usr/X11/include /usr/X11R5/include /usr/X11R6/include \
+ /usr/include/Motif2.0 /usr/include/Motif1.2 /usr/include/Motif1.1 \
+ /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 \
+ /usr/dt/include /usr/openwin/include \
+ /usr/dt/*/include /opt/*/include /usr/include/Motif* \
+ "${prefix}"/*/include /usr/*/include /usr/local/*/include \
+ "${prefix}"/include/* /usr/include/* /usr/local/include/*
+do
+ if test -f "$dir/X11/xpm.h"; then
+ xdvi_cv_xpm_includes="$dir"
+ break
+ elif test -f "$dir/xpm.h"; then
+ xdvi_cv_xpm_includes="$dir"
+ break
+ fi
+done
+])
+#
+LIBS="$xdvi_xpm_save_LIBS"
+CFLAGS="$xdvi_xpm_save_CFLAGS"
+CPPFLAGS="$xdvi_xpm_save_CPPFLAGS"
+LDFLAGS="$xdvi_xpm_save_LDFLAGS"
+])
+xpm_includes="$xdvi_cv_xpm_includes"
+fi
+
+dnl Second arg of AC_CACHE_VAL shouldn't contain any AC_DEFINE's,
+dnl moved them out. Peter Breitenlohner <peb@mppmu.mpg.de>
+dnl
+if test "x$xpm_includes" != x; then
+ if test "x$xpm_includes" = xdefault; then
+ AC_DEFINE(HAVE_X11_XPM_H, 1)
+ elif test -f "$xpm_includes/X11/xpm.h"; then
+ AC_DEFINE(HAVE_X11_XPM_H, 1)
+ elif test -f "$xpm_includes/xpm.h"; then
+ AC_DEFINE(HAVE_XPM_H, 1)
+ fi
+fi
+
+#
+#
+# Now for the libraries.
+#
+if test "$xpm_libraries" = ""; then
+AC_CACHE_VAL(xdvi_cv_xpm_libraries,
+[
+xdvi_xpm_save_LIBS="$LIBS"
+xdvi_xpm_save_CFLAGS="$CFLAGS"
+xdvi_xpm_save_CPPFLAGS="$CPPFLAGS"
+xdvi_xpm_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXpm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+xdvi_cv_xpm_libraries=
+#
+#
+# We use XtToolkitInitialize() here since it takes no arguments
+# and thus also works with a C++ compiler.
+AC_TRY_LINK([
+#include <X11/Intrinsic.h>
+#include <X11/xpm.h>
+],[XtToolkitInitialize();],
+[
+# libxpm.a is in the standard search path.
+xdvi_cv_xpm_libraries="default"
+],
+[
+# libXpm.a is not in the standard search path.
+# Locate it and put its directory in `xpm_libraries'
+#
+#
+# /usr/lib/Motif* are used on HP-UX (Motif).
+# /usr/lib/X11* are used on HP-UX (X and Xpm).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Xpm).
+# Other directories are just guesses.
+for dir in "$x_libraries" "${prefix}/lib" /usr/lib /usr/local/lib \
+ /usr/lib/Motif2.0 /usr/lib/Motif1.2 /usr/lib/Motif1.1 \
+ /usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4 /usr/lib/X11 \
+ /usr/dt/lib /usr/openwin/lib \
+ /usr/dt/*/lib /opt/*/lib /usr/lib/Motif* \
+ "${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \
+ "${prefix}"/lib/* /usr/lib/* /usr/local/lib/*
+do
+ if test -d "$dir" && test "`ls $dir/libXpm.* 2> /dev/null`" != ""; then
+ xdvi_cv_xpm_libraries="$dir"
+ break
+ fi
+done
+])
+#
+LIBS="$xdvi_xpm_save_LIBS"
+CFLAGS="$xdvi_xpm_save_CFLAGS"
+CPPFLAGS="$xdvi_xpm_save_CPPFLAGS"
+LDFLAGS="$xdvi_xpm_save_LDFLAGS"
+])
+#
+xpm_libraries="$xdvi_cv_xpm_libraries"
+fi
+#
+# Add Xpm definitions to X flags
+#
+if test "x$xpm_includes" != "xdefault" && test "$xpm_includes" != "" \
+ && test "$xpm_includes" != "$x_includes" && test "$xpm_includes" != "no"
+then
+ X_CFLAGS="-I$xpm_includes $X_CFLAGS"
+fi
+
+if test "x$xpm_libraries" != "xdefault" && test "$xpm_libraries" != "" \
+ && test "$xpm_libraries" != "$x_libraries" && test "$xpm_libraries" != "no"
+then
+case "$X_LIBS" in
+ *-R\ *) X_LIBS="-L$xpm_libraries -R $xpm_libraries $X_LIBS";;
+ *-R*) X_LIBS="-L$xpm_libraries -R$xpm_libraries $X_LIBS";;
+ *) X_LIBS="-L$xpm_libraries $X_LIBS";;
+esac
+fi
+
+#
+#
+x_xpm_libs="-lXpm"
+#
+# Now check the results of headers and libraries and set USE_XPM to 0
+# if one of them hadn't been found.
+#
+AC_DEFINE(USE_XPM, 1)
+xpm_libraries_result="$xpm_libraries"
+xpm_includes_result="$xpm_includes"
+if test "x$xpm_libraries_result" = "xdefault" ; then
+ xpm_libraries_result="in default path"
+elif test "$xpm_libraries_result" = no || test "x$xpm_libraries_result" = "x"; then
+ xpm_libraries_result="(none)"
+ AC_DEFINE(USE_XPM, 0)
+ x_xpm_libs=""
+fi
+
+if test "x$xpm_includes_result" = "xdefault"; then
+ xpm_includes_result="in default path"
+elif test "$xpm_includes_result" = no || test "x$xpm_includes_result" = "x"; then
+ AC_DEFINE(USE_XPM, 0)
+ xpm_includes_result="(none)"
+fi
+
+AC_SUBST(x_xpm_libs)
+AC_MSG_RESULT(
+ [libraries $xpm_libraries_result, headers $xpm_includes_result])
+])dnl
+
+
+
+dnl ### Check for Motif libraries and headers
+dnl Put Motif include directory in motif_include,
+dnl put Motif library directory in motif_libdir,
+dnl and add appropriate flags to X_CFLAGS and X_LIBS.
+dnl If $1 is not `none', use Xaw as default toolkit if Motif isn't found.
+AC_DEFUN([XDVI_FIND_MOTIF],
+[
+default_toolkit="$1"
+motif_include="$2"
+motif_libdir="$3"
+AC_REQUIRE([AC_PATH_XTRA])
+AC_MSG_CHECKING(for Motif)
+#
+#
+# Search the include files.
+#
+if test "$motif_include" = ""; then
+AC_CACHE_VAL(xdvi_cv_motif_include,
+[
+xdvi_motif_save_LIBS="$LIBS"
+xdvi_motif_save_CFLAGS="$CFLAGS"
+xdvi_motif_save_CPPFLAGS="$CPPFLAGS"
+xdvi_motif_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+AC_TRY_COMPILE([#include <Xm/Xm.h>],[int a;],
+[
+# Xm/Xm.h is in the standard search path.
+xdvi_cv_motif_include=
+],
+[
+# Xm/Xm.h is not in the standard search path.
+# Locate it and put its directory in `motif_include'
+#
+# /usr/include/Motif* are used on HP-UX (Motif).
+# /usr/include/X11* are used on HP-UX (X and Athena).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Athena).
+# Other directories are just guesses.
+for dir in "$x_includes" "${prefix}/include" /usr/include /usr/local/include \
+ /usr/include/Motif2.0 /usr/include/Motif1.2 /usr/include/Motif1.1 \
+ /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 \
+ /usr/dt/include /usr/openwin/include \
+ /usr/dt/*/include /opt/*/include /usr/include/Motif* \
+ "${prefix}"/*/include /usr/*/include /usr/local/*/include \
+ "${prefix}"/include/* /usr/include/* /usr/local/include/*; do
+ if test -f "$dir/Xm/Xm.h"; then
+ xdvi_cv_motif_include="$dir"
+ break
+ fi
+done
+if test "$xdvi_cv_motif_include" = ""; then
+xdvi_cv_motif_include=no
+fi
+])
+#
+LIBS="$xdvi_motif_save_LIBS"
+CFLAGS="$xdvi_motif_save_CFLAGS"
+CPPFLAGS="$xdvi_motif_save_CPPFLAGS"
+LDFLAGS="$xdvi_motif_save_LDFLAGS"
+])
+motif_include="$xdvi_cv_motif_include"
+fi
+#
+#
+# Now for the libraries.
+#
+if test "$motif_libdir" = ""; then
+AC_CACHE_VAL(xdvi_cv_motif_libdir,
+[
+xdvi_motif_save_LIBS="$LIBS"
+xdvi_motif_save_CFLAGS="$CFLAGS"
+xdvi_motif_save_CPPFLAGS="$CPPFLAGS"
+xdvi_motif_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+# We use XtToolkitInitialize() here since it takes no arguments
+# and thus also works with a C++ compiler.
+AC_TRY_LINK(
+[#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+],[XtToolkitInitialize();],
+[
+# libXm.a is in the standard search path.
+xdvi_cv_motif_libdir=
+],
+[
+# libXm.a is not in the standard search path.
+# Locate it and put its directory in `motif_libdir'
+#
+# /usr/lib/Motif* are used on HP-UX (Motif).
+# /usr/lib/X11* are used on HP-UX (X and Athena).
+# /usr/dt is used on Solaris (Motif).
+# /usr/lesstif is used on Linux (Lesstif).
+# /usr/openwin is used on Solaris (X and Athena).
+# Other directories are just guesses.
+for dir in "$x_libraries" "${prefix}/lib" /usr/lib /usr/local/lib \
+ /usr/lib/Motif2.0 /usr/lib/Motif1.2 /usr/lib/Motif1.1 \
+ /usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4 /usr/lib/X11 \
+ /usr/dt/lib /usr/openwin/lib \
+ /usr/dt/*/lib /opt/*/lib /usr/lib/Motif* \
+ /usr/lesstif*/lib /usr/lib/Lesstif* \
+ "${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \
+ "${prefix}"/lib/* /usr/lib/* /usr/local/lib/*; do
+ if test -d "$dir" && test "`ls $dir/libXm.* 2> /dev/null`" != ""; then
+ xdvi_cv_motif_libdir="$dir"
+ break
+ fi
+done
+if test "$xdvi_cv_motif_libdir" = ""; then
+xdvi_cv_motif_libdir=no
+fi
+])
+#
+LIBS="$xdvi_motif_save_LIBS"
+CFLAGS="$xdvi_motif_save_CFLAGS"
+CPPFLAGS="$xdvi_motif_save_CPPFLAGS"
+LDFLAGS="$xdvi_motif_save_LDFLAGS"
+])
+#
+motif_libdir="$xdvi_cv_motif_libdir"
+fi
+# Add Motif definitions to X flags
+#
+if test "$motif_include" != "" && test "$motif_include" != "$x_includes" && test "$motif_include" != "no"
+then
+X_CFLAGS="-I$motif_include $X_CFLAGS"
+fi
+if test "$motif_libdir" != "" && test "$motif_libdir" != "$x_libraries" && test "$motif_libdir" != "no"
+then
+case "$X_LIBS" in
+ *-R\ *) X_LIBS="-L$motif_libdir -R $motif_libdir $X_LIBS";;
+ *-R*) X_LIBS="-L$motif_libdir -R$motif_libdir $X_LIBS";;
+ *) X_LIBS="-L$motif_libdir $X_LIBS";;
+esac
+fi
+#
+#
+motif_libdir_result="$motif_libdir"
+motif_include_result="$motif_include"
+test "$motif_libdir_result" = "" &&
+ motif_libdir_result="in default path" && AC_DEFINE(MOTIF, 1)
+test "$motif_include_result" = "" &&
+ motif_include_result="in default path" && AC_DEFINE(MOTIF, 1)
+if test "$motif_libdir_result" = "no"; then
+ if test "$default_toolkit" = "none"; then
+ motif_libdir_result="(none)"
+ else
+ motif_libdir_result=""
+ fi
+fi
+if test "$motif_include_result" = "no"; then
+ if test "$default_toolkit" = "none"; then
+ motif_include_result="(none)"
+ else
+ motif_include_result=""
+ fi
+fi
+
+if test "$motif_include_result" != "" && test "$motif_libdir_result" != ""; then
+ AC_MSG_RESULT([libraries $motif_libdir_result, headers $motif_include_result])
+ prog_extension="motif"
+ AC_DEFINE(MOTIF)
+ x_tool_libs="-lXm"
+else
+ AC_MSG_RESULT([not found, using Xaw])
+ prog_extension="xaw"
+ AC_DEFINE(XAW)
+ x_tool_libs="-lXaw"
+fi
+
+#
+AC_MSG_CHECKING(whether to compile in panner (requires Xaw))
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+AC_TRY_COMPILE([
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/Xaw/Reports.h>
+],[
+],
+xdvi_use_xaw_panner=yes, xdvi_use_xaw_panner=no
+)
+CPPFLAGS=$save_CPPFLAGS
+if test $xdvi_use_xaw_panner = yes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(USE_XAW_PANNER)
+else
+ AC_MSG_RESULT(no)
+fi
+])dnl
+
+dnl SU: the following is copied from gnome/compiler-flags.m4: turn on warnings for gcc
+dnl
+dnl COMPILER_WARNINGS
+dnl Turn on many useful compiler warnings
+dnl For now, only works on GCC
+AC_DEFUN([COMPILER_WARNINGS],[
+ AC_ARG_ENABLE(compiler-warnings,
+ [ --enable-compiler-warnings=[no/minimum/yes/maximum]
+ Turn on compiler warnings],,enable_compiler_warnings=minimum)
+
+ AC_MSG_CHECKING(what warning flags to pass to the C compiler)
+ warnCFLAGS=
+ if test "x$GCC" != xyes; then
+ enable_compiler_warnings=no
+ fi
+
+ if test "x$enable_compiler_warnings" != "xno"; then
+ if test "x$GCC" = "xyes"; then
+ case " $CFLAGS " in
+ *[\ \ ]-Wall[\ \ ]*) ;;
+ *) warnCFLAGS="-W -Wall -Wunused" ;;
+ esac
+
+ ## -W is not all that useful. And it cannot be controlled
+ ## with individual -Wno-xxx flags, unlike -Wall
+ if test "x$enable_compiler_warnings" = "xyes"; then
+ warnCFLAGS="$warnCFLAGS -pedantic -Wmissing-prototypes -Wmissing-declarations"
+ elif test "x$enable_compiler_warnings" = "xmaximum"; then
+ ## just turn on about everything:
+ warnCFLAGS="-Wall -Wunused -Wmissing-prototypes -Wmissing-declarations -Wimplicit -Wparentheses -Wreturn-type -Wswitch -Wtrigraphs -Wunused -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
+ fi
+ fi
+ fi
+ AC_MSG_RESULT($warnCFLAGS)
+
+ ### FIXME: if we restrict setting the flags to this case only, they will get overridden
+ ### somehwere else further up in the configure process.
+ if test "x$cflags_set" != "xyes"; then
+ XTRA_WARN_CFLAGS=$warnCFLAGS
+ AC_SUBST(XTRA_WARN_CFLAGS)
+# CFLAGS="$CFLAGS $warnCFLAGS"
+ cflags_set=yes
+ AC_SUBST(cflags_set)
+ fi
+])
+
+dnl ### Check for Xaw version
+AC_DEFUN([XDVI_OLD_XAW],[
+if test "${with_xdvi_x_toolkit}" = xaw; then
+ AC_MSG_CHECKING(for Xaw library)
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ AC_TRY_COMPILE([
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xaw/Form.h>
+ ],[
+ ],
+ xdvi_have_xaw=yes, xdvi_have_xaw=no
+ )
+ CPPFLAGS=$save_CPPFLAGS
+ if test $xdvi_have_xaw = yes; then
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR([Sorry, you will need at least the Xaw header/library files to compile xdvik.])
+ fi
+
+ AC_MSG_CHECKING(version of Xaw library)
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ AC_TRY_COMPILE([
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/ToggleP.h>
+ typedef void (*XawDiamondProc) (Widget);
+
+ /* New fields for the Radio widget class record */
+ typedef struct _RadioClass {
+ Dimension dsize; /* diamond size */
+ XawDiamondProc drawDiamond;
+ /* pixmaps for the button */
+ Pixmap sel_radio; /* selected state */
+ Pixmap unsel_radio; /* unselected state */
+ Pixmap sel_menu; /* selected state */
+ Pixmap unsel_menu; /* unselected state */
+ /* TODO: 3-d and xaw-xpm features? */
+ XtPointer extension;
+ } RadioClassPart;
+
+ /* Full class record declaration */
+ typedef struct _RadioClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ ToggleClassPart toggle_class;
+ RadioClassPart radio_class;
+ } RadioClassRec;
+ /* New fields for the Radio widget record */
+ typedef struct {
+ /* resources */
+ Boolean isRadio; /* radio if True, checkbox else */
+ /* TODO: 3-d and xaw-xpm features? */
+
+ /* private data */
+ XtPointer extension;
+ } RadioPart;
+
+ /* Full widget declaration */
+ typedef struct _RadioRec {
+ CorePart core;
+ SimplePart simple;
+#ifdef _ThreeDP_h
+ ThreeDPart threeD;
+#endif
+ LabelPart label;
+ CommandPart command;
+ TogglePart toggle;
+ RadioPart radio;
+ } RadioRec;
+
+
+ /* The actions table from Toggle is almost perfect, but we need
+ * to override Highlight, Set, and Unset.
+ */
+
+#define SuperClass ((ToggleWidgetClass)&toggleClassRec)
+
+#define BOX_SIZE 16
+#define PIXMAP_OFFSET 2 /* additional space between pixmap and label */
+ ],[
+ RadioClassRec radioClassRec = {
+ {
+ (WidgetClass) SuperClass, /* superclass */
+ "Radio", /* class_name */
+ sizeof(RadioRec), /* size */
+ NULL, /* class_initialize */
+ NULL, /* class_part_initialize */
+ FALSE, /* class_inited */
+ NULL, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ NULL, /* resources */
+ 0, /* resource_count */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ NULL, /* destroy */
+ NULL, /* resize */
+ NULL, /* expose */
+ NULL, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ XtInheritTranslations, /* tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL /* extension */
+ }, /* CoreClass fields initialization */
+ {
+ XtInheritChangeSensitive, /* change_sensitive */
+ NULL
+ }, /* SimpleClass fields initialization */
+ {
+ 0 /* field not used */
+ }, /* LabelClass fields initialization */
+ {
+ 0 /* field not used */
+ }, /* CommandClass fields initialization */
+ {
+ NULL, /* Set Procedure. */
+ NULL, /* Unset Procedure. */
+ NULL /* extension. */
+ }, /* ToggleClass fields initialization */
+ {
+ BOX_SIZE,
+ NULL, /* draw procedure */
+ None, /* selected radiobutton */
+ None, /* unselected radiobutton */
+ None, /* selected menubutton */
+ None, /* unselected menubutton */
+ NULL /* extension. */
+ } /* RadioClass fields initialization */
+ };
+ (void)radioClassRec;
+ ],
+ xdvi_old_xaw=no, xdvi_old_xaw=yes
+ )
+ CPPFLAGS=$save_CPPFLAGS
+if test $xdvi_old_xaw = yes; then
+ AC_MSG_RESULT(old)
+ AC_DEFINE(HAVE_OLD_XAW)
+else
+ AC_MSG_RESULT(current)
+fi
+fi
+])
diff --git a/Build/source/texk/xdvik/alloc-debug.h b/Build/source/texk/xdvik/alloc-debug.h
new file mode 100644
index 00000000000..0ef270cff11
--- /dev/null
+++ b/Build/source/texk/xdvik/alloc-debug.h
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "xdvi-config.h" /* for xmalloc etc. */
+
+#ifndef ALLOC_DEBUG_H__
+#define ALLOC_DEBUG_H__
+
+
+/*
+ * Simplistic macros to help finding `hot spots'/bugs in memory handling.
+ * Require that MALLOC(x) is never a single statement following an if(),
+ * else() etc. without braces, and never in the middle of a variable
+ * declarations list.
+ */
+
+/* #define DEBUG_MEMORY_HANDLING */
+
+#ifdef DEBUG_MEMORY_HANDLING
+#define XMALLOC(x,y) ( \
+ fprintf(stderr, "=== %s:%d: malloc(%p (%s), %d)\n", __FILE__, __LINE__, x, #x, y), \
+ xmalloc(y))
+#define XREALLOC(x,y) ( \
+ fprintf(stderr, "=== %s:%d: realloc(%p (%s), %d)\n", __FILE__, __LINE__, x, #x, y), \
+ xrealloc(x, y))
+#define FREE(x) ( \
+ fprintf(stderr, "=== %s:%d: free(%p (%s))\n", __FILE__, __LINE__, x, #x), \
+ free(x))
+#else
+#define XMALLOC(x,y) xmalloc(y)
+#define XREALLOC(x,y) xrealloc(x,y)
+#define FREE(x) free(x)
+#endif
+
+#endif /* ALLOC_DEBUG_H__ */
diff --git a/Build/source/texk/xdvik/browser.c b/Build/source/texk/xdvik/browser.c
new file mode 100644
index 00000000000..4fbbe342c1d
--- /dev/null
+++ b/Build/source/texk/xdvik/browser.c
@@ -0,0 +1,273 @@
+/* routines for launching a browser to retrieve remote documents.
+ * Copyright(C) 2002-2004 the xdvik development team.
+ */
+/*
+ * 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.
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <ctype.h>
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+
+#include <sys/types.h>
+#include <sys/wait.h> /* for waitpid(), WEXITSTATUS */
+
+#include "util.h"
+#include "message-window.h"
+#include "events.h"
+#include "browser.h"
+#include "string-utils.h"
+#include "statusline.h"
+
+static const char *const default_browser_cmd =
+ "netscape -raise -remote \"openURL(%s,new-window)\""
+ ":xterm -e lynx %s"
+ ":xterm -e wget %s";
+
+static Boolean
+do_fork_browser(char *argv[])
+{
+ pid_t pid;
+ switch(pid = vfork()) {
+ case -1: /* forking error */
+ perror("fork");
+ return False;
+ case 0: /* child */
+ execvp(argv[0], argv);
+ /* arrive here only if execvp failed */
+ XDVI_ERROR((stderr, "Execution of %s failed: %s", argv[0], strerror(errno)));
+ _exit(EXIT_FAILURE);
+ return False; /* notreached - make compiler happy */
+ default: /* parent */
+ {
+ int timeout;
+ for (timeout = 0; timeout < 15; timeout++) {
+ int status;
+ if (waitpid(pid, &status, WNOHANG)) {
+ TRACE_HTEX((stderr, "waiting for %d: %d", (int)pid, status));
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "Command `%s' exited with error status %d\n",
+ argv[0], WEXITSTATUS(status));
+ return False;
+ }
+ else {
+ TRACE_HTEX((stderr, "Child exited OK."));
+ return True;
+ }
+ }
+ else { /* when do we arrive here?? */
+ sleep(1);
+ }
+ }
+ else { /* waiting for child to finish */
+ sleep(1);
+ }
+ }
+ return True; /* child not finished in time */
+ }
+ }
+}
+
+static Boolean
+fork_browser(const char *browser, const char *url)
+{
+ char *cmd, *orig_cmd, *last_arg;
+ char **argv = NULL;
+ int argv_len = 0;
+ int i = 0, j = 0;
+ int match = 0;
+ int retval;
+
+
+ cmd = xmalloc(strlen(browser) + strlen(url) + 1);
+ orig_cmd = cmd; /* for freeing it later */
+ last_arg = cmd;
+
+ /* skip over leading space */
+ while (isspace((int)browser[i]))
+ i++;
+
+ while (browser[i] != '\0') {
+ while (j >= argv_len) {
+ argv_len += 10;
+ argv = xrealloc(argv, argv_len * sizeof *argv);
+ }
+ /* chop into separate arguments at spaces */
+ if (isspace((int)browser[i])) {
+ *cmd++ = '\0';
+ argv[j++] = format_arg(last_arg, url, &match);
+ last_arg = cmd;
+ /* skip over multiple spaces */
+ while (isspace((int)browser[i]))
+ i++;
+ }
+ /* remove quotes around arguments containing spaces */
+ else if (browser[i] == '\'' || browser[i] == '"') {
+ int len = 0;
+ /* normalize %% and replace %s by URL */
+ argv[j++] = unquote_arg(browser+i, url, &match, &len);
+ if (len == 0) { /* excess quote at end of arg; try to recover: */
+ j--;
+ break;
+ }
+ i += len + 1;
+ }
+ else {
+ *cmd++ = browser[i++];
+ }
+ }
+ *cmd = browser[i]; /* null-teminate */
+ /* append last, unless it contained only skipped spaces */
+ if (strlen(last_arg) > 0) {
+ argv[j++] = format_arg(last_arg, url, &match);
+ }
+
+ if (match == 0)
+ argv[j++] = xstrdup(url);
+ argv[j++] = NULL;
+
+ for (i = 0; argv[i] != NULL; i++) {
+ TRACE_HTEX((stderr, "arg[%d]: |%s|", i, argv[i]));
+ }
+
+ /* This will wait for child exits: */
+ retval = do_fork_browser(argv);
+ for (i = 0; argv[i] != NULL; i++)
+ free(argv[i]);
+ free(orig_cmd);
+ free(argv);
+ return retval;
+}
+
+void
+launch_browser(const char *filename)
+{
+ const char *browser;
+ int pid;
+ struct xchild *my_child;
+ struct xio *my_io;
+ int err_pipe[2];
+
+ /* try to set it from possible resources: First command-line argument
+ or X resource, then environment variables, then default_browser_cmd
+ */
+ for (;;) {
+ if ((browser = resource.browser) != NULL)
+ break;
+ if ((browser = getenv("BROWSER")) != NULL)
+ break;
+ if ((browser = getenv("WWWBROWSER")) != NULL)
+ break;
+ XDVI_INFO((stderr, "Browser not set (xdvi.wwwBrowser, -browser or $BROWSER environment variable)."));
+ XDVI_INFO((stderr, "Using built-in default: `%s'",
+ default_browser_cmd));
+ browser = default_browser_cmd;
+ break;
+ }
+
+ /* fork first time so that we can wait for children, without
+ freezing the GUI. FIXME: this copies stuff from
+ fork_process for the inter-process communication stuff -
+ it would be better to have this in one function. */
+ my_child = xmalloc(sizeof *my_child);
+ my_io = xmalloc(sizeof *my_io);
+ statusline_print(STATUS_MEDIUM, "Trying to launch browser ...");
+ /* 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);
+
+ if (pipe(err_pipe) < 0) {
+ perror("pipe");
+ _exit(-1);
+ }
+
+ switch (pid = fork()) {
+ case -1: /* forking error */
+ perror("fork");
+ close(err_pipe[0]);
+ close(err_pipe[1]);
+ return;
+ case 0: /* child */
+ {
+ char *tmp_browser = xstrdup(browser);
+
+ close(err_pipe[0]); /* no reading from stderr */
+
+ /* make stderr of child go to err_pipe[1] */
+ if (dup2(err_pipe[1], STDERR_FILENO) != STDERR_FILENO) {
+ perror("dup2 for stderr");
+ _exit(EXIT_FAILURE);
+ return; /* make compiler happy */
+ }
+
+ /*
+ BROWSER is a colon-separated list of commands, in decreasing preference;
+ use the first that can be forked successfully. Note that the return
+ value of the command isn't used at all (with GUI programs, xdvi shouldn't
+ hang until they terminate!)
+ */
+ while (tmp_browser != NULL) {
+ char *next = strchr(tmp_browser, ':');
+ if (next != NULL) {
+ *next++ = '\0';
+ }
+ TRACE_HTEX((stderr, "trying browser |%s|", tmp_browser));
+ /* fork a second time to start the browser */
+ if (fork_browser(tmp_browser, filename)) { /* foking worked */
+ _exit(EXIT_SUCCESS);
+ }
+ tmp_browser = next;
+ }
+ /* child arrives here only if none of the commands worked */
+ XDVI_WARNING((stderr, "None of the browser commands in the `browser' resource (%s) worked\n",
+ browser));
+ free(tmp_browser);
+ _exit(EXIT_FAILURE);
+ }
+ default: /* parent */
+ close(err_pipe[1]); /* no writing to stderr */
+
+ my_io->next = NULL;
+ my_io->fd = err_pipe[0];
+ my_io->xio_events = XIO_IN;
+#if HAVE_POLL
+ my_io->pfd = NULL;
+#endif
+ my_io->read_proc = read_child_error;
+ my_io->write_proc = NULL;
+
+ my_child->next = NULL;
+ my_child->pid = pid;
+ my_child->name = NULL;
+ my_child->proc = handle_child_exit;
+ my_child->data = NULL;
+ my_child->io = my_io;
+
+ set_chld(my_child);
+ statusline_print(STATUS_MEDIUM, "Trying to launch browser ... done.");
+ }
+}
+
+
diff --git a/Build/source/texk/xdvik/browser.h b/Build/source/texk/xdvik/browser.h
new file mode 100644
index 00000000000..0a5d13296be
--- /dev/null
+++ b/Build/source/texk/xdvik/browser.h
@@ -0,0 +1,29 @@
+/* public interface for launching a browser to retrieve remote documents.
+ * Copyright(C) 2002-2004 the xdvik development team.
+ */
+/*
+ * 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.
+*/
+
+#ifndef BROWSER_H_
+#define BROWSER_H_
+
+extern void launch_browser(const char *filename);
+
+#endif /* BROWSER_H_ */
diff --git a/Build/source/texk/xdvik/c-auto.in b/Build/source/texk/xdvik/c-auto.in
new file mode 100644
index 00000000000..dc4e0669407
--- /dev/null
+++ b/Build/source/texk/xdvik/c-auto.in
@@ -0,0 +1,460 @@
+/* c-auto.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the ANSI # stringizing operator in cpp. */
+#undef HAVE_STRINGIZE
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the ANSI # stringizing operator in cpp. */
+#undef HAVE_STRINGIZE
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the ANSI # stringizing operator in cpp. */
+#undef HAVE_STRINGIZE
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* c-auto.in. Generated from configure.in by autoheader. */
+/* Define to determine the integer type to be used in bitmaps. The type used
+ will be "unsigned BMTYPE". */
+#define BMTYPE int
+
+/* Define to the length (in bytes) of the above type. */
+#define BMBYTES 4
+
+/* Define if your system has STREAMS (and if X uses it). */
+#undef HAVE_STREAMS
+
+/* Define if you are using SunOS 4.x. */
+#undef SUNOS4
+
+/* Define if you are using Linux 2.1.xxx -- 2.2.8,
+ or if you find it necessary. */
+#undef FLAKY_SIGPOLL
+
+/* Define if your system has <poll.h> and poll(). */
+#undef HAVE_POLL
+
+/* Define to use the Xaw toolkit. */
+#undef XAW
+
+/* Define to use the Motif toolkit. */
+#undef MOTIF
+
+/* Define to enable greyscale anti-aliasing for shrunken bitmaps. */
+#undef GREY
+
+/* Define to enable support for color specials. */
+#undef COLOR
+
+/* Define to enable gf format files (in addition to pk format). */
+#undef USE_GF
+
+/* Define to use A4 as the default paper size. */
+#undef A4
+
+/* Define to use ImageMagick */
+#undef MAGICK
+
+/* ??? */
+#undef LDT1LIB
+
+/* Define to compile in t1lib */
+#undef T1LIB
+
+/* Define to compile in t1lib */
+#undef T1LIB
+
+/* Define if your C compiler can do string concatenation */
+#undef HAVE_CC_CONCAT
+
+/* Define if the memicmp() function is in <string.h> */
+#undef HAVE_MEMICMP
+
+/* Define to point to the default command to use for printing (optional). */
+#undef DEFAULT_DVIPS_PATH
+
+/* Define to point to the default command to use for printing (optional). */
+#undef DEFAULT_PS2PDF_PATH
+
+/* Define if you have an old version of the Xaw library */
+#undef HAVE_OLD_XAW
+
+/* Define if you want to use the Xpm library */
+#undef USE_XPM
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* Define to 1 if cpp supports the ANSI # stringizing operator. */
+#undef HAVE_STRINGIZE
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#undef uint32_t
+
+/* Define if the vsnprintf function works. */
+#undef HAVE_GOOD_VSNPRINTF
+
+/* Define if your system allows setsid() within vfork(). */
+#undef HAVE_GOOD_SETSID_VFORK
+
+/* Define if your system allows multiple definitions of functions. */
+#undef LD_ALLOWS_MULTIPLE_DEFINITIONS
+
+/* Define if you have the <X11/xpm.h> header file. */
+#undef HAVE_X11_XPM_H
+
+/* Define if you have the <xpm.h> header file (not in X11, e.g. Solaris 5.8). */
+#undef HAVE_XPM_H
+
+/* Define if you have the <iconv.h> header file. */
+#undef HAVE_ICONV_H
+
+/* Define if you have the iconv function. */
+#undef HAVE_ICONV
+
+/* Define the type of the iconv input string (char ** or const char **) */
+#undef ICONV_CHAR_PPTR_TYPE
+
+/* Define if the CODESET argument to nl_langinfo works. */
+#undef HAVE_WORKING_NL_LANGINFO_CODESET
+
+/* Define to use Xaw panner. */
+#undef USE_XAW_PANNER
+
+/* Define if you have the fchdir function. */
+#undef HAVE_FCHDIR
+
+/* Define if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getcwd function. */
+#undef HAVE_GETCWD
+
+/* Define if you have the getpwnam function. */
+#undef HAVE_GETPWNAM
+
+/* Define if you have the getpwuid function. */
+#undef HAVE_GETPWUID
+
+/* Define if you have the getuid function. */
+#undef HAVE_GETUID
+
+/* Define if you have the iconv function. */
+#undef HAVE_ICONV
+
+/* Define if you have the isinf function. */
+#undef HAVE_ISINF
+
+/* Define if you have the lstat function. */
+#undef HAVE_LSTAT
+
+/* Define if you have the memcpy function. */
+#undef HAVE_MEMCPY
+
+/* Define if you have the mkstemp function. */
+#undef HAVE_MKSTEMP
+
+/* Define if you have the nl_langinfo function. */
+#undef HAVE_NL_LANGINFO
+
+/* Define if you have the realpath function. */
+#undef HAVE_REALPATH
+
+/* Define if you have the setenv function. */
+#undef HAVE_SETENV
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the snprintf function. */
+#undef HAVE_SNPRINTF
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the ulltostr function. */
+#undef HAVE_ULLTOSTR
+
+/* Define if you have the vsnprintf function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if you have the waitpid function. */
+#undef HAVE_WAITPID
+
+/* Define if you have the <X11/Xmu/Editres.h> header file. */
+#undef HAVE_X11_XMU_EDITRES_H
+
+/* Define if you have the <X11/Xmu/Xmu.h> header file. */
+#undef HAVE_X11_XMU_XMU_H
+
+/* Define if you have the <X11/Xosdefs.h> header file. */
+#undef HAVE_X11_XOSDEFS_H
+
+/* Define if you have the <X11/xpm.h> header file. */
+#undef HAVE_X11_XPM_H
+
+/* Define if you have the <Xm/XpmP.h> header file. */
+#undef HAVE_XM_XPMP_H
+
+/* Define if you have the <iconv.h> header file. */
+#undef HAVE_ICONV_H
+
+/* Define if you have the <ieeefp.h> header file. */
+#undef HAVE_IEEEFP_H
+
+/* Define if you have the <langinfo.h> header file. */
+#undef HAVE_LANGINFO_H
+
+/* Define if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <regex.h> header file. */
+#undef HAVE_REGEX_H
+
+/* Define if you have the <select.h> header file. */
+#undef HAVE_SELECT_H
+
+/* Define if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define if you have the <sys/bsdtypes.h> header file. */
+#undef HAVE_SYS_BSDTYPES_H
+
+/* Define if you have the <sys/fcntl.h> header file. */
+#undef HAVE_SYS_FCNTL_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the m library (-lm). */
+#undef HAVE_LIBM
diff --git a/Build/source/texk/xdvik/c-openmx.h b/Build/source/texk/xdvik/c-openmx.h
new file mode 100644
index 00000000000..1a3560fa6bb
--- /dev/null
+++ b/Build/source/texk/xdvik/c-openmx.h
@@ -0,0 +1,37 @@
+/* c-openmx.h: define OPEN_MAX, the maximum number of open files a
+ process can have. Possibly dynamically determined.
+
+Copyright (C) 1993 Karl Berry.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef C_OPENMX_H_
+#define C_OPENMX_H_
+
+#include "kpathsea/c-limits.h"
+
+#ifndef OPEN_MAX
+#ifdef _SC_OPEN_MAX
+#define OPEN_MAX sysconf (_SC_OPEN_MAX)
+#else /* no SC_OPEN_MAX */
+#ifdef NOFILE
+#define OPEN_MAX NOFILE
+#else /* no NOFILE */
+#define OPEN_MAX 24 /* The POSIX minimum. */
+#endif /* no NOFILE */
+#endif /* no _SC_OPEN_MAX */
+#endif /* no OPEN_MAX */
+
+#endif /* not C_OPENMX_H_ */
diff --git a/Build/source/texk/xdvik/configure b/Build/source/texk/xdvik/configure
new file mode 100755
index 00000000000..5c14e55ddb5
--- /dev/null
+++ b/Build/source/texk/xdvik/configure
@@ -0,0 +1,6703 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer"
+ac_help="$ac_help
+ --without-mktexmf-default do not run mktexmf if MF source missing"
+ac_help="$ac_help
+ --without-mktexpk-default do not run mktexpk if PK font missing"
+ac_help="$ac_help
+ --without-mktextfm-default do not run mktextfm if TFM file missing"
+ac_help="$ac_help
+ --without-mkocp-default do not run mkocp if OCP file missing"
+ac_help="$ac_help
+ --without-mkofm-default do not run mkofm if OFM file missing"
+ac_help="$ac_help
+ --with-mktexfmt-default run mktexfmt if format file missing"
+ac_help="$ac_help
+ --with-mktextex-default run mktextex if TeX source missing"
+ac_help="$ac_help
+ --with-x use the X Window System"
+ac_help="$ac_help
+ --enable-compiler-warnings=[no/minimum/yes/maximum]
+ Turn on compiler warnings"
+ac_help="$ac_help
+ --with-x-toolkit=KIT OBSOLETE: use --with-mf-x-toolkit and/or
+ --with-xdvi-x-toolkit instead."
+ac_help="$ac_help
+ --with-ps=PS Use PostScript (PS=no/yes/gs/dps/news, default gs)"
+ac_help="$ac_help
+ --disable-grey Disable greyscale anti-aliasing for shrunken bitmaps
+"
+ac_help="$ac_help
+ --disable-color Disable support for color specials"
+ac_help="$ac_help
+ --disable-t1lib Do not use T1lib (direct rendering of Type1 fonts)"
+ac_help="$ac_help
+ --enable-gf Enable gf format pixel files (in addition to pk)"
+ac_help="$ac_help
+ --disable-a4 Set default paper size to letter and default unit to inch"
+ac_help="$ac_help
+ --enable-magick Use ImageMagick to load/render image files.
+ EXPERIMENTAL - DO NOT USE!"
+ac_help="$ac_help
+ --with-xdvi-x-toolkit=KIT
+ Use toolkit KIT for xdvi (KIT=motif/xaw/xaw3d/neXtaw).
+ If no --with-xdvi-x-toolkit option is used, use Motif
+ if available, else Xaw."
+ac_help="$ac_help
+ --with-system-t1lib Use installed T1lib"
+ac_help="$ac_help
+ --with-t1lib-libdir=DIR
+ Specify the location of T1lib library files (libt1.a)"
+ac_help="$ac_help
+ --with-t1lib-include=DIR
+ Specify the location of T1lib header files"
+ac_help="$ac_help
+ --without-xpm Do not use the Xpm library (will disable the toolbar)"
+ac_help="$ac_help
+ --with-xpm-include=DIR
+ Specify the location of Xpm include files"
+ac_help="$ac_help
+ --with-xpm-libdir=DIR
+ Specify the location of Xpm libraries"
+ac_help="$ac_help
+ --with-motif-include=DIR
+ Specify the location of Motif include files"
+ac_help="$ac_help
+ --with-motif-libdir=DIR
+ Specify the location of Motif libraries"
+ac_help="$ac_help
+ --with-iconv-libdir=DIR
+ Specify the location of iconv library (librecode.so)"
+ac_help="$ac_help
+ --with-iconv-include=DIR
+ Specify the location of iconv header (iconv.h)"
+ac_help="$ac_help
+ --with-default-dvips-path=CMD
+ Use CMD as default DVI to PS converter"
+ac_help="$ac_help
+ --with-default-ps2pdf-path=CMD
+ Use CMD as default PS to PDF converter"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+ac_config_files=
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_envvar| sed 's/[_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: invalid variable name: $ac_envvar" 1>&2; exit 1; }
+ fi
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=xdvi.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:623: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test $ac_x $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:654: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test $ac_x $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:706: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test $ac_x $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:739: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 750 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:755: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:781: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:786: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:795: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:814: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ case $ac_dir in
+ /*|[A-z]:/*) ac_aux_dir=$ac_dir;;
+ *) ac_aux_dir=`pwd`/$ac_dir;;
+ esac
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ case $ac_dir in
+ /*|[A-z]:/*) ac_aux_dir=$ac_dir;;
+ *) ac_aux_dir=`pwd`/$ac_dir;;
+ esac
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:882: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ # Hack for MSDOS and descendants.
+ if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test $ac_x $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:937: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:964: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ rm -f conftestdata
+# MS-DOS is a special case, because it sort of pretends that ln -s
+# works for executables.
+if test -z "$COMSPEC" && ln -s X conftestdata 2>/dev/null
+then
+ rm -f conftestdata
+ ac_cv_prog_LN_S="ln -s"
+else
+ ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:989: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test $ac_x $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+
+echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
+echo "configure:1040: checking whether to enable maintainer-specific portions of Makefiles" >&5
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6
+ if test "x$USE_MAINTAINER_MODE" = xyes; then
+ MAINT=
+ else
+ MAINT='#M#'
+ fi
+
+
+
+echo $ac_n "checking for loader (symbol LD)""... $ac_c" 1>&6
+echo "configure:1059: checking for loader (symbol LD)" >&5
+if eval "test \"`echo '$''{'cf_cv_subst_LD'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+test -z "$LD" && LD=ld
+cf_cv_subst_LD=$LD
+fi
+
+LD=${cf_cv_subst_LD}
+echo "$ac_t""$LD" 1>&6
+
+
+echo $ac_n "checking for archiver (symbol AR)""... $ac_c" 1>&6
+echo "configure:1073: checking for archiver (symbol AR)" >&5
+if eval "test \"`echo '$''{'cf_cv_subst_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+test -z "$AR" && AR=ar
+cf_cv_subst_AR=$AR
+fi
+
+AR=${cf_cv_subst_AR}
+echo "$ac_t""$AR" 1>&6
+
+
+echo $ac_n "checking for archiver options (symbol ARFLAGS)""... $ac_c" 1>&6
+echo "configure:1087: checking for archiver options (symbol ARFLAGS)" >&5
+if eval "test \"`echo '$''{'cf_cv_subst_ARFLAGS'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+test -z "$ARFLAGS" && ARFLAGS=rc
+cf_cv_subst_ARFLAGS=$ARFLAGS
+fi
+
+ARFLAGS=${cf_cv_subst_ARFLAGS}
+echo "$ac_t""$ARFLAGS" 1>&6
+
+
+
+# Check whether --with-mktexmf-default or --without-mktexmf-default was given.
+if test "${with_mktexmf_default+set}" = set; then
+ withval="$with_mktexmf_default"
+ :
+else
+ with_mktexmf_default=yes
+fi
+
+# Check whether --with-mktexpk-default or --without-mktexpk-default was given.
+if test "${with_mktexpk_default+set}" = set; then
+ withval="$with_mktexpk_default"
+ :
+else
+ with_mktexpk_default=yes
+fi
+
+# Check whether --with-mktextfm-default or --without-mktextfm-default was given.
+if test "${with_mktextfm_default+set}" = set; then
+ withval="$with_mktextfm_default"
+ :
+else
+ with_mktextfm_default=yes
+fi
+
+# Check whether --with-mkocp-default or --without-mkocp-default was given.
+if test "${with_mkocp_default+set}" = set; then
+ withval="$with_mkocp_default"
+ :
+else
+ with_mkocp_default=yes
+fi
+
+# Check whether --with-mkofm-default or --without-mkofm-default was given.
+if test "${with_mkofm_default+set}" = set; then
+ withval="$with_mkofm_default"
+ :
+else
+ with_mkofm_default=yes
+fi
+
+# Check whether --with-mktexfmt-default or --without-mktexfmt-default was given.
+if test "${with_mktexfmt_default+set}" = set; then
+ withval="$with_mktexfmt_default"
+ :
+fi
+
+# Check whether --with-mktextex-default or --without-mktextex-default was given.
+if test "${with_mktextex_default+set}" = set; then
+ withval="$with_mktextex_default"
+ with_mktextex_default=yes
+else
+ with_mktextex_default=no
+fi
+
+
+echo $ac_n "checking where the main texmf tree is located""... $ac_c" 1>&6
+echo "configure:1157: checking where the main texmf tree is located" >&5
+texmfmain=
+if test "x$datadir" != 'x${prefix}/share'; then
+ # First case, datadir is defined...
+ eval p=\"$datadir\"
+ # Unconditionally set the directory, but...
+ texmfmain=`echo "$p/texmf" | sed 's,//*,/,g'`
+ # ... do complain if it wasn't found.
+ if test -d "$texmfmain"; then
+ echo "$ac_t"""$texmfmain"" 1>&6
+ else
+ echo "$ac_t""not found" 1>&6
+ echo "configure: warning: No texmf tree found at $texmfmain.
+ *****************************************************************
+ * Error: The main texmf tree was not found. *
+ * If you do not have the files, you should be able to them from *
+ * the same place you got these sources from, or from one of the *
+ * CTAN hosts. *
+ *****************************************************************
+ Winging it." 1>&2
+ fi
+else
+ # Second case, datadir is default...
+ if test "x$prefix" = "xNONE"; then
+ p="$ac_default_prefix"
+ else
+ eval p=\"$prefix\"
+ fi
+ for e in share/texmf lib/texmf texmf; do
+ if test -d "$p/$e"; then
+ texmfmain='${prefix}'/"$e"
+ break
+ fi
+ done
+ if test -z "$texmfmain" && test "x$prefix" = "xNONE"; then
+ # Still no texmfmain found, no prefix set, perhaps kpsewhich is
+ # installed and can help us out.
+ texmfmain=`kpsewhich --expand-path='$TEXMFMAIN'` 2>/dev/null
+ fi
+ texmfmain=`echo "$texmfmain" | sed 's,//*,/,g'`
+ if test -n "$texmfmain"; then
+ echo "$ac_t"""$texmfmain"" 1>&6
+ else
+ eval texmfmain="$datadir/texmf"
+ echo "$ac_t""not found" 1>&6
+ echo "configure: warning: The main texmf tree was not found at $texmfmain.
+ *****************************************************************
+ * Error: The main texmf tree was not found. *
+ * Use the --datadir option to specify its parent directory. *
+ * If you do not have the files, you should be able to them from *
+ * the same place you got these sources from, or from one of the *
+ * CTAN hosts. *
+ *****************************************************************
+ Winging it by pretending $texmfmain is correct." 1>&2
+ fi
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1217: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1232 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1238: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1249 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1255: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1266 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1272: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1297: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1302 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1310: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1327 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1345 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1366 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1377: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1401: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1406 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for vfork.h""... $ac_c" 1>&6
+echo "configure:1438: checking for vfork.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1443 "configure"
+#include "confdefs.h"
+#include <vfork.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1448: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_VFORK_H 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for working vfork""... $ac_c" 1>&6
+echo "configure:1473: checking for working vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo $ac_n "checking for vfork""... $ac_c" 1>&6
+echo "configure:1479: checking for vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1484 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vfork(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vfork();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vfork) || defined (__stub___vfork)
+choke me
+#else
+vfork();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1507: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_vfork=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_vfork=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1529 "configure"
+#include "confdefs.h"
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+ argument registers are propagated back to the parent.
+ The compiler is told about this with #include <vfork.h>,
+ but some compilers (e.g. gcc -O) don't grok <vfork.h>.
+ Test for this by using a static variable whose address
+ is put into a register that is clobbered by the vfork. */
+static
+#ifdef __cplusplus
+sparc_address_test (int arg)
+#else
+sparc_address_test (arg) int arg;
+#endif
+{
+ static pid_t child;
+ if (!child) {
+ child = vfork ();
+ if (child < 0) {
+ perror ("vfork");
+ _exit(2);
+ }
+ if (!child) {
+ arg = getpid();
+ write(-1, "", 0);
+ _exit (arg);
+ }
+ }
+}
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ sparc_address_test ();
+
+ child = vfork ();
+
+ if (child == 0) {
+ /* Here is another test for sparc vfork register problems.
+ This test uses lots of local variables, at least
+ as many local variables as main has allocated so far
+ including compiler temporaries. 4 locals are enough for
+ gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe.
+ A buggy compiler should reuse the register of parent
+ for one of the local variables, since it will think that
+ parent can't possibly be used any more in this routine.
+ Assigning to the local variable will thus munge parent
+ in the parent process. */
+ pid_t
+ p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+ p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+ /* Convince the compiler that p..p7 are live; otherwise, it might
+ use the same hardware register for all 8 local variables. */
+ if (p != p1 || p != p2 || p != p3 || p != p4
+ || p != p5 || p != p6 || p != p7)
+ _exit(1);
+
+ /* On some systems (e.g. IRIX 3.3),
+ vfork doesn't separate parent from child file descriptors.
+ If the child closes a descriptor before it execs or exits,
+ this munges the parent's descriptor as well.
+ Test for this by closing stdout in the child. */
+ _exit(close(fileno(stdout)) != 0);
+ } else {
+ int status;
+ struct stat st;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+
+ /* Did the vfork/compiler bug occur? */
+ || parent != getpid()
+
+ /* Did the file descriptor bug occur? */
+ || fstat(fileno(stdout), &st) != 0
+ );
+ }
+}
+EOF
+if { (eval echo configure:1624: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_vfork_works=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_vfork_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_vfork_works" 1>&6
+if test $ac_cv_func_vfork_works = no; then
+ cat >> confdefs.h <<\EOF
+#define vfork fork
+EOF
+
+fi
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:1647: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1652 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vprintf(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:1699: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1704 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char _doprnt(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for a working implementation of (v)snprintf()""... $ac_c" 1>&6
+echo "configure:1752: checking for a working implementation of (v)snprintf()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_func_good_vsnprintf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ # safe value for cross-compiling
+xdvi_cv_func_good_vsnprintf=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1761 "configure"
+#include "confdefs.h"
+
+#ifdef IRIX
+#define _XOPEN_SOURCE 500
+#endif
+#include <stdio.h>
+int main()
+{
+ char s[2];
+ int retval = snprintf(s, 2, "test");
+ if (retval > -1 && retval != 4) /* neither negative nor desired size, not OK */
+ return 1;
+ return 0;
+}
+EOF
+if { (eval echo configure:1777: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_cv_func_good_vsnprintf=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ xdvi_cv_func_good_vsnprintf=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$xdvi_cv_func_good_vsnprintf" 1>&6
+if test $xdvi_cv_func_good_vsnprintf = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GOOD_VSNPRINTF 1
+EOF
+
+fi
+echo $ac_n "checking for memicmp""... $ac_c" 1>&6
+echo "configure:1799: checking for memicmp" >&5
+if eval "test \"`echo '$''{'xdvi_cv_memicmp'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1804 "configure"
+#include "confdefs.h"
+#include <string.h>
+
+int main() {
+(void)memicmp((char *)NULL, (char *)NULL, 0);
+; return 0; }
+EOF
+if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_cv_memicmp=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cv_memicmp=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cv_memicmp" 1>&6
+if test $xdvi_cv_memicmp = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_MEMICMP 1
+EOF
+
+fi
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:1834: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1839 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:1846: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_header_alloca_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:1867: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1872 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:1900: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_alloca_works=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.${ac_objext}
+ cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:1932: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1937 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "webecray" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_os_cray=yes
+else
+ rm -rf conftest*
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+ echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1962: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1967 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+ break
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2017: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2025 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+ exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2044: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_stack_direction=1
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+
+
+echo $ac_n "checking for preprocessor stringizing operator""... $ac_c" 1>&6
+echo "configure:2068: checking for preprocessor stringizing operator" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stringize'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2073 "configure"
+#include "confdefs.h"
+
+#define x(y) #y
+
+char *s = x(teststring);
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "#teststring" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_c_stringize=no
+else
+ rm -rf conftest*
+ ac_cv_c_stringize=yes
+fi
+rm -f conftest*
+
+fi
+
+if test "${ac_cv_c_stringize}" = yes
+then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STRINGIZE 1
+EOF
+
+fi
+echo "$ac_t""${ac_cv_c_stringize}" 1>&6
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:2103: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_func_memcmp_clean=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2111 "configure"
+#include "confdefs.h"
+
+main()
+{
+ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+ exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:2121: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_memcmp_clean=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
+test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:2139: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2144 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:2160: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2181: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2186 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2203: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:2222: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 2229 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2240: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 2244 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2255: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_bigendian=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2275 "configure"
+#include "confdefs.h"
+main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+if { (eval echo configure:2288: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_bigendian=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+ cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+# If we find X, set shell vars x_includes and x_libraries to the
+# paths, otherwise set no_x=yes.
+# Uses ac_ vars as temps to allow command line to override cache and checks.
+# --without-x overrides everything else, but does not touch the cache.
+echo $ac_n "checking for X""... $ac_c" 1>&6
+echo "configure:2316: checking for X" >&5
+
+# Check whether --with-x or --without-x was given.
+if test "${with_x+set}" = set; then
+ withval="$with_x"
+ :
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then
+ # Both variables are already set.
+ have_x=yes
+ else
+if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=NO ac_x_libraries=NO
+rm -fr conftestdir
+if mkdir conftestdir; then
+ cd conftestdir
+ # Make sure to not put "make" in the Imakefile rules, since we grep it out.
+ cat > Imakefile <<'EOF'
+acfindx:
+ @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"'
+EOF
+ if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+ eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl; do
+ if test ! -f $ac_im_usrlibdir/libX11.$ac_extension &&
+ test -f $ac_im_libdir/libX11.$ac_extension; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case "$ac_im_incroot" in
+ /usr/include) ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;;
+ esac
+ case "$ac_im_usrlibdir" in
+ /usr/lib | /lib) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;;
+ esac
+ fi
+ cd ..
+ rm -fr conftestdir
+fi
+
+if test "$ac_x_includes" = NO; then
+ # Guess where to find include files, by looking for this one X11 .h file.
+ test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h
+
+ # First, try using that file with no special directory specified.
+cat > conftest.$ac_ext <<EOF
+#line 2378 "configure"
+#include "confdefs.h"
+#include <$x_direct_test_include>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2383: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ # Look for the header file in a standard set of common directories.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ for ac_dir in \
+ /usr/X11/include \
+ /usr/X11R6/include \
+ /usr/X11R5/include \
+ /usr/X11R4/include \
+ \
+ /usr/include/X11 \
+ /usr/include/X11R6 \
+ /usr/include/X11R5 \
+ /usr/include/X11R4 \
+ \
+ /usr/local/X11/include \
+ /usr/local/X11R6/include \
+ /usr/local/X11R5/include \
+ /usr/local/X11R4/include \
+ \
+ /usr/local/include/X11 \
+ /usr/local/include/X11R6 \
+ /usr/local/include/X11R5 \
+ /usr/local/include/X11R4 \
+ \
+ /usr/X386/include \
+ /usr/x386/include \
+ /usr/XFree86/include/X11 \
+ \
+ /usr/include \
+ /usr/local/include \
+ /usr/unsupported/include \
+ /usr/athena/include \
+ /usr/local/x11r5/include \
+ /usr/lpp/Xamples/include \
+ \
+ /usr/openwin/include \
+ /usr/openwin/share/include \
+ ; \
+ do
+ if test -r "$ac_dir/$x_direct_test_include"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+ done
+fi
+rm -f conftest*
+fi # $ac_x_includes = NO
+
+if test "$ac_x_libraries" = NO; then
+ # Check for the libraries.
+
+ test -z "$x_direct_test_library" && x_direct_test_library=Xt
+ test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc
+ test -z "$x_direct_test_arguments" && x_direct_test_arguments=1
+
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS="$LIBS"
+ LIBS="-l$x_direct_test_library $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2453 "configure"
+#include "confdefs.h"
+#include <${x_direct_test_include}>
+int main() {
+${x_direct_test_function}(${x_direct_test_arguments})
+; return 0; }
+EOF
+if { (eval echo configure:2460: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ LIBS="$ac_save_LIBS"
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$ac_save_LIBS"
+# First see if replacing the include by lib works.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \
+ /usr/X11/lib \
+ /usr/X11R6/lib \
+ /usr/X11R5/lib \
+ /usr/X11R4/lib \
+ \
+ /usr/lib/X11 \
+ /usr/lib/X11R6 \
+ /usr/lib/X11R5 \
+ /usr/lib/X11R4 \
+ \
+ /usr/local/X11/lib \
+ /usr/local/X11R6/lib \
+ /usr/local/X11R5/lib \
+ /usr/local/X11R4/lib \
+ \
+ /usr/local/lib/X11 \
+ /usr/local/lib/X11R6 \
+ /usr/local/lib/X11R5 \
+ /usr/local/lib/X11R4 \
+ \
+ /usr/X386/lib \
+ /usr/x386/lib \
+ /usr/XFree86/lib/X11 \
+ \
+ /usr/lib \
+ /usr/local/lib \
+ /usr/unsupported/lib \
+ /usr/athena/lib \
+ /usr/local/x11r5/lib \
+ /usr/lpp/Xamples/lib \
+ /lib/usr/lib/X11 \
+ \
+ /usr/openwin/lib \
+ /usr/openwin/share/lib \
+ ; \
+do
+ for ac_extension in a so sl; do
+ if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f conftest*
+fi # $ac_x_libraries = NO
+
+if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then
+ # Didn't find X anywhere. Cache the known absence of X.
+ ac_cv_have_x="have_x=no"
+else
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes \
+ ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries"
+fi
+fi
+ fi
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ echo "$ac_t""$have_x" 1>&6
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes \
+ ac_x_includes=$x_includes ac_x_libraries=$x_libraries"
+ echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6
+fi
+
+if test "$no_x" = yes; then
+ # Not all programs may use this symbol, but it does not hurt to define it.
+ cat >> confdefs.h <<\EOF
+#define X_DISPLAY_MISSING 1
+EOF
+
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ # It would also be nice to do this for all -L options, not just this one.
+ if test -n "$x_libraries"; then
+ X_LIBS="$X_LIBS -L$x_libraries"
+ # For Solaris; some versions of Sun CC require a space after -R and
+ # others require no space. Words are not sufficient . . . .
+ case "`(uname -sr) 2>/dev/null`" in
+ "SunOS 5"*)
+ echo $ac_n "checking whether -R must be followed by a space""... $ac_c" 1>&6
+echo "configure:2566: checking whether -R must be followed by a space" >&5
+ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS -R$x_libraries"
+ cat > conftest.$ac_ext <<EOF
+#line 2569 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:2576: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_R_nospace=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_R_nospace=no
+fi
+rm -f conftest*
+ if test $ac_R_nospace = yes; then
+ echo "$ac_t""no" 1>&6
+ X_LIBS="$X_LIBS -R$x_libraries"
+ else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ cat > conftest.$ac_ext <<EOF
+#line 2592 "configure"
+#include "confdefs.h"
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:2599: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_R_space=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_R_space=no
+fi
+rm -f conftest*
+ if test $ac_R_space = yes; then
+ echo "$ac_t""yes" 1>&6
+ X_LIBS="$X_LIBS -R $x_libraries"
+ else
+ echo "$ac_t""neither works" 1>&6
+ fi
+ fi
+ LIBS="$ac_xsave_LIBS"
+ ;;
+ OSF1*|IRIX*)
+ # OSF1 refers to Dec-Unix. -rpath is required in du 4.0 - at least
+ # -rpath is required in irix 5.x and 6.x - at least
+ # (Is -rpath really needed in IRIX? OJM)
+ X_LIBS="$X_LIBS -Wl,-rpath,$x_libraries"
+ ;;
+ esac
+ fi
+
+ # Check for system-dependent libraries X programs must link with.
+ # Do this before checking for the system-independent R6 libraries
+ # (-lICE), since we may need -lsocket or whatever for X linking.
+
+ if test "$ISC" = yes; then
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+ else
+ # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X
+ # libraries were built with DECnet support. And karl@cs.umb.edu says
+ # the Alpha needs dnet_stub (dnet does not exist).
+ echo $ac_n "checking for dnet_ntoa in -ldnet""... $ac_c" 1>&6
+echo "configure:2638: checking for dnet_ntoa in -ldnet" >&5
+ac_lib_var=`echo dnet'_'dnet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldnet $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2646 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dnet_ntoa();
+
+int main() {
+dnet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:2657: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+ echo $ac_n "checking for dnet_ntoa in -ldnet_stub""... $ac_c" 1>&6
+echo "configure:2679: checking for dnet_ntoa in -ldnet_stub" >&5
+ac_lib_var=`echo dnet_stub'_'dnet_ntoa | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldnet_stub $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2687 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dnet_ntoa();
+
+int main() {
+dnet_ntoa()
+; return 0; }
+EOF
+if { (eval echo configure:2698: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+ # to get the SysV transport functions.
+ # chad@anasazi.com says the Pyramis MIS-ES running DC/OSx (SVR4)
+ # needs -lnsl.
+ # The nsl library prevents programs from opening the X display
+ # on Irix 5.2, according to dickey@clark.net.
+ echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6
+echo "configure:2727: checking for gethostbyname" >&5
+if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2732 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname) || defined (__stub___gethostbyname)
+choke me
+#else
+gethostbyname();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2755: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_gethostbyname=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'gethostbyname`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_gethostbyname = no; then
+ echo $ac_n "checking for gethostbyname in -lnsl""... $ac_c" 1>&6
+echo "configure:2776: checking for gethostbyname in -lnsl" >&5
+ac_lib_var=`echo nsl'_'gethostbyname | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2784 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname();
+
+int main() {
+gethostbyname()
+; return 0; }
+EOF
+if { (eval echo configure:2795: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # lieder@skyler.mavd.honeywell.com says without -lsocket,
+ # socket/setsockopt and other routines are undefined under SCO ODT
+ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
+ # on later versions), says simon@lia.di.epfl.ch: it contains
+ # gethostby* variants that don't use the nameserver (or something).
+ # -lsocket must be given before -lnsl if both are needed.
+ # We assume that if connect needs -lnsl, so does gethostbyname.
+ echo $ac_n "checking for connect""... $ac_c" 1>&6
+echo "configure:2825: checking for connect" >&5
+if eval "test \"`echo '$''{'ac_cv_func_connect'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2830 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char connect(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_connect) || defined (__stub___connect)
+choke me
+#else
+connect();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2853: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_connect=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_connect=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'connect`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_connect = no; then
+ echo $ac_n "checking for connect in -lsocket""... $ac_c" 1>&6
+echo "configure:2874: checking for connect in -lsocket" >&5
+ac_lib_var=`echo socket'_'connect | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2882 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char connect();
+
+int main() {
+connect()
+; return 0; }
+EOF
+if { (eval echo configure:2893: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # gomez@mi.uni-erlangen.de says -lposix is necessary on A/UX.
+ echo $ac_n "checking for remove""... $ac_c" 1>&6
+echo "configure:2917: checking for remove" >&5
+if eval "test \"`echo '$''{'ac_cv_func_remove'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2922 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char remove(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char remove();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_remove) || defined (__stub___remove)
+choke me
+#else
+remove();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2945: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_remove=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_remove=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'remove`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_remove = no; then
+ echo $ac_n "checking for remove in -lposix""... $ac_c" 1>&6
+echo "configure:2966: checking for remove in -lposix" >&5
+ac_lib_var=`echo posix'_'remove | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lposix $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2974 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char remove();
+
+int main() {
+remove()
+; return 0; }
+EOF
+if { (eval echo configure:2985: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+
+ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+ echo $ac_n "checking for shmat""... $ac_c" 1>&6
+echo "configure:3009: checking for shmat" >&5
+if eval "test \"`echo '$''{'ac_cv_func_shmat'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3014 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char shmat(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shmat();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_shmat) || defined (__stub___shmat)
+choke me
+#else
+shmat();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3037: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_shmat=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_shmat=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'shmat`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test $ac_cv_func_shmat = no; then
+ echo $ac_n "checking for shmat in -lipc""... $ac_c" 1>&6
+echo "configure:3058: checking for shmat in -lipc" >&5
+ac_lib_var=`echo ipc'_'shmat | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lipc $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3066 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shmat();
+
+int main() {
+shmat()
+; return 0; }
+EOF
+if { (eval echo configure:3077: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ fi
+ fi
+
+ # Check for libraries that X11R6 Xt/Xaw programs need.
+ ac_save_LDFLAGS="$LDFLAGS"
+ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+ # check for ICE first), but we must link in the order -lSM -lICE or
+ # we get undefined symbols. So assume we have SM if we have ICE.
+ # These have to be linked with before -lX11, unlike the other
+ # libraries we check for below, so use a different variable.
+ # --interran@uluru.Stanford.EDU, kb@cs.umb.edu.
+ echo $ac_n "checking for IceConnectionNumber in -lICE""... $ac_c" 1>&6
+echo "configure:3110: checking for IceConnectionNumber in -lICE" >&5
+ac_lib_var=`echo ICE'_'IceConnectionNumber | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3118 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char IceConnectionNumber();
+
+int main() {
+IceConnectionNumber()
+; return 0; }
+EOF
+if { (eval echo configure:3129: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ LDFLAGS="$ac_save_LDFLAGS"
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:3154: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3159 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+
+if test $ac_cv_func_vfork_works = yes; then
+echo $ac_n "checking for whether setsid() is allowed within vfork()""... $ac_c" 1>&6
+echo "configure:3192: checking for whether setsid() is allowed within vfork()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_setsid_in_vfork'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ # safe value for cross-compiling
+xdvi_cv_setsid_in_vfork=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3201 "configure"
+#include "confdefs.h"
+/* Test adapted from Gnu autoconf */
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+int
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ child = vfork ();
+
+ if (child == 0) {
+ if (setsid () == -1)
+ _exit(1);
+ _exit(0);
+ } else {
+ int status;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+ );
+ }
+}
+EOF
+if { (eval echo configure:3240: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_cv_setsid_in_vfork=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ xdvi_cv_setsid_in_vfork=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$xdvi_cv_setsid_in_vfork" 1>&6
+if test $xdvi_cv_setsid_in_vfork = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_GOOD_SETSID_VFORK 1
+EOF
+
+fi
+fi
+echo $ac_n "checking whether C compiler supports string concatenation""... $ac_c" 1>&6
+echo "configure:3263: checking whether C compiler supports string concatenation" >&5
+if eval "test \"`echo '$''{'xdvi_cc_concat'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3268 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+puts("Testing" " string" " concatenation");
+
+; return 0; }
+EOF
+if { (eval echo configure:3277: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ xdvi_cc_concat=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cc_concat=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cc_concat" 1>&6
+if test $xdvi_cc_concat = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_CC_CONCAT 1
+EOF
+
+fi
+echo $ac_n "checking for integer type to use in bitmaps""... $ac_c" 1>&6
+echo "configure:3297: checking for integer type to use in bitmaps" >&5
+if eval "test \"`echo '$''{'xdvi_cv_bitmap_type'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3305 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+ FILE *f=fopen("conftestval", "w");
+ if (!f) exit(1);
+ if ((sizeof(unsigned long) == 4 || sizeof(unsigned long) == 2)
+ && sizeof(unsigned long) != sizeof(unsigned int))
+ fprintf(f, "BMTYPE=long BMBYTES=%d\n", sizeof(unsigned long));
+ if (sizeof(unsigned int) == 4 || sizeof(unsigned int) == 2)
+ fprintf(f, "BMTYPE=int BMBYTES=%d\n", sizeof(unsigned int));
+ else if (sizeof(unsigned short) == 4 || sizeof(unsigned short) == 2)
+ fprintf(f, "BMTYPE=short BMBYTES=%d\n", sizeof(unsigned short));
+ else fprintf(f, "BMTYPE=char BMBYTES=%d\n", sizeof(unsigned char));
+ exit(0);
+}
+EOF
+if { (eval echo configure:3323: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_cv_bitmap_type="`cat conftestval`"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ { echo "configure: error: could not determine integer type for bitmap" 1>&2; exit 1; }
+fi
+rm -fr conftest*
+fi
+
+fi
+
+eval "$xdvi_cv_bitmap_type"
+cat >> confdefs.h <<EOF
+#define BMTYPE $BMTYPE
+EOF
+
+cat >> confdefs.h <<EOF
+#define BMBYTES $BMBYTES
+EOF
+
+echo "$ac_t""unsigned $BMTYPE, size = $BMBYTES" 1>&6
+echo $ac_n "checking for stropts.h and isastream()""... $ac_c" 1>&6
+echo "configure:3348: checking for stropts.h and isastream()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_sys_streams'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3353 "configure"
+#include "confdefs.h"
+#include <stropts.h>
+
+int main() {
+#ifndef I_SETSIG
+choke me
+#else
+isastream(0);
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:3365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_cv_sys_streams=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cv_sys_streams=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cv_sys_streams" 1>&6
+if test $xdvi_cv_sys_streams = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_STREAMS 1
+EOF
+
+fi
+echo $ac_n "checking for SunOS 4""... $ac_c" 1>&6
+echo "configure:3385: checking for SunOS 4" >&5
+if eval "test \"`echo '$''{'xdvi_cv_sys_sunos_4'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "`(uname -sr) 2>/dev/null`" in
+"SunOS 4."*)
+ xdvi_cv_sys_sunos_4=yes ;;
+*) xdvi_cv_sys_sunos_4=no ;;
+esac
+fi
+
+echo "$ac_t""$xdvi_cv_sys_sunos_4" 1>&6
+if test $xdvi_cv_sys_sunos_4 = yes; then
+ cat >> confdefs.h <<\EOF
+#define SUNOS4 1
+EOF
+
+fi
+echo $ac_n "checking for certain old versions of Linux""... $ac_c" 1>&6
+echo "configure:3404: checking for certain old versions of Linux" >&5
+if eval "test \"`echo '$''{'xdvi_cv_sys_old_linux'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "`(uname -sr) 2>/dev/null`" in
+"Linux 2."[01].* | "Linux 2.2."[0-8] | "Linux 2.2."[0-8]-*)
+ xdvi_cv_sys_old_linux=yes ;;
+*) xdvi_cv_sys_old_linux=no ;;
+esac
+fi
+
+echo "$ac_t""$xdvi_cv_sys_old_linux" 1>&6
+if test $xdvi_cv_sys_old_linux = yes; then
+ cat >> confdefs.h <<\EOF
+#define FLAKY_SIGPOLL 1
+EOF
+
+fi
+echo $ac_n "checking for poll.h and poll()""... $ac_c" 1>&6
+echo "configure:3423: checking for poll.h and poll()" >&5
+if eval "test \"`echo '$''{'xdvi_cv_func_poll'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3428 "configure"
+#include "confdefs.h"
+#include <poll.h>
+
+int main() {
+poll((struct pollfd *) 0, 0, 0);
+; return 0; }
+EOF
+if { (eval echo configure:3436: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_cv_func_poll=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_cv_func_poll=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$xdvi_cv_func_poll" 1>&6
+if test $xdvi_cv_func_poll = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_POLL 1
+EOF
+
+else
+ for ac_hdr in sys/select.h select.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3459: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3464 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3469: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+
+ # Check whether --enable-compiler-warnings or --disable-compiler-warnings was given.
+if test "${enable_compiler_warnings+set}" = set; then
+ enableval="$enable_compiler_warnings"
+ :
+else
+ enable_compiler_warnings=minimum
+fi
+
+
+ echo $ac_n "checking what warning flags to pass to the C compiler""... $ac_c" 1>&6
+echo "configure:3508: checking what warning flags to pass to the C compiler" >&5
+ warnCFLAGS=
+ if test "x$GCC" != xyes; then
+ enable_compiler_warnings=no
+ fi
+
+ if test "x$enable_compiler_warnings" != "xno"; then
+ if test "x$GCC" = "xyes"; then
+ case " $CFLAGS " in
+ *\ \ -Wall\ \ *) ;;
+ *) warnCFLAGS="-W -Wall -Wunused" ;;
+ esac
+
+ ## -W is not all that useful. And it cannot be controlled
+ ## with individual -Wno-xxx flags, unlike -Wall
+ if test "x$enable_compiler_warnings" = "xyes"; then
+ warnCFLAGS="$warnCFLAGS -pedantic -Wmissing-prototypes -Wmissing-declarations"
+ elif test "x$enable_compiler_warnings" = "xmaximum"; then
+ ## just turn on about everything:
+ warnCFLAGS="-Wall -Wunused -Wmissing-prototypes -Wmissing-declarations -Wimplicit -Wparentheses -Wreturn-type -Wswitch -Wtrigraphs -Wunused -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
+ fi
+ fi
+ fi
+ echo "$ac_t""$warnCFLAGS" 1>&6
+
+ ### FIXME: if we restrict setting the flags to this case only, they will get overridden
+ ### somehwere else further up in the configure process.
+ if test "x$cflags_set" != "xyes"; then
+ XTRA_WARN_CFLAGS=$warnCFLAGS
+
+# CFLAGS="$CFLAGS $warnCFLAGS"
+ cflags_set=yes
+
+ fi
+
+
+echo $ac_n "checking whether linker supports the --allow-multiple-definition flag""... $ac_c" 1>&6
+echo "configure:3545: checking whether linker supports the --allow-multiple-definition flag" >&5
+if eval "test \"`echo '$''{'xdvi_linker_multiple_defns'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ xdvi_save_LDFLAGS="$LDFLAGS"
+LDFLAGS="-Xlinker --allow-multiple-definition"
+x_linker_options=""
+cat > conftest.$ac_ext <<EOF
+#line 3553 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+void foo(void);
+
+; return 0; }
+EOF
+if { (eval echo configure:3562: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_linker_multiple_defns=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_linker_multiple_defns=no
+
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$xdvi_linker_multiple_defns" 1>&6
+if test $xdvi_linker_multiple_defns = yes; then
+ x_linker_options="-Xlinker --allow-multiple-definition"
+ LDFLAGS="$xdvi_save_LDFLAGS"
+ cat >> confdefs.h <<\EOF
+#define LD_ALLOWS_MULTIPLE_DEFINITIONS 1
+EOF
+
+else
+ LDFLAGS="$xdvi_save_LDFLAGS"
+
+ xdvi_ld_save_LIBS="$LIBS"
+ xdvi_ld_save_CFLAGS="$CFLAGS"
+ xdvi_ld_save_CPPFLAGS="$CPPFLAGS"
+ xdvi_ld_save_LDFLAGS="$LDFLAGS"
+
+ LIBS="$X_PRE_LIBS -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+ CFLAGS="$X_CFLAGS $CFLAGS"
+ CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+ LDFLAGS="$X_LIBS $LDFLAGS"
+
+ echo $ac_n "checking whether linker supports multiple definitions by default""... $ac_c" 1>&6
+echo "configure:3598: checking whether linker supports multiple definitions by default" >&5
+
+ cat > conftest.$ac_ext <<EOF
+#line 3601 "configure"
+#include "confdefs.h"
+#include <X11/Intrinsic.h>
+
+ XtIntervalId XtAppAddTimeOut(XtAppContext app,
+ unsigned long interval,
+ XtTimerCallbackProc proc,
+ XtPointer closure)
+ {
+ (void)app; (void)interval; (void)proc; (void)closure;
+ return (XtIntervalId)0;
+ }
+
+int main() {
+
+ XtIntervalId i = 0;
+ XtRemoveTimeOut(i);
+
+; return 0; }
+EOF
+if { (eval echo configure:3621: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ xdvi_linker_multiple_defns=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_linker_multiple_defns=no
+
+fi
+rm -f conftest*
+
+ if test $xdvi_linker_multiple_defns = yes; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define LD_ALLOWS_MULTIPLE_DEFINITIONS 1
+EOF
+
+ else
+ echo "$ac_t""no" 1>&6
+ echo "configure: warning: Linker does not allow multiple definitions.
+ *****************************************************************
+ * Warning: Your linker does not allow multiple definitions. *
+ * This does not make xdvik unusable, but it will cause problems *
+ * with event handling: Some widgets, e.g. the print log window, *
+ * tooltips, statusline messages and hyperlink location markers *
+ * will not be updated until the mouse is moved. *
+ *****************************************************************" 1>&2
+ fi
+ LIBS="$xdvi_ld_save_LIBS"
+ CFLAGS="$xdvi_ld_save_CFLAGS"
+ CPPFLAGS="$xdvi_ld_save_CPPFLAGS"
+ LDFLAGS="$xdvi_ld_save_LDFLAGS"
+fi
+
+
+for ac_hdr in stdint.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3661: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3666 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3671: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for uint32_t""... $ac_c" 1>&6
+echo "configure:3699: checking for uint32_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_uint32_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3704 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])uint32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_uint32_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_uint32_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_uint32_t" 1>&6
+if test $ac_cv_type_uint32_t = no; then
+ cat >> confdefs.h <<\EOF
+#define uint32_t unsigned long
+EOF
+
+fi
+
+
+
+for ac_func in mkstemp memcpy strerror waitpid sigaction strchr setenv ulltostr \
+ fchdir getcwd getpwnam getuid getpwuid \
+ iconv nl_langinfo \
+ lstat ftruncate snprintf vsnprintf realpath
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3742: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3747 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3770: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+for ac_hdr in netdb.h sys/bsdtypes.h sys/param.h unistd.h sys/fcntl.h regex.h iconv.h langinfo.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3799: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3804 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3809: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+cppflags_save=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+for ac_hdr in X11/Xosdefs.h X11/xpm.h Xm/XpmP.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3842: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3847 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3852: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+CPPFLAGS=$cppflags_save
+
+cppflags_save=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+for ac_hdr in X11/Intrinsic.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3886: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3891 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3896: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in X11/Xmu/Editres.h X11/Xmu/Xmu.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:3926: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3931 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3936: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ x_xmu_lib=-lXmu
+else
+ echo "$ac_t""no" 1>&6
+x_xmu_lib=
+fi
+done
+
+
+CPPFLAGS=$cppflags_save
+
+
+
+# Check whether --with-x-toolkit or --without-x-toolkit was given.
+if test "${with_x_toolkit+set}" = set; then
+ withval="$with_x_toolkit"
+
+ echo "configure: warning: the --with-x-toolkit option is obsolete; please use --with-mf-x-toolkit
+and/or --with-xdvi-x-toolkit instead. (Assuming default toolkit.)" 1>&2
+ with_xdvi_x_toolkit=yes
+ with_mf_x_toolkit=yes
+
+fi
+
+
+
+# Check if the user wants to use Ghostscript, DPS or NeWS to
+# display PostScript.
+# Check whether --with-ps or --without-ps was given.
+if test "${with_ps+set}" = set; then
+ withval="$with_ps"
+ case $withval in
+ yes|gs) PS_DEF="$PS_DEF -DPS_GS";;
+ no) PS_DEF=no;;
+ dps) PS_DEF="$PS_DEF -DPS_DPS";;
+ news) PS_DEF="$PS_DEF -DPS_NEWS";;
+ *) echo "configure: warning: Unknown --with-ps argument \`$withval'; using gs." 1>&2;;
+ esac
+fi
+
+
+# Check whether --enable-grey or --disable-grey was given.
+if test "${enable_grey+set}" = set; then
+ enableval="$enable_grey"
+ if test "$enableval" = yes; then
+ cat >> confdefs.h <<\EOF
+#define GREY 1
+EOF
+
+ else
+ echo DISABLED grey
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define GREY 1
+EOF
+
+fi
+
+
+# Check whether --enable-color or --disable-color was given.
+if test "${enable_color+set}" = set; then
+ enableval="$enable_color"
+ if test "$enableval" = yes; then
+ cat >> confdefs.h <<\EOF
+#define COLOR 1
+EOF
+
+ else
+ echo DISABLED color
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define COLOR 1
+EOF
+
+fi
+
+
+
+
+# Check whether --enable-t1lib or --disable-t1lib was given.
+if test "${enable_t1lib+set}" = set; then
+ enableval="$enable_t1lib"
+ if test "$enableval" = yes; then
+ T1LIB=1
+ LDT1LIB=../../libs/t1lib/lib/.libs/libt1.a
+ cat >> confdefs.h <<\EOF
+#define LDT1LIB 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define T1LIB 1
+EOF
+
+else
+ T1LIB=
+ LDT1LIB=
+ echo DISABLED t1lib
+fi
+else
+ T1LIB=1
+LDT1LIB=../../libs/t1lib/lib/.libs/libt1.a
+cat >> confdefs.h <<\EOF
+#define LDT1LIB 1
+EOF
+
+cat >> confdefs.h <<\EOF
+#define T1LIB 1
+EOF
+
+fi
+
+
+# Check whether --enable-gf or --disable-gf was given.
+if test "${enable_gf+set}" = set; then
+ enableval="$enable_gf"
+ if test "$enableval" != no; then
+ cat >> confdefs.h <<\EOF
+#define USE_GF 1
+EOF
+
+ OPT_SRCS="$OPT_SRCS gf.c"
+ OPT_OBJS="$OPT_OBJS gf.o"
+fi
+fi
+
+
+# Check whether --enable-a4 or --disable-a4 was given.
+if test "${enable_a4+set}" = set; then
+ enableval="$enable_a4"
+ if test "$enableval" = yes; then
+ cat >> confdefs.h <<\EOF
+#define A4 1
+EOF
+
+ else
+ echo Disabled a4/cm, using letter/in instead
+fi
+else
+ cat >> confdefs.h <<\EOF
+#define A4 1
+EOF
+
+fi
+
+
+# Check whether --enable-magick or --disable-magick was given.
+if test "${enable_magick+set}" = set; then
+ enableval="$enable_magick"
+ if test "$enableval" != no; then
+ echo -n "checking for ImageMagick >= 5.3 ... "
+ if MAGICK_VER=`Magick-config --version 2>/dev/null`; then
+ echo $MAGICK_VER
+ set -- `echo $MAGICK_VER | sed -e 's/\./ /g'`
+ MAGICK_VER_MAJOR=$1
+ MAGICK_VER_MINOR=$2
+ if expr $MAGICK_VER_MAJOR \> 4 >/dev/null && \
+ (expr $MAGICK_VER_MAJOR \> 5 >/dev/null || \
+ expr $MAGICK_VER_MINOR \> 2 >/dev/null); then
+ MAGICK_CPP="-DMAGICK_VER_MAJOR=$MAGICK_VER_MAJOR -DMAGICK_VER_MINOR=$MAGICK_VER_MINOR `Magick-config --cppflags`"
+ # echo "CPP: $MAGICK_CPP"
+ MAGICK_LD="`Magick-config --libs`"
+ # echo "LD: $MAGICK_LD"
+ echo "ImageMagick support enabled"
+ MAGICK_INCLUDE=
+ MAGICK_LIBDIR=
+
+ if test "x$with_magick_include" != x; then
+ MAGIC_INCLUDE="-I$with_magick_include"
+ fi
+ if test "x$with_magick_libdir" != x; then
+ MAGIC_LIBDIR="-L$with_magick_libdir"
+ fi
+
+ X_EXTRA_LIBS="$X_EXTRA_LIBS $MAGIC_LIBDIR $MAGICK_LD"
+ X_CFLAGS="$X_CFLAGS $MAGIC_INCLUDE $MAGICK_CPP"
+ cat >> confdefs.h <<\EOF
+#define MAGICK 1
+EOF
+
+ #echo MAGICK_DEF=\"$MAGICK_DEF\"
+ else
+ echo "ImageMagick version too old - ImageMagick support disabled"
+ fi
+ else
+ echo "Can't run 'Magick-config' - ImageMagick support disabled"
+ fi
+fi
+fi
+
+
+
+
+
+
+# Check whether --with-xdvi-x-toolkit or --without-xdvi-x-toolkit was given.
+if test "${with_xdvi_x_toolkit+set}" = set; then
+ withval="$with_xdvi_x_toolkit"
+ case "${withval}" in
+ next | nextaw | neXtaw ) val=neXtaw ;;
+ xaw3d ) val=xaw3d ;;
+ x | xa | xaw ) val=xaw ;;
+ m | mo | mot | moti | motif ) val=motif ;;
+ * )
+echo "configure: warning: unknown --with-xdvi-x-toolkit argument \`$withval'; using xaw." 1>&2
+ val=xaw;;
+ esac
+ with_xdvi_x_toolkit=$val
+
+fi
+
+
+# Check whether --with-system-t1lib or --without-system-t1lib was given.
+if test "${with_system_t1lib+set}" = set; then
+ withval="$with_system_t1lib"
+ :
+fi
+
+
+# Check whether --with-t1lib_libdir or --without-t1lib_libdir was given.
+if test "${with_t1lib_libdir+set}" = set; then
+ withval="$with_t1lib_libdir"
+ :
+fi
+
+
+# Check whether --with-t1lib_include or --without-t1lib_include was given.
+if test "${with_t1lib_include+set}" = set; then
+ withval="$with_t1lib_include"
+ :
+fi
+
+
+if test "$needs_libt1" = no; then
+ LIBT1CPPFLAGS=
+ LDLIBT1=
+ LIBT1DEP=
+else
+ EXTRA_LIBT1_INCLUDE=
+ EXTRA_LIBT1_LIBDIR=
+
+ if test "$with_system_t1lib" = yes; then
+ if test "x$with_t1lib_libdir" != x; then
+ EXTRA_LIBT1_LIBDIR="-L$with_t1lib_libdir"
+ fi
+ if test "x$with_t1lib_include" != x; then
+ EXTRA_LIBT1_INCLUDE="-I$with_t1lib_include"
+ fi
+ fi
+
+ OLD_LDFLAGS=$LDFLAGS
+ OLD_CPP=$CPP
+ OLDCPPFLAGS=$CPPFLAGS
+ OLD_LIBS=$LIBS
+
+ LDFLAGS="$LDFLAGS $EXTRA_LIBT1_LIBDIR"
+ CPP="$CPP $EXTRA_LIBT1_INCLUDE"
+ CPPFLAGS="$CPPFLAGS $EXTRA_LIBT1_INCLUDE"
+
+ if test "$with_system_t1lib" = yes; then
+ echo $ac_n "checking for T1_AddFont in -lt1""... $ac_c" 1>&6
+echo "configure:4217: checking for T1_AddFont in -lt1" >&5
+ac_lib_var=`echo t1'_'T1_AddFont | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lt1 -lz -lm $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4225 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char T1_AddFont();
+
+int main() {
+T1_AddFont()
+; return 0; }
+EOF
+if { (eval echo configure:4236: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ t1lib=-lt1
+else
+ echo "$ac_t""no" 1>&6
+echo "configure: warning: Standard T1 library not found. Compiling my own." 1>&2
+ with_system_t1lib=no
+fi
+
+ fi
+
+ LIBS="-lt1 -lm $LIBS"
+ if test "$with_system_t1lib" = yes; then
+ echo $ac_n "checking whether installed T1 lib is >= v 5.0.0 ""... $ac_c" 1>&6
+echo "configure:4263: checking whether installed T1 lib is >= v 5.0.0 " >&5
+ if test "$cross_compiling" = yes; then
+ ac_compile_t1lib=1
+ ]
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4269 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include "t1lib.h"
+#define BUFLEN 128
+int main() {
+ char *t1libId = T1_GetLibIdent();
+ char testbuf[BUFLEN];
+ char *p = testbuf;
+ int i;
+ int version_num;
+ /* T1_GetLibIdent() might return something like '0.8-beta2';
+ convert the leading numbers to a single digit: */
+ for (i = 0; i < BUFLEN - 1; i++) {
+ if (t1libId[i] >= '0' && t1libId[i] <= '9')
+ *p++ = t1libId[i];
+ else if (t1libId[i] != '.' && t1libId[i] != '_' && t1libId[i] != '-')
+ break;
+ }
+ *p = '\0';
+ version_num = strtoul(testbuf, (char **)NULL, 10);
+ /* xdvik needs >= 5.0.0.
+ Try to deal with version strings with 1 or more digits. */
+ if (version_num >= 500
+ || (version_num < 100 && version_num >= 50)
+ || (version_num < 10 && version_num >= 5))
+ exit(0);
+ exit(1);
+}
+
+EOF
+if { (eval echo configure:4301: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_compile_t1lib=0
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_compile_t1lib=1
+fi
+rm -fr conftest*
+fi
+
+ if test $ac_compile_t1lib = 0; then
+ echo "$ac_t""yes" 1>&6
+ else
+ echo "$ac_t""no, will compile my own version" 1>&6
+ with_system_t1lib=no
+ fi
+ fi
+
+ LDFLAGS=$OLD_LDFLAGS
+ CPP=$OLD_CPP
+ CPPFLAGS=$OLDCPPFLAGS
+ LIBS=$OLD_LIBS
+
+ if test "$with_system_t1lib" != yes; then
+ LIBT1CPPFLAGS='-I$(LIBT1DIR) -I$(LIBT1SRCDIR) -I$(LIBT1DIR)/../type1 -I$(LIBT1SRCDIR)/../type1'
+ LDLIBT1='$(LIBT1DIR)/libt1.a $(LIBT1DIR)/../type1/libtype1.a'
+ LIBT1DEP='$(LIBT1DIR)/libt1.a $(LIBT1DIR)/../type1/libtype1.a'
+ using_system_t1lib=no
+ else
+ LIBT1CPPFLAGS="$EXTRA_LIBT1_INCLUDE"
+ LDLIBT1="$EXTRA_LIBT1_LIBDIR -lt1"
+ LIBT1DEP=
+ using_system_t1lib=yes
+ fi
+fi
+
+
+
+
+
+
+
+if test "${with_xdvi_x_toolkit}" = xaw; then
+ echo $ac_n "checking for Xaw library""... $ac_c" 1>&6
+echo "configure:4347: checking for Xaw library" >&5
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ cat > conftest.$ac_ext <<EOF
+#line 4351 "configure"
+#include "confdefs.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+#include <X11/Xaw/Form.h>
+
+int main() {
+
+
+; return 0; }
+EOF
+if { (eval echo configure:4368: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ xdvi_have_xaw=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_have_xaw=no
+
+fi
+rm -f conftest*
+ CPPFLAGS=$save_CPPFLAGS
+ if test $xdvi_have_xaw = yes; then
+ echo "$ac_t""yes" 1>&6
+ else
+ echo "$ac_t""not found" 1>&6
+ { echo "configure: error: Sorry, you will need at least the Xaw header/library files to compile xdvik." 1>&2; exit 1; }
+ fi
+
+ echo $ac_n "checking version of Xaw library""... $ac_c" 1>&6
+echo "configure:4388: checking version of Xaw library" >&5
+ save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+ cat > conftest.$ac_ext <<EOF
+#line 4392 "configure"
+#include "confdefs.h"
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/ToggleP.h>
+ typedef void (*XawDiamondProc) (Widget);
+
+ /* New fields for the Radio widget class record */
+ typedef struct _RadioClass {
+ Dimension dsize; /* diamond size */
+ XawDiamondProc drawDiamond;
+ /* pixmaps for the button */
+ Pixmap sel_radio; /* selected state */
+ Pixmap unsel_radio; /* unselected state */
+ Pixmap sel_menu; /* selected state */
+ Pixmap unsel_menu; /* unselected state */
+ /* TODO: 3-d and xaw-xpm features? */
+ XtPointer extension;
+ } RadioClassPart;
+
+ /* Full class record declaration */
+ typedef struct _RadioClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ ToggleClassPart toggle_class;
+ RadioClassPart radio_class;
+ } RadioClassRec;
+ /* New fields for the Radio widget record */
+ typedef struct {
+ /* resources */
+ Boolean isRadio; /* radio if True, checkbox else */
+ /* TODO: 3-d and xaw-xpm features? */
+
+ /* private data */
+ XtPointer extension;
+ } RadioPart;
+
+ /* Full widget declaration */
+ typedef struct _RadioRec {
+ CorePart core;
+ SimplePart simple;
+#ifdef _ThreeDP_h
+ ThreeDPart threeD;
+#endif
+ LabelPart label;
+ CommandPart command;
+ TogglePart toggle;
+ RadioPart radio;
+ } RadioRec;
+
+
+ /* The actions table from Toggle is almost perfect, but we need
+ * to override Highlight, Set, and Unset.
+ */
+
+#define SuperClass ((ToggleWidgetClass)&toggleClassRec)
+
+#define BOX_SIZE 16
+#define PIXMAP_OFFSET 2 /* additional space between pixmap and label */
+
+int main() {
+
+ RadioClassRec radioClassRec = {
+ {
+ (WidgetClass) SuperClass, /* superclass */
+ "Radio", /* class_name */
+ sizeof(RadioRec), /* size */
+ NULL, /* class_initialize */
+ NULL, /* class_part_initialize */
+ FALSE, /* class_inited */
+ NULL, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ NULL, /* resources */
+ 0, /* resource_count */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ NULL, /* destroy */
+ NULL, /* resize */
+ NULL, /* expose */
+ NULL, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ XtInheritTranslations, /* tm_table */
+ NULL, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL /* extension */
+ }, /* CoreClass fields initialization */
+ {
+ XtInheritChangeSensitive, /* change_sensitive */
+ NULL
+ }, /* SimpleClass fields initialization */
+ {
+ 0 /* field not used */
+ }, /* LabelClass fields initialization */
+ {
+ 0 /* field not used */
+ }, /* CommandClass fields initialization */
+ {
+ NULL, /* Set Procedure. */
+ NULL, /* Unset Procedure. */
+ NULL /* extension. */
+ }, /* ToggleClass fields initialization */
+ {
+ BOX_SIZE,
+ NULL, /* draw procedure */
+ None, /* selected radiobutton */
+ None, /* unselected radiobutton */
+ None, /* selected menubutton */
+ None, /* unselected menubutton */
+ NULL /* extension. */
+ } /* RadioClass fields initialization */
+ };
+ (void)radioClassRec;
+
+; return 0; }
+EOF
+if { (eval echo configure:4526: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ xdvi_old_xaw=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_old_xaw=yes
+
+fi
+rm -f conftest*
+ CPPFLAGS=$save_CPPFLAGS
+if test $xdvi_old_xaw = yes; then
+ echo "$ac_t""old" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_OLD_XAW 1
+EOF
+
+else
+ echo "$ac_t""current" 1>&6
+fi
+fi
+
+
+echo $ac_n "checking if nl_langinfo(CODESET) is working""... $ac_c" 1>&6
+echo "configure:4551: checking if nl_langinfo(CODESET) is working" >&5
+cat > conftest.$ac_ext <<EOF
+#line 4553 "configure"
+#include "confdefs.h"
+#include <langinfo.h>
+int main() {
+char* cs = nl_langinfo(CODESET);
+; return 0; }
+EOF
+if { (eval echo configure:4560: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ cat >> confdefs.h <<\EOF
+#define HAVE_WORKING_NL_LANGINFO_CODESET 1
+EOF
+ echo "$ac_t""yes" 1>&6
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+
+fi
+rm -f conftest*
+
+if test -z "$x_ext_lib"; then # allow envvar override
+ if test -n "$x_libraries"; then
+ XLFLAG="-L$x_libraries"
+ else
+ XLFLAG=
+ fi
+ echo $ac_n "checking for XpQueryVersion in -lXp""... $ac_c" 1>&6
+echo "configure:4582: checking for XpQueryVersion in -lXp" >&5
+ac_lib_var=`echo Xp'_'XpQueryVersion | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lXp -lXext -lX11 $X_EXTRA_LIBS $XLFLAG $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4590 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XpQueryVersion();
+
+int main() {
+XpQueryVersion()
+; return 0; }
+EOF
+if { (eval echo configure:4601: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ x_ext_lib="-lXp -lXext"
+else
+ echo "$ac_t""no" 1>&6
+:
+fi
+
+fi
+if test -z "$x_ext_lib"; then # previous test unsuccessful, or envvar override
+ if test -n "$x_libraries"; then
+ XLFLAG="-L$x_libraries"
+ else
+ XLFLAG=
+ fi
+ echo $ac_n "checking for XextCreateExtension in -lXext""... $ac_c" 1>&6
+echo "configure:4630: checking for XextCreateExtension in -lXext" >&5
+ac_lib_var=`echo Xext'_'XextCreateExtension | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lXext -lX11 $X_EXTRA_LIBS $XLFLAG $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4638 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char XextCreateExtension();
+
+int main() {
+XextCreateExtension()
+; return 0; }
+EOF
+if { (eval echo configure:4649: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ x_ext_lib=-lXext
+else
+ echo "$ac_t""no" 1>&6
+:
+fi
+
+fi
+
+
+
+
+
+xpm_includes=
+xpm_libraries=
+# Check whether --with-xpm or --without-xpm was given.
+if test "${with_xpm+set}" = set; then
+ withval="$with_xpm"
+ :
+fi
+
+if test "$with_xpm" = "no"
+then
+xpm_includes=no
+xpm_libraries=no
+fi
+# Check whether --with-xpm-includes or --without-xpm-includes was given.
+if test "${with_xpm_includes+set}" = set; then
+ withval="$with_xpm_includes"
+ xpm_includes="$withval"
+fi
+
+# Check whether --with-xpm-libraries or --without-xpm-libraries was given.
+if test "${with_xpm_libraries+set}" = set; then
+ withval="$with_xpm_libraries"
+ xpm_libraries="$withval"
+fi
+
+echo $ac_n "checking for Xpm""... $ac_c" 1>&6
+echo "configure:4702: checking for Xpm" >&5
+#
+#
+# Search the include files. XPM can either be in <X11/xpm.h> (as in X11R6),
+# which is dealt with by AC_CHECK_HEADERS(X11/xpm.h), or in <xpm.h> if installed locally;
+# this is what this test is for.
+#
+if test "$xpm_includes" = ""; then
+if eval "test \"`echo '$''{'xdvi_cv_xpm_includes'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+xdvi_xpm_save_LIBS="$LIBS"
+xdvi_xpm_save_CFLAGS="$CFLAGS"
+xdvi_xpm_save_CPPFLAGS="$CPPFLAGS"
+xdvi_xpm_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXpm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+cat > conftest.$ac_ext <<EOF
+#line 4725 "configure"
+#include "confdefs.h"
+
+#include <X11/xpm.h>
+
+int main() {
+int a;
+; return 0; }
+EOF
+if { (eval echo configure:4734: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+# X11/xpm.h is in the standard search path.
+xdvi_cv_xpm_includes="default"
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+# X11/xpm.h is not in the standard search path.
+# Locate it and put its directory in `xpm_includes'
+#
+# /usr/include/Motif* are used on HP-UX (Motif).
+# /usr/include/X11* are used on HP-UX (X and Xaw).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Xaw).
+# Other directories are just guesses.
+for dir in "$x_includes" "${prefix}/include" /usr/include /usr/local/include \
+ /usr/X11/include /usr/X11R5/include /usr/X11R6/include \
+ /usr/include/Motif2.0 /usr/include/Motif1.2 /usr/include/Motif1.1 \
+ /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 \
+ /usr/dt/include /usr/openwin/include \
+ /usr/dt/*/include /opt/*/include /usr/include/Motif* \
+ "${prefix}"/*/include /usr/*/include /usr/local/*/include \
+ "${prefix}"/include/* /usr/include/* /usr/local/include/*
+do
+ if test -f "$dir/X11/xpm.h"; then
+ xdvi_cv_xpm_includes="$dir"
+ break
+ elif test -f "$dir/xpm.h"; then
+ xdvi_cv_xpm_includes="$dir"
+ break
+ fi
+done
+
+fi
+rm -f conftest*
+#
+LIBS="$xdvi_xpm_save_LIBS"
+CFLAGS="$xdvi_xpm_save_CFLAGS"
+CPPFLAGS="$xdvi_xpm_save_CPPFLAGS"
+LDFLAGS="$xdvi_xpm_save_LDFLAGS"
+
+fi
+
+xpm_includes="$xdvi_cv_xpm_includes"
+fi
+
+if test "x$xpm_includes" != x; then
+ if test "x$xpm_includes" = xdefault; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_X11_XPM_H 1
+EOF
+
+ elif test -f "$xpm_includes/X11/xpm.h"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_X11_XPM_H 1
+EOF
+
+ elif test -f "$xpm_includes/xpm.h"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_XPM_H 1
+EOF
+
+ fi
+fi
+
+#
+#
+# Now for the libraries.
+#
+if test "$xpm_libraries" = ""; then
+if eval "test \"`echo '$''{'xdvi_cv_xpm_libraries'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+xdvi_xpm_save_LIBS="$LIBS"
+xdvi_xpm_save_CFLAGS="$CFLAGS"
+xdvi_xpm_save_CPPFLAGS="$CPPFLAGS"
+xdvi_xpm_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXpm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+xdvi_cv_xpm_libraries=
+#
+#
+# We use XtToolkitInitialize() here since it takes no arguments
+# and thus also works with a C++ compiler.
+cat > conftest.$ac_ext <<EOF
+#line 4827 "configure"
+#include "confdefs.h"
+
+#include <X11/Intrinsic.h>
+#include <X11/xpm.h>
+
+int main() {
+XtToolkitInitialize();
+; return 0; }
+EOF
+if { (eval echo configure:4837: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+
+# libxpm.a is in the standard search path.
+xdvi_cv_xpm_libraries="default"
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+# libXpm.a is not in the standard search path.
+# Locate it and put its directory in `xpm_libraries'
+#
+#
+# /usr/lib/Motif* are used on HP-UX (Motif).
+# /usr/lib/X11* are used on HP-UX (X and Xpm).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Xpm).
+# Other directories are just guesses.
+for dir in "$x_libraries" "${prefix}/lib" /usr/lib /usr/local/lib \
+ /usr/lib/Motif2.0 /usr/lib/Motif1.2 /usr/lib/Motif1.1 \
+ /usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4 /usr/lib/X11 \
+ /usr/dt/lib /usr/openwin/lib \
+ /usr/dt/*/lib /opt/*/lib /usr/lib/Motif* \
+ "${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \
+ "${prefix}"/lib/* /usr/lib/* /usr/local/lib/*
+do
+ if test -d "$dir" && test "`ls $dir/libXpm.* 2> /dev/null`" != ""; then
+ xdvi_cv_xpm_libraries="$dir"
+ break
+ fi
+done
+
+fi
+rm -f conftest*
+#
+LIBS="$xdvi_xpm_save_LIBS"
+CFLAGS="$xdvi_xpm_save_CFLAGS"
+CPPFLAGS="$xdvi_xpm_save_CPPFLAGS"
+LDFLAGS="$xdvi_xpm_save_LDFLAGS"
+
+fi
+
+#
+xpm_libraries="$xdvi_cv_xpm_libraries"
+fi
+#
+# Add Xpm definitions to X flags
+#
+if test "x$xpm_includes" != "xdefault" && test "$xpm_includes" != "" \
+ && test "$xpm_includes" != "$x_includes" && test "$xpm_includes" != "no"
+then
+ X_CFLAGS="-I$xpm_includes $X_CFLAGS"
+fi
+
+if test "x$xpm_libraries" != "xdefault" && test "$xpm_libraries" != "" \
+ && test "$xpm_libraries" != "$x_libraries" && test "$xpm_libraries" != "no"
+then
+case "$X_LIBS" in
+ *-R\ *) X_LIBS="-L$xpm_libraries -R $xpm_libraries $X_LIBS";;
+ *-R*) X_LIBS="-L$xpm_libraries -R$xpm_libraries $X_LIBS";;
+ *) X_LIBS="-L$xpm_libraries $X_LIBS";;
+esac
+fi
+
+#
+#
+x_xpm_libs="-lXpm"
+#
+# Now check the results of headers and libraries and set USE_XPM to 0
+# if one of them hadn't been found.
+#
+cat >> confdefs.h <<\EOF
+#define USE_XPM 1
+EOF
+
+xpm_libraries_result="$xpm_libraries"
+xpm_includes_result="$xpm_includes"
+if test "x$xpm_libraries_result" = "xdefault" ; then
+ xpm_libraries_result="in default path"
+elif test "$xpm_libraries_result" = no || test "x$xpm_libraries_result" = "x"; then
+ xpm_libraries_result="(none)"
+ cat >> confdefs.h <<\EOF
+#define USE_XPM 0
+EOF
+
+ x_xpm_libs=""
+fi
+
+if test "x$xpm_includes_result" = "xdefault"; then
+ xpm_includes_result="in default path"
+elif test "$xpm_includes_result" = no || test "x$xpm_includes_result" = "x"; then
+ cat >> confdefs.h <<\EOF
+#define USE_XPM 0
+EOF
+
+ xpm_includes_result="(none)"
+fi
+
+
+echo "$ac_t""libraries $xpm_libraries_result, headers $xpm_includes_result" 1>&6
+
+
+prog_extension="xaw"
+motif_include=
+motif_libdir=
+# Check whether --with-motif-include or --without-motif-include was given.
+if test "${with_motif_include+set}" = set; then
+ withval="$with_motif_include"
+ motif_include="$withval"
+fi
+
+# Check whether --with-motif-libdir or --without-motif-libdir was given.
+if test "${with_motif_libdir+set}" = set; then
+ withval="$with_motif_libdir"
+ motif_libdir="$withval"
+fi
+
+
+if test "x$with_xdvi_x_toolkit" = xxaw3d; then
+ prog_extension="xaw3d"
+ x_tool_libs="-lXaw3d"
+elif test "x$with_xdvi_x_toolkit" = xneXtaw; then
+ prog_extension="nextaw"
+ x_tool_libs="-lneXtaw"
+elif test "x$with_xdvi_x_toolkit" = xmotif; then
+
+default_toolkit="none"
+motif_include=""$motif_include""
+motif_libdir=""$motif_libdir""
+
+echo $ac_n "checking for Motif""... $ac_c" 1>&6
+echo "configure:4970: checking for Motif" >&5
+#
+#
+# Search the include files.
+#
+if test "$motif_include" = ""; then
+if eval "test \"`echo '$''{'xdvi_cv_motif_include'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+xdvi_motif_save_LIBS="$LIBS"
+xdvi_motif_save_CFLAGS="$CFLAGS"
+xdvi_motif_save_CPPFLAGS="$CPPFLAGS"
+xdvi_motif_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+cat > conftest.$ac_ext <<EOF
+#line 4991 "configure"
+#include "confdefs.h"
+#include <Xm/Xm.h>
+int main() {
+int a;
+; return 0; }
+EOF
+if { (eval echo configure:4998: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+# Xm/Xm.h is in the standard search path.
+xdvi_cv_motif_include=
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+# Xm/Xm.h is not in the standard search path.
+# Locate it and put its directory in `motif_include'
+#
+# /usr/include/Motif* are used on HP-UX (Motif).
+# /usr/include/X11* are used on HP-UX (X and Athena).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Athena).
+# Other directories are just guesses.
+for dir in "$x_includes" "${prefix}/include" /usr/include /usr/local/include \
+ /usr/include/Motif2.0 /usr/include/Motif1.2 /usr/include/Motif1.1 \
+ /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 \
+ /usr/dt/include /usr/openwin/include \
+ /usr/dt/*/include /opt/*/include /usr/include/Motif* \
+ "${prefix}"/*/include /usr/*/include /usr/local/*/include \
+ "${prefix}"/include/* /usr/include/* /usr/local/include/*; do
+ if test -f "$dir/Xm/Xm.h"; then
+ xdvi_cv_motif_include="$dir"
+ break
+ fi
+done
+if test "$xdvi_cv_motif_include" = ""; then
+xdvi_cv_motif_include=no
+fi
+
+fi
+rm -f conftest*
+#
+LIBS="$xdvi_motif_save_LIBS"
+CFLAGS="$xdvi_motif_save_CFLAGS"
+CPPFLAGS="$xdvi_motif_save_CPPFLAGS"
+LDFLAGS="$xdvi_motif_save_LDFLAGS"
+
+fi
+
+motif_include="$xdvi_cv_motif_include"
+fi
+#
+#
+# Now for the libraries.
+#
+if test "$motif_libdir" = ""; then
+if eval "test \"`echo '$''{'xdvi_cv_motif_libdir'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+xdvi_motif_save_LIBS="$LIBS"
+xdvi_motif_save_CFLAGS="$CFLAGS"
+xdvi_motif_save_CPPFLAGS="$CPPFLAGS"
+xdvi_motif_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+# We use XtToolkitInitialize() here since it takes no arguments
+# and thus also works with a C++ compiler.
+cat > conftest.$ac_ext <<EOF
+#line 5067 "configure"
+#include "confdefs.h"
+#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+
+int main() {
+XtToolkitInitialize();
+; return 0; }
+EOF
+if { (eval echo configure:5076: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+
+# libXm.a is in the standard search path.
+xdvi_cv_motif_libdir=
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+# libXm.a is not in the standard search path.
+# Locate it and put its directory in `motif_libdir'
+#
+# /usr/lib/Motif* are used on HP-UX (Motif).
+# /usr/lib/X11* are used on HP-UX (X and Athena).
+# /usr/dt is used on Solaris (Motif).
+# /usr/lesstif is used on Linux (Lesstif).
+# /usr/openwin is used on Solaris (X and Athena).
+# Other directories are just guesses.
+for dir in "$x_libraries" "${prefix}/lib" /usr/lib /usr/local/lib \
+ /usr/lib/Motif2.0 /usr/lib/Motif1.2 /usr/lib/Motif1.1 \
+ /usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4 /usr/lib/X11 \
+ /usr/dt/lib /usr/openwin/lib \
+ /usr/dt/*/lib /opt/*/lib /usr/lib/Motif* \
+ /usr/lesstif*/lib /usr/lib/Lesstif* \
+ "${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \
+ "${prefix}"/lib/* /usr/lib/* /usr/local/lib/*; do
+ if test -d "$dir" && test "`ls $dir/libXm.* 2> /dev/null`" != ""; then
+ xdvi_cv_motif_libdir="$dir"
+ break
+ fi
+done
+if test "$xdvi_cv_motif_libdir" = ""; then
+xdvi_cv_motif_libdir=no
+fi
+
+fi
+rm -f conftest*
+#
+LIBS="$xdvi_motif_save_LIBS"
+CFLAGS="$xdvi_motif_save_CFLAGS"
+CPPFLAGS="$xdvi_motif_save_CPPFLAGS"
+LDFLAGS="$xdvi_motif_save_LDFLAGS"
+
+fi
+
+#
+motif_libdir="$xdvi_cv_motif_libdir"
+fi
+# Add Motif definitions to X flags
+#
+if test "$motif_include" != "" && test "$motif_include" != "$x_includes" && test "$motif_include" != "no"
+then
+X_CFLAGS="-I$motif_include $X_CFLAGS"
+fi
+if test "$motif_libdir" != "" && test "$motif_libdir" != "$x_libraries" && test "$motif_libdir" != "no"
+then
+case "$X_LIBS" in
+ *-R\ *) X_LIBS="-L$motif_libdir -R $motif_libdir $X_LIBS";;
+ *-R*) X_LIBS="-L$motif_libdir -R$motif_libdir $X_LIBS";;
+ *) X_LIBS="-L$motif_libdir $X_LIBS";;
+esac
+fi
+#
+#
+motif_libdir_result="$motif_libdir"
+motif_include_result="$motif_include"
+test "$motif_libdir_result" = "" &&
+ motif_libdir_result="in default path" && cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+test "$motif_include_result" = "" &&
+ motif_include_result="in default path" && cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+if test "$motif_libdir_result" = "no"; then
+ if test "$default_toolkit" = "none"; then
+ motif_libdir_result="(none)"
+ else
+ motif_libdir_result=""
+ fi
+fi
+if test "$motif_include_result" = "no"; then
+ if test "$default_toolkit" = "none"; then
+ motif_include_result="(none)"
+ else
+ motif_include_result=""
+ fi
+fi
+
+if test "$motif_include_result" != "" && test "$motif_libdir_result" != ""; then
+ echo "$ac_t""libraries $motif_libdir_result, headers $motif_include_result" 1>&6
+ prog_extension="motif"
+ cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+ x_tool_libs="-lXm"
+else
+ echo "$ac_t""not found, using Xaw" 1>&6
+ prog_extension="xaw"
+ cat >> confdefs.h <<\EOF
+#define XAW 1
+EOF
+
+ x_tool_libs="-lXaw"
+fi
+
+#
+echo $ac_n "checking whether to compile in panner (requires Xaw)""... $ac_c" 1>&6
+echo "configure:5189: checking whether to compile in panner (requires Xaw)" >&5
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+cat > conftest.$ac_ext <<EOF
+#line 5193 "configure"
+#include "confdefs.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/Xaw/Reports.h>
+
+int main() {
+
+
+; return 0; }
+EOF
+if { (eval echo configure:5211: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ xdvi_use_xaw_panner=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_use_xaw_panner=no
+
+fi
+rm -f conftest*
+CPPFLAGS=$save_CPPFLAGS
+if test $xdvi_use_xaw_panner = yes; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_XAW_PANNER 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+elif test "x$with_xdvi_x_toolkit" = xxaw; then
+ prog_extension="xaw"
+ cat >> confdefs.h <<\EOF
+#define XAW 1
+EOF
+
+ x_tool_libs="-lXaw"
+else
+
+default_toolkit="Xaw"
+motif_include=""$motif_include""
+motif_libdir=""$motif_libdir""
+
+echo $ac_n "checking for Motif""... $ac_c" 1>&6
+echo "configure:5247: checking for Motif" >&5
+#
+#
+# Search the include files.
+#
+if test "$motif_include" = ""; then
+if eval "test \"`echo '$''{'xdvi_cv_motif_include'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+xdvi_motif_save_LIBS="$LIBS"
+xdvi_motif_save_CFLAGS="$CFLAGS"
+xdvi_motif_save_CPPFLAGS="$CPPFLAGS"
+xdvi_motif_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+cat > conftest.$ac_ext <<EOF
+#line 5268 "configure"
+#include "confdefs.h"
+#include <Xm/Xm.h>
+int main() {
+int a;
+; return 0; }
+EOF
+if { (eval echo configure:5275: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+
+# Xm/Xm.h is in the standard search path.
+xdvi_cv_motif_include=
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+# Xm/Xm.h is not in the standard search path.
+# Locate it and put its directory in `motif_include'
+#
+# /usr/include/Motif* are used on HP-UX (Motif).
+# /usr/include/X11* are used on HP-UX (X and Athena).
+# /usr/dt is used on Solaris (Motif).
+# /usr/openwin is used on Solaris (X and Athena).
+# Other directories are just guesses.
+for dir in "$x_includes" "${prefix}/include" /usr/include /usr/local/include \
+ /usr/include/Motif2.0 /usr/include/Motif1.2 /usr/include/Motif1.1 \
+ /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 \
+ /usr/dt/include /usr/openwin/include \
+ /usr/dt/*/include /opt/*/include /usr/include/Motif* \
+ "${prefix}"/*/include /usr/*/include /usr/local/*/include \
+ "${prefix}"/include/* /usr/include/* /usr/local/include/*; do
+ if test -f "$dir/Xm/Xm.h"; then
+ xdvi_cv_motif_include="$dir"
+ break
+ fi
+done
+if test "$xdvi_cv_motif_include" = ""; then
+xdvi_cv_motif_include=no
+fi
+
+fi
+rm -f conftest*
+#
+LIBS="$xdvi_motif_save_LIBS"
+CFLAGS="$xdvi_motif_save_CFLAGS"
+CPPFLAGS="$xdvi_motif_save_CPPFLAGS"
+LDFLAGS="$xdvi_motif_save_LDFLAGS"
+
+fi
+
+motif_include="$xdvi_cv_motif_include"
+fi
+#
+#
+# Now for the libraries.
+#
+if test "$motif_libdir" = ""; then
+if eval "test \"`echo '$''{'xdvi_cv_motif_libdir'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+xdvi_motif_save_LIBS="$LIBS"
+xdvi_motif_save_CFLAGS="$CFLAGS"
+xdvi_motif_save_CPPFLAGS="$CPPFLAGS"
+xdvi_motif_save_LDFLAGS="$LDFLAGS"
+#
+LIBS="$X_PRE_LIBS -lXm -lXt -lX11 $X_EXTRA_LIBS $LIBS"
+CFLAGS="$X_CFLAGS $CFLAGS"
+CPPFLAGS="$X_CFLAGS $CPPFLAGS"
+LDFLAGS="$X_LIBS $LDFLAGS"
+#
+# We use XtToolkitInitialize() here since it takes no arguments
+# and thus also works with a C++ compiler.
+cat > conftest.$ac_ext <<EOF
+#line 5344 "configure"
+#include "confdefs.h"
+#include <X11/Intrinsic.h>
+#include <Xm/Xm.h>
+
+int main() {
+XtToolkitInitialize();
+; return 0; }
+EOF
+if { (eval echo configure:5353: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+
+# libXm.a is in the standard search path.
+xdvi_cv_motif_libdir=
+
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+
+# libXm.a is not in the standard search path.
+# Locate it and put its directory in `motif_libdir'
+#
+# /usr/lib/Motif* are used on HP-UX (Motif).
+# /usr/lib/X11* are used on HP-UX (X and Athena).
+# /usr/dt is used on Solaris (Motif).
+# /usr/lesstif is used on Linux (Lesstif).
+# /usr/openwin is used on Solaris (X and Athena).
+# Other directories are just guesses.
+for dir in "$x_libraries" "${prefix}/lib" /usr/lib /usr/local/lib \
+ /usr/lib/Motif2.0 /usr/lib/Motif1.2 /usr/lib/Motif1.1 \
+ /usr/lib/X11R6 /usr/lib/X11R5 /usr/lib/X11R4 /usr/lib/X11 \
+ /usr/dt/lib /usr/openwin/lib \
+ /usr/dt/*/lib /opt/*/lib /usr/lib/Motif* \
+ /usr/lesstif*/lib /usr/lib/Lesstif* \
+ "${prefix}"/*/lib /usr/*/lib /usr/local/*/lib \
+ "${prefix}"/lib/* /usr/lib/* /usr/local/lib/*; do
+ if test -d "$dir" && test "`ls $dir/libXm.* 2> /dev/null`" != ""; then
+ xdvi_cv_motif_libdir="$dir"
+ break
+ fi
+done
+if test "$xdvi_cv_motif_libdir" = ""; then
+xdvi_cv_motif_libdir=no
+fi
+
+fi
+rm -f conftest*
+#
+LIBS="$xdvi_motif_save_LIBS"
+CFLAGS="$xdvi_motif_save_CFLAGS"
+CPPFLAGS="$xdvi_motif_save_CPPFLAGS"
+LDFLAGS="$xdvi_motif_save_LDFLAGS"
+
+fi
+
+#
+motif_libdir="$xdvi_cv_motif_libdir"
+fi
+# Add Motif definitions to X flags
+#
+if test "$motif_include" != "" && test "$motif_include" != "$x_includes" && test "$motif_include" != "no"
+then
+X_CFLAGS="-I$motif_include $X_CFLAGS"
+fi
+if test "$motif_libdir" != "" && test "$motif_libdir" != "$x_libraries" && test "$motif_libdir" != "no"
+then
+case "$X_LIBS" in
+ *-R\ *) X_LIBS="-L$motif_libdir -R $motif_libdir $X_LIBS";;
+ *-R*) X_LIBS="-L$motif_libdir -R$motif_libdir $X_LIBS";;
+ *) X_LIBS="-L$motif_libdir $X_LIBS";;
+esac
+fi
+#
+#
+motif_libdir_result="$motif_libdir"
+motif_include_result="$motif_include"
+test "$motif_libdir_result" = "" &&
+ motif_libdir_result="in default path" && cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+test "$motif_include_result" = "" &&
+ motif_include_result="in default path" && cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+if test "$motif_libdir_result" = "no"; then
+ if test "$default_toolkit" = "none"; then
+ motif_libdir_result="(none)"
+ else
+ motif_libdir_result=""
+ fi
+fi
+if test "$motif_include_result" = "no"; then
+ if test "$default_toolkit" = "none"; then
+ motif_include_result="(none)"
+ else
+ motif_include_result=""
+ fi
+fi
+
+if test "$motif_include_result" != "" && test "$motif_libdir_result" != ""; then
+ echo "$ac_t""libraries $motif_libdir_result, headers $motif_include_result" 1>&6
+ prog_extension="motif"
+ cat >> confdefs.h <<\EOF
+#define MOTIF 1
+EOF
+
+ x_tool_libs="-lXm"
+else
+ echo "$ac_t""not found, using Xaw" 1>&6
+ prog_extension="xaw"
+ cat >> confdefs.h <<\EOF
+#define XAW 1
+EOF
+
+ x_tool_libs="-lXaw"
+fi
+
+#
+echo $ac_n "checking whether to compile in panner (requires Xaw)""... $ac_c" 1>&6
+echo "configure:5466: checking whether to compile in panner (requires Xaw)" >&5
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+cat > conftest.$ac_ext <<EOF
+#line 5470 "configure"
+#include "confdefs.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/Xaw/Reports.h>
+
+int main() {
+
+
+; return 0; }
+EOF
+if { (eval echo configure:5488: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ xdvi_use_xaw_panner=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ xdvi_use_xaw_panner=no
+
+fi
+rm -f conftest*
+CPPFLAGS=$save_CPPFLAGS
+if test $xdvi_use_xaw_panner = yes; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_XAW_PANNER 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+
+# Check whether --with-iconv-libdir or --without-iconv-libdir was given.
+if test "${with_iconv_libdir+set}" = set; then
+ withval="$with_iconv_libdir"
+ if test XXX"$withval" != "XXX"; then
+ iconv_libpath="-L$withval"
+ iconv_libs="-lrecode"
+else
+ iconv_libpath=
+ iconv_libs=
+fi
+else
+
+iconv_libpath=
+iconv_libs=
+echo $ac_n "checking for iconv_open in -liconv""... $ac_c" 1>&6
+echo "configure:5528: checking for iconv_open in -liconv" >&5
+ac_lib_var=`echo iconv'_'iconv_open | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-liconv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5536 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char iconv_open();
+
+int main() {
+iconv_open()
+; return 0; }
+EOF
+if { (eval echo configure:5547: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ iconv_libs=-liconv
+else
+ echo "$ac_t""no" 1>&6
+echo $ac_n "checking for libiconv_open in -liconv""... $ac_c" 1>&6
+echo "configure:5566: checking for libiconv_open in -liconv" >&5
+ac_lib_var=`echo iconv'_'libiconv_open | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-liconv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5574 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char libiconv_open();
+
+int main() {
+libiconv_open()
+; return 0; }
+EOF
+if { (eval echo configure:5585: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ iconv_libs=-liconv
+else
+ echo "$ac_t""no" 1>&6
+iconv_libs=
+fi
+
+
+fi
+
+
+fi
+
+if test XXX"$iconv_libs" != "XXX"; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ICONV 1
+EOF
+
+fi
+
+
+
+# Check whether --with-iconv-include or --without-iconv-include was given.
+if test "${with_iconv_include+set}" = set; then
+ withval="$with_iconv_include"
+ if test XXX"$withval" != "XXX"; then
+ iconv_includes="-I$withval"
+fi
+else
+
+iconv_includes=
+
+fi
+
+
+
+
+ ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+# AC_LANG_PUSH(C++) # in newer autoconf
+#
+xdvi_iconv_save_libs="$LIBS"
+xdvi_iconv_save_cxxflags="$CXXFLAGS"
+xdvi_iconv_save_ldflags="$LDFLAGS"
+#
+LIBS="$LIBS $iconv_libs"
+CXXFLAGS="$CXXFLAGS $iconv_includes"
+LDFLAGS="$LDFLAGS $iconv_libpath"
+#
+echo $ac_n "checking for iconv input type""... $ac_c" 1>&6
+echo "configure:5654: checking for iconv input type" >&5
+if eval "test \"`echo '$''{'xdvi_iconv_char_pptr_type'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ # `correct' default for cross-compiling ...
+xdvi_iconv_char_pptr_type="char_pptr"
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5663 "configure"
+#include "confdefs.h"
+#ifdef __cplusplus
+extern "C" void exit(int);
+#endif
+
+/* iconv() definitions may differ depending on following macros ... */
+#ifdef __hpux
+/* On HP-UX 10.10 B and 20.10, compiling with _XOPEN_SOURCE + ..._EXTENDED
+ * leads to poll() not realizing that a file descriptor is writable in psgs.c.
+ */
+# define _HPUX_SOURCE 1
+#else
+# ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+# endif
+# define _XOPEN_SOURCE_EXTENDED 1
+# define __EXTENSIONS__ 1 /* needed to get struct timeval on SunOS 5.5 */
+# define _SVID_SOURCE 1 /* needed to get S_IFLNK in glibc */
+# define _BSD_SOURCE 1 /* needed to get F_SETOWN in glibc-2.1.3 */
+#endif
+
+#include <iconv.h>
+
+ // Define two iconv_adapter() functions, one with a const char **, the other with
+ // a char ** argument. The compiler will figure out which one to use, and we can
+ // check the exit value to see which it was.
+ // Idea taken from http://gcc.gnu.org/ml/libstdc++/2000-11/msg00127.html
+
+ typedef const char ** ConstCharPtrT;
+ typedef char ** CharPtrT;
+
+ inline int
+ iconv_adapter(size_t(*iconv_func)(iconv_t, ConstCharPtrT, size_t *, char**, size_t*),
+ iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+ {
+ return 1; // 1 = false = const char **
+ }
+
+
+ inline int
+ iconv_adapter(size_t(*iconv_func)(iconv_t, CharPtrT, size_t *, char**, size_t*),
+ iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+ {
+ return 0; // 0 = true = char **
+ }
+
+
+ int main(void)
+ {
+ iconv_t testconv = (iconv_t)-1;
+ char *ptr1 = 0;
+ char *ptr2 = 0;
+ size_t len1 = 0;
+ size_t len2 = 0;
+
+ return iconv_adapter(iconv, testconv,
+ (char**)&ptr1, &len1,
+ (char**)&ptr2, &len2);
+ }
+
+EOF
+if { (eval echo configure:5727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ xdvi_iconv_char_pptr_type="char_pptr"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ xdvi_iconv_char_pptr_type="const_char_pptr"
+fi
+rm -fr conftest*
+fi
+
+fi
+
+#
+LIBS="$xdvi_iconv_save_libs"
+CXXFLAGS="$xdvi_iconv_save_cxxflags"
+LDFLAGS="$xdvi_iconv_save_ldflags"
+#
+if test $xdvi_iconv_char_pptr_type = "const_char_pptr"; then
+ cat >> confdefs.h <<\EOF
+#define ICONV_CHAR_PPTR_TYPE const char **
+EOF
+
+ echo "$ac_t""const char **" 1>&6
+else
+ cat >> confdefs.h <<\EOF
+#define ICONV_CHAR_PPTR_TYPE char **
+EOF
+
+ echo "$ac_t""char **" 1>&6
+fi
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+#AC_LANG_POP(C++) # in newer autoconf
+
+
+my_program_transform_name=`echo $program_transform_name | sed 's,\\$\\$,$,g' | sed 's,\\\\\\\\,\\\\,g'`
+exec_name="xdvi-$prog_extension.bin"
+final_exec_name=`echo $exec_name | sed "$my_program_transform_name"`
+wrapper_script=`echo xdvi | sed "$my_program_transform_name"`
+
+
+
+
+
+test -z "$PS_DEF" && PS_DEF=-DPS_GS
+test "$PS_DEF" = no && PS_DEF=
+if echo "$PS_DEF" | grep PS_DPS >/dev/null; then
+ if test "`(uname) 2>/dev/null`" = SunOS \
+ && uname -r | grep '^5' >/dev/null; then
+ echo "$ac_t""adding DPS includes and libraries for Solaris" 1>&6
+ X_CFLAGS="$X_CFLAGS -I/usr/openwin/include/X11"
+ echo $ac_n "checking for isinf in -lsunmath""... $ac_c" 1>&6
+echo "configure:5786: checking for isinf in -lsunmath" >&5
+ac_lib_var=`echo sunmath'_'isinf | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsunmath $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5794 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char isinf();
+
+int main() {
+isinf()
+; return 0; }
+EOF
+if { (eval echo configure:5805: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_sunmath=-lsunmath
+else
+ echo "$ac_t""no" 1>&6
+ac_sunmath=""
+fi
+
+ X_LIBS="$X_LIBS -R/usr/openwin/lib /usr/openwin/lib/libdps.so $ac_sunmath"
+ for ac_func in isinf
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:5830: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5835 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:5858: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ for ac_hdr in ieeefp.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:5886: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 5891 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:5896: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ else
+ echo "$ac_t""adding DPS includes and libraries for SunOS 4.x" 1>&6
+ X_LIBS="$X_LIBS -ldps"
+ fi
+elif echo "$PS_DEF" | grep PS_NEWS >/dev/null; then
+ echo "$ac_t""adding NeWS libraries" 1>&6
+ X_LIBS="$X_LIBS -lxview -lcps -lolgx -lxvps"
+fi
+
+# Check whether --with-default-dvips-path or --without-default-dvips-path was given.
+if test "${with_default_dvips_path+set}" = set; then
+ withval="$with_default_dvips_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_DVIPS_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_DVIPS_PATH "dvips"
+EOF
+
+
+fi
+
+
+# Check whether --with-default-ps2pdf-path or --without-default-ps2pdf-path was given.
+if test "${with_default_ps2pdf_path+set}" = set; then
+ withval="$with_default_ps2pdf_path"
+ cat >> confdefs.h <<EOF
+#define DEFAULT_PS2PDF_PATH "$withval"
+EOF
+
+
+else
+ cat >> confdefs.h <<\EOF
+#define DEFAULT_PS2PDF_PATH "ps2pdf"
+EOF
+
+
+fi
+
+
+PS_DEF="$PS_DEF $MAGICK_DEF"
+if echo "$PS_DEF" | grep MAGICK >/dev/null; then
+ echo "$ac_t""adding ImageMagick libraries" 1>&6
+ X_EXTRA_LIBS="$X_EXTRA_LIBS `Magick-config --libs`"
+fi
+
+# needed for web2c later than 7.3.4:
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:5973: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lm $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 5981 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:5988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lm $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:6016: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 6021 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:6070: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+
+# If you're cross-compiling, these macros set up the variables in
+# ../make/cross.mk: BUILDCC, BUILDCFLAGS, BUILDCCLD etc. These are
+# near the end so people have some chance of seeing them.
+if test "$cross_compiling" = yes; then
+ if test -z "${BUILDCC}"; then
+ BUILDCC='cc'
+ fi
+ echo "$ac_t""setting \$BUILDCC to ${BUILDCC}" 1>&6
+else
+ if test -n "${BUILDCC}"; then
+ echo "configure: warning: \$BUILDCC set but not cross-compiling." 1>&2
+ fi
+ BUILDCC='$(CC)'
+fi
+
+
+if test "$cross_compiling" = yes; then
+ if test -z "${BUILDCFLAGS}"; then
+ BUILDCFLAGS='$(BUILDXCFLAGS)'
+ fi
+ echo "$ac_t""setting \$BUILDCFLAGS to ${BUILDCFLAGS}" 1>&6
+else
+ if test -n "${BUILDCFLAGS}"; then
+ echo "configure: warning: \$BUILDCFLAGS set but not cross-compiling." 1>&2
+ fi
+ BUILDCFLAGS='$(CFLAGS)'
+fi
+
+
+if test "$cross_compiling" = yes; then
+ if test -z "${BUILDCPPFLAGS}"; then
+ BUILDCPPFLAGS='$(BUILDXCPPFLAGS)'
+ fi
+ echo "$ac_t""setting \$BUILDCPPFLAGS to ${BUILDCPPFLAGS}" 1>&6
+else
+ if test -n "${BUILDCPPFLAGS}"; then
+ echo "configure: warning: \$BUILDCPPFLAGS set but not cross-compiling." 1>&2
+ fi
+ BUILDCPPFLAGS='$(CPPFLAGS)'
+fi
+
+
+if test "$cross_compiling" = yes; then
+ if test -z "${BUILDLDFLAGS}"; then
+ BUILDLDFLAGS='$(BUILDXLDFLAGS)'
+ fi
+ echo "$ac_t""setting \$BUILDLDFLAGS to ${BUILDLDFLAGS}" 1>&6
+else
+ if test -n "${BUILDLDFLAGS}"; then
+ echo "configure: warning: \$BUILDLDFLAGS set but not cross-compiling." 1>&2
+ fi
+ BUILDLDFLAGS='$(LDFLAGS)'
+fi
+
+
+if test "$cross_compiling" = yes; then
+ if test -z "${BUILDCCLD}"; then
+ BUILDCCLD='$(BUILDCC)'
+ fi
+ echo "$ac_t""setting \$BUILDCCLD to ${BUILDCCLD}" 1>&6
+else
+ if test -n "${BUILDCCLD}"; then
+ echo "configure: warning: \$BUILDCCLD set but not cross-compiling." 1>&2
+ fi
+ BUILDCCLD='$(CCLD)'
+fi
+
+
+
+ac_config_files="$ac_config_files Makefile gui/Makefile"
+
+ac_config_files="$ac_config_files xdvi-sh"
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+
+trap 'rm -fr `echo "$ac_config_files c-auto.h:c-auto.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@LN_S@%$LN_S%g
+s%@RANLIB@%$RANLIB%g
+s%@MAINT@%$MAINT%g
+s%@LD@%$LD%g
+s%@AR@%$AR%g
+s%@ARFLAGS@%$ARFLAGS%g
+s%@texmfmain@%$texmfmain%g
+s%@CPP@%$CPP%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+s%@X_CFLAGS@%$X_CFLAGS%g
+s%@X_PRE_LIBS@%$X_PRE_LIBS%g
+s%@X_LIBS@%$X_LIBS%g
+s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g
+s%@XTRA_WARN_CFLAGS@%$XTRA_WARN_CFLAGS%g
+s%@cflags_set@%$cflags_set%g
+s%@x_linker_options@%$x_linker_options%g
+s%@x_xmu_lib@%$x_xmu_lib%g
+s%@LDT1LIB@%$LDT1LIB%g
+s%@LIBT1CPPFLAGS@%$LIBT1CPPFLAGS%g
+s%@LDLIBT1@%$LDLIBT1%g
+s%@LIBT1DEP@%$LIBT1DEP%g
+s%@x_ext_lib@%$x_ext_lib%g
+s%@x_xpm_libs@%$x_xpm_libs%g
+s%@x_tool_libs@%$x_tool_libs%g
+s%@iconv_libpath@%$iconv_libpath%g
+s%@iconv_libs@%$iconv_libs%g
+s%@iconv_includes@%$iconv_includes%g
+s%@exec_name@%$exec_name%g
+s%@final_exec_name@%$final_exec_name%g
+s%@wrapper_script@%$wrapper_script%g
+s%@PS_DEF@%$PS_DEF%g
+s%@BUILDCC@%$BUILDCC%g
+s%@BUILDCFLAGS@%$BUILDCFLAGS%g
+s%@BUILDCPPFLAGS@%$BUILDCPPFLAGS%g
+s%@BUILDLDFLAGS@%$BUILDLDFLAGS%g
+s%@BUILDCCLD@%$BUILDCCLD%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"$ac_config_files"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*|[A-z]:/*) # Absolute path.
+ srcdir="$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ "") ;;
+ [/$]*|[A-z]:/*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ rm -f conftest.in
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%:% $ac_given_srcdir/%g" -e "s%^%$ac_given_srcdir/%"`
+ cat $ac_file_inputs > conftest.in
+ #
+ # Replace lines of the form ac_include foo with the contents of foo:
+ # first, from the ac_include lines construct a list of file names.
+ # From that list, we construct a second list of those files that exist.
+ # Then we construct lists of sed commands for including those files,
+ # and a sed command that removes the ac_include lines. We don't attempt
+ # to read non-existent files because some (buggy) versions of sed choke
+ # on this. Have to use sed because old (Ultrix, SunOS) awk does not support
+ # getline or system. (Anyway, configure scripts aren't supposed to use awk.)
+ # Can't use only one -e and commands {dr foo} because foo has to be last.
+ # Be careful, because the filename may contain /. Be careful with
+ # whitespace; we need to use echo.
+ #
+ file_substs=`sed -n '/^ac_include/s%ac_include[ ]*\(.*\)%\1%p' conftest.in`
+ # Create the sed command line ...
+ if test -n "$file_substs"; then
+ echo "configure: warning: ac_include is obsolete; instead use kpse_include" 1>&2
+ file_subst_cmd="sed -e 's/^ac_include/kpse_include/'"
+ else
+ file_subst_cmd='sed'
+ fi
+ kpse_substs=`sed -n '/^kpse_include/s%kpse_include[ ]*\(.*\)%\1%p' conftest.in`
+ for ac_inc in $file_substs $kpse_substs; do
+ if test -f "$ac_given_srcdir/$ac_inc"; then
+ ac_mung=`echo $ac_inc | sed 's,/,%,g'`
+ file_subst_cmd="$file_subst_cmd -e '/^kpse_include $ac_mung$/r $ac_given_srcdir/$ac_inc'"
+ fi
+ done
+ file_subst_cmd="$file_subst_cmd -e '/^kpse_include/d'"
+ # ... and fix the whitespace and escaped slashes.
+ file_subst_cmd=`echo "$file_subst_cmd" | sed -e 's,%,\\\/,g' \
+-e 's/kpse_include /kpse_include[ ]*/g'`
+ # I can't find any way to do variable substitution in the sed commands
+ # (so the user could have, e.g., $top_srcdir in their ac_include line).
+ (eval $file_subst_cmd conftest.in) \
+ | sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s* conftest.in
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ].*$%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS=" c-auto.h:c-auto.in"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%:% $ac_given_srcdir/%g" -e "s%^%$ac_given_srcdir/%"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+
+
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+date >stamp-auto
+
+
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+if test "$no_recursion" != yes; then
+
+ # Remove --cache-file and --srcdir arguments so they do not pile up.
+ ac_sub_configure_args=
+ ac_prev=
+ for ac_arg in $ac_configure_args; do
+ if test -n "$ac_prev"; then
+ ac_prev=
+ continue
+ fi
+ case "$ac_arg" in
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ ;;
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ ;;
+ *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;;
+ esac
+ done
+
+ for ac_config_dir in : $subdirs; do
+
+ # Do not complain, so a configure script can configure whichever
+ # parts of a large source tree are present.
+ if test ! -d $srcdir/$ac_config_dir; then
+ continue
+ fi
+
+ echo configuring in $ac_config_dir
+
+ case "$srcdir" in
+ .) ;;
+ *)
+ if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :;
+ else
+ { echo "configure: error: can not create `pwd`/$ac_config_dir" 1>&2; exit 1; }
+ fi
+ ;;
+ esac
+
+ ac_popdir=`pwd`
+ cd $ac_config_dir
+
+ # A "../" for each directory in /$ac_config_dir.
+ ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'`
+
+ case "$srcdir" in
+ .) # No --srcdir option. We are building in place.
+ ac_sub_srcdir=$srcdir ;;
+ /*|[A-z]:/*) # Absolute path.
+ ac_sub_srcdir=$srcdir/$ac_config_dir ;;
+ *) # Relative path.
+ ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;;
+ esac
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f ./configure; then
+ ac_sub_configure=./configure
+ elif test -f $ac_sub_srcdir/configure; then
+ ac_sub_configure=$ac_sub_srcdir/configure
+ elif test -f $ac_sub_srcdir/configure.in; then
+ ac_sub_configure=$ac_configure
+ else
+ echo "configure: warning: no configuration information is in $ac_config_dir" 1>&2
+ ac_sub_configure=
+ fi
+
+ # The recursion is here.
+ if test -n "$ac_sub_configure"; then
+
+ # Make the cache file name correct relative to the subdirectory.
+ case "$cache_file" in
+ /*|[A-z]:/*) ac_sub_cache_file=$cache_file ;;
+ *) # Relative path.
+ ac_sub_cache_file="$ac_dots$cache_file" ;;
+ esac
+ case "$ac_given_INSTALL" in
+ "") ;;
+ [/$]*|[A-z]:/*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo "running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir"
+ # The eval makes quoting arguments work.
+ if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir
+ then :
+ else
+ { echo "configure: error: $ac_sub_configure failed for $ac_config_dir" 1>&2; exit 1; }
+ fi
+ fi
+
+ cd $ac_popdir
+ done
+fi
+
diff --git a/Build/source/texk/xdvik/configure.in b/Build/source/texk/xdvik/configure.in
new file mode 100644
index 00000000000..445249640ee
--- /dev/null
+++ b/Build/source/texk/xdvik/configure.in
@@ -0,0 +1,289 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl e.g.:
+dnl /usr/bin/autoconf --macrodir=../etc/autoconf configure.in > configure
+dnl the macrodir argument is neccessary to make the non-standard `ac_include'
+dnl extension (acsite.m4) available to autoconf.
+AC_INIT(xdvi.c)
+AC_PREREQ(2.13)
+
+AC_CONFIG_HEADERS([c-auto.h:c-auto.in], [date >stamp-auto])
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_LN_S
+AC_PROG_RANLIB
+
+dnl allow for --program-suffix
+AC_ARG_PROGRAM
+
+sinclude(../kpathsea/withenable.ac)
+
+AC_FUNC_VFORK
+AC_FUNC_VPRINTF
+dnl begin additions SU, 2000/03/07
+dnl AC_FUNC_VSNPRINTF
+XDVI_FUNC_WORKING_VSNPRINTF
+AC_FUNC_MEMICMP
+dnl AC_FUNC_REALPATH
+AC_FUNC_ALLOCA
+AC_C_STRINGIZE
+dnl end additions SU
+AC_FUNC_MEMCMP
+AC_HEADER_SYS_WAIT
+AC_TYPE_SIGNAL
+AC_C_BIGENDIAN
+dnl Put here by Thomas Esser for teTeX. This causes some tests to be run
+dnl twice by the kps version.
+AC_PATH_XTRA
+AC_TYPE_SIZE_T
+
+dnl XDVI checks by Paul Vojta
+XDVI_FUNC_SETSID_IN_VFORK
+XDVI_CC_CONCAT
+XDVI_C_BITMAP_TYPE
+XDVI_SYS_STREAMS
+XDVI_SYS_SUNOS_4
+XDVI_SYS_OLD_LINUX
+XDVI_FUNC_POLL
+
+dnl SU: added flags to turn on gcc warnings, taken from gnome/compiler-flags.m4 and put into aclocal.m4
+COMPILER_WARNINGS
+
+dnl SU: for `--allow-multiple-definition' linker flag on Cygwin
+XDVI_LINKER_MULTIPLE_DEFNS
+
+AC_CHECK_HEADERS(stdint.h)
+
+AC_CHECK_TYPE(uint32_t, unsigned long)
+
+dnl These were probably missing from the test-set?
+dnl On the other hand, they are not used already, why start now? -janl
+dnl AC_TYPE_OFF_T
+dnl AC_HEADER_TIME
+
+AC_CHECK_FUNCS(mkstemp memcpy strerror waitpid sigaction strchr setenv ulltostr \
+ fchdir getcwd getpwnam getuid getpwuid \
+ iconv nl_langinfo \
+ lstat ftruncate snprintf vsnprintf realpath)
+
+dnl <sys/bsdtypes.h> is for ISC 4.0, to define fd_set in psgs.c.
+dnl regex.h is needed for regexp support in DVI search.
+AC_CHECK_HEADERS(netdb.h sys/bsdtypes.h sys/param.h unistd.h sys/fcntl.h regex.h iconv.h langinfo.h)
+
+cppflags_save=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+AC_CHECK_HEADERS(X11/Xosdefs.h X11/xpm.h Xm/XpmP.h)
+CPPFLAGS=$cppflags_save
+
+dnl For editres, we need to check both the header and define a linker option.
+cppflags_save=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+dnl The fourth argument below is ignored by autoconf-2.13,
+dnl but is required by autoconf-2.59
+AC_CHECK_HEADERS(X11/Intrinsic.h)
+AC_CHECK_HEADERS(X11/Xmu/Editres.h X11/Xmu/Xmu.h, x_xmu_lib=-lXmu, x_xmu_lib=,
+[#ifdef HAVE_X11_INTRINSIC_H
+# include <X11/Intrinsic.h>
+#endif
+])
+AC_SUBST(x_xmu_lib)
+CPPFLAGS=$cppflags_save
+
+dnl For the bitmap size. -- I think this is in XDVI_C_BITMAP_TYPE now -janl
+dnl AC_CHECK_SIZEOF(long)
+
+sinclude(../kpathsea/xt.ac)
+sinclude(withenable.ac)
+sinclude(../../libs/t1lib/withenable.ac)
+sinclude(../../libs/t1lib/t1lib.ac)
+
+dnl check for Xaw version
+XDVI_OLD_XAW
+
+dnl nl_langinfo checks
+AC_MSG_CHECKING(if nl_langinfo(CODESET) is working)
+AC_TRY_LINK([#include <langinfo.h>], [char* cs = nl_langinfo(CODESET);],
+ AC_DEFINE(HAVE_WORKING_NL_LANGINFO_CODESET) AC_MSG_RESULT(yes),
+ AC_MSG_RESULT(no)
+)
+
+dnl First, check for libXp and libXext:
+if test -z "$x_ext_lib"; then # allow envvar override
+ if test -n "$x_libraries"; then
+ XLFLAG="-L$x_libraries"
+ else
+ XLFLAG=
+ fi
+ AC_CHECK_LIB(Xp, XpQueryVersion,
+ x_ext_lib="-lXp -lXext", :, -lXext -lX11 $X_EXTRA_LIBS $XLFLAG)
+fi
+dnl
+dnl If libXp not found, try libXext only:
+dnl
+if test -z "$x_ext_lib"; then # previous test unsuccessful, or envvar override
+ if test -n "$x_libraries"; then
+ XLFLAG="-L$x_libraries"
+ else
+ XLFLAG=
+ fi
+ AC_CHECK_LIB(Xext, XextCreateExtension,
+ x_ext_lib=-lXext, :, -lX11 $X_EXTRA_LIBS $XLFLAG)
+fi
+AC_SUBST(x_ext_lib)
+
+dnl For --with-x-toolkit. Must be Xaw at least. If no --with-x-toolkit is given,
+dnl we try to check if Motif is available, and if yes, use it; else,
+dnl we use Xaw (--with-x-toolkit=xaw can be used to override this default).
+
+dnl Check whether -lXpm can be used
+XDVI_FIND_XPM
+
+dnl Check which X toolkit to use
+prog_extension="xaw"
+motif_include=
+motif_libdir=
+AC_ARG_WITH([motif-include],
+[ --with-motif-include=DIR
+ Specify the location of Motif include files],
+[motif_include="$withval"])
+AC_ARG_WITH([motif-libdir],
+[ --with-motif-libdir=DIR
+ Specify the location of Motif libraries],
+[motif_libdir="$withval"])
+
+if test "x$with_xdvi_x_toolkit" = xxaw3d; then
+ prog_extension="xaw3d"
+ x_tool_libs="-lXaw3d"
+elif test "x$with_xdvi_x_toolkit" = xneXtaw; then
+ prog_extension="nextaw"
+ x_tool_libs="-lneXtaw"
+elif test "x$with_xdvi_x_toolkit" = xmotif; then
+dnl Motif with no fallback
+dnl XDVI_FIND_MOTIF also defines $prog_extension, AC_DEFINE(toolkit) and $x_tool_libs
+ XDVI_FIND_MOTIF(none, "$motif_include", "$motif_libdir")
+elif test "x$with_xdvi_x_toolkit" = xxaw; then
+ prog_extension="xaw"
+ AC_DEFINE(XAW)
+ x_tool_libs="-lXaw"
+else
+dnl Motif with xaw as fallback
+dnl XDVI_FIND_MOTIF also defines $prog_extension, AC_DEFINE(toolkit) and $x_tool_libs
+ XDVI_FIND_MOTIF(Xaw, "$motif_include", "$motif_libdir")
+fi
+AC_SUBST(x_tool_libs)
+
+AC_ARG_WITH([iconv-libdir],
+[ --with-iconv-libdir=DIR
+ Specify the location of iconv library (librecode.so)],
+[if test XXX"$withval" != "XXX"; then
+ iconv_libpath="-L$withval"
+ iconv_libs="-lrecode"
+else
+ iconv_libpath=
+ iconv_libs=
+fi], [
+dnl On non-Linux systems, -liconv is needed. Check for both iconv_open and libiconv_open.
+iconv_libpath=
+iconv_libs=
+AC_CHECK_LIB(iconv, iconv_open, iconv_libs=-liconv,
+ AC_CHECK_LIB(iconv, libiconv_open, iconv_libs=-liconv,iconv_libs=,)
+ ,)
+])
+if test XXX"$iconv_libs" != "XXX"; then
+ AC_DEFINE(HAVE_ICONV)
+fi
+AC_SUBST(iconv_libpath)
+AC_SUBST(iconv_libs)
+
+AC_ARG_WITH([iconv-include],
+[ --with-iconv-include=DIR
+ Specify the location of iconv header (iconv.h)],
+[if test XXX"$withval" != "XXX"; then
+ iconv_includes="-I$withval"
+fi],[
+iconv_includes=
+])
+AC_SUBST(iconv_includes)
+
+XDVI_ICONV_CHAR_PPTR_TYPE
+
+dnl We try to perform the $program_transform_name replacement already
+dnl here, and AC_SUBST the final names into the Makefile; this makes
+dnl the compilation commands more readable and causes less problems with
+dnl backtick magic inside other commands.
+dnl
+dnl For some reason, the doubling of $$ and \\ must be reverted here:
+my_program_transform_name=`echo $program_transform_name | sed 's,\\$\\$,$,g' | sed 's,\\\\\\\\,\\\\,g'`
+exec_name="xdvi-$prog_extension.bin"
+final_exec_name=`echo $exec_name | sed "$my_program_transform_name"`
+wrapper_script=`echo xdvi | sed "$my_program_transform_name"`
+AC_SUBST(exec_name)
+AC_SUBST(final_exec_name)
+AC_SUBST(wrapper_script)
+
+dnl
+dnl Tests for different application setup features follow.
+dnl
+
+dnl For --with-ps.
+test -z "$PS_DEF" && PS_DEF=-DPS_GS
+test "$PS_DEF" = no && PS_DEF=
+AC_SUBST(PS_DEF)dnl
+dnl
+dnl If we're on Solaris and we want DPS, then add the extra compilation stuff
+dnl to get it.
+if echo "$PS_DEF" | grep PS_DPS >/dev/null; then
+ if test "`(uname) 2>/dev/null`" = SunOS \
+ && uname -r | grep '^5' >/dev/null; then
+ AC_MSG_RESULT(adding DPS includes and libraries for Solaris)
+ X_CFLAGS="$X_CFLAGS -I/usr/openwin/include/X11"
+ AC_CHECK_LIB(sunmath, isinf, ac_sunmath=-lsunmath, ac_sunmath="")
+ X_LIBS="$X_LIBS -R/usr/openwin/lib /usr/openwin/lib/libdps.so $ac_sunmath"
+ dnl We only need isinf and ieeefp.h to work around a Solaris bug in
+ dnl -ldps; see psdps.c. isinf is in -lsunmath.
+ AC_CHECK_FUNCS(isinf)
+ AC_CHECK_HEADERS(ieeefp.h)
+ else
+ dnl SunOS 4.x is simpler.
+ AC_MSG_RESULT(adding DPS includes and libraries for SunOS 4.x)
+ X_LIBS="$X_LIBS -ldps"
+ fi
+elif echo "$PS_DEF" | grep PS_NEWS >/dev/null; then
+ AC_MSG_RESULT(adding NeWS libraries)
+ X_LIBS="$X_LIBS -lxview -lcps -lolgx -lxvps"
+fi
+
+XDVI_ARG_STRING(default-dvips-path,
+[ --with-default-dvips-path=CMD
+ Use CMD as default DVI to PS converter],
+DEFAULT_DVIPS_PATH, "dvips")
+
+XDVI_ARG_STRING(default-ps2pdf-path,
+[ --with-default-ps2pdf-path=CMD
+ Use CMD as default PS to PDF converter],
+DEFAULT_PS2PDF_PATH, "ps2pdf")
+
+dnl ImageMagick support
+PS_DEF="$PS_DEF $MAGICK_DEF"
+if echo "$PS_DEF" | grep MAGICK >/dev/null; then
+ AC_MSG_RESULT(adding ImageMagick libraries)
+ X_EXTRA_LIBS="$X_EXTRA_LIBS `Magick-config --libs`"
+fi
+
+# needed for web2c later than 7.3.4:
+AC_CHECK_LIB(m, main)
+AC_C_CONST()
+
+# If you're cross-compiling, these macros set up the variables in
+# ../make/cross.mk: BUILDCC, BUILDCFLAGS, BUILDCCLD etc. These are
+# near the end so people have some chance of seeing them.
+KPSE_CROSS_BUILD_VAR(CC, cc)
+KPSE_CROSS_BUILD_VAR(CFLAGS, $(BUILDXCFLAGS))
+KPSE_CROSS_BUILD_VAR(CPPFLAGS, $(BUILDXCPPFLAGS))
+KPSE_CROSS_BUILD_VAR(LDFLAGS, $(BUILDXLDFLAGS))
+KPSE_CROSS_BUILD_VAR(CCLD, $(BUILDCC))
+
+KPSE_CONFIG_FILES([Makefile gui/Makefile])
+AC_CONFIG_FILES([xdvi-sh])
+AC_OUTPUT
diff --git a/Build/source/texk/xdvik/depend.mak b/Build/source/texk/xdvik/depend.mak
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Build/source/texk/xdvik/depend.mak
diff --git a/Build/source/texk/xdvik/depend.mk b/Build/source/texk/xdvik/depend.mk
new file mode 100644
index 00000000000..7733bcee015
--- /dev/null
+++ b/Build/source/texk/xdvik/depend.mk
@@ -0,0 +1,536 @@
+browser.o: browser.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ $(kpathsea_srcdir)/c-fopen.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ util.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ events.h \
+ browser.h \
+ string-utils.h my-vsnprintf.h
+dvi-draw.o: dvi-draw.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ $(kpathsea_srcdir)/c-fopen.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/magstep.h $(kpathsea_srcdir)/tex-file.h dvi.h string-utils.h \
+ my-vsnprintf.h util.h $(kpathsea_srcdir)/hash.h \
+ events.h x_util.h \
+ dvi-init.h hypertex.h \
+ special.h tfmload.h read-mapfile.h my-snprintf.h \
+ dvi-draw.h \
+ search-internal.h \
+ dvisel.h print-internal.h \
+ encodings.h \
+ pagehist.h psgs.h
+dvi-init.o: dvi-init.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvi-init.h dvi-draw.h util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ events.h x_util.h \
+ mime.h special.h hypertex.h \
+ $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/magstep.h $(kpathsea_srcdir)/tex-glyph.h \
+ dvi.h string-utils.h my-vsnprintf.h browser.h \
+ pagehist.h \
+ search-internal.h \
+ dvisel.h \
+ print-internal.h \
+ font-open.h
+dvisel.o: dvisel.c \
+ dvi.h \
+ xdvi.h xdvi-config.h c-auto.h \
+ xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvisel.h dvi-init.h print-internal.h \
+ util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ events.h dvi-draw.h
+encodings.o: encodings.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ events.h encodings.h my-snprintf.h
+events.o: events.c xdvi-config.h c-auto.h \
+ $(kpathsea_srcdir)/getopt.h \
+ xdvi.h \
+ xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ filehist.h special.h events.h \
+ psgs.h util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ x_util.h string-utils.h my-vsnprintf.h \
+ dvi-draw.h \
+ hypertex.h dvi-init.h \
+ browser.h search-internal.h \
+ dvisel.h print-internal.h my-snprintf.h \
+ encodings.h pagehist.h
+filehist.o: filehist.c \
+ xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h my-snprintf.h string-utils.h \
+ my-vsnprintf.h dvi-init.h \
+ filehist.h
+font-open.o: font-open.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvi-draw.h util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h my-snprintf.h \
+ font-open.h \
+ $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/tex-glyph.h
+gf.o: gf.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvi-init.h util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h
+hypertex.o: hypertex.c alloc-debug.h \
+ xdvi-config.h c-auto.h \
+ xdvi.h xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ $(kpathsea_srcdir)/c-fopen.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ events.h dvi-init.h \
+ util.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ x_util.h mime.h \
+ dvi-draw.h \
+ browser.h hypertex.h \
+ special.h string-utils.h my-vsnprintf.h \
+ my-snprintf.h pagehist.h
+image-magick.o: image-magick.c \
+ xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvi-init.h events.h dvi-draw.h util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ special.h \
+ image-magick.h
+mime.o: mime.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ hypertex.h util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h string-utils.h my-vsnprintf.h mime.h \
+ browser.h \
+ $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/variable.h
+my-snprintf.o: my-snprintf.c \
+ xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ my-vsnprintf.h my-snprintf.h
+my-vsnprintf.o: my-vsnprintf.c \
+ xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ my-vsnprintf.h
+pagehist.o: pagehist.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h string-utils.h my-vsnprintf.h \
+ dvi-init.h \
+ pagehist.h
+pk.o: pk.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvi-init.h util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h
+print-internal.o: print-internal.c xdvi-config.h c-auto.h xdvi.h \
+ xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvisel.h dvi-init.h print-internal.h \
+ search-internal.h \
+ events.h \
+ util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ x_util.h \
+ string-utils.h my-vsnprintf.h my-snprintf.h
+psdps.o: psdps.c
+psgs.o: psgs.c \
+ xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ psgs.h dvi-init.h dvi-draw.h events.h \
+ special.h util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h
+psheader.o: psheader.c
+psnews.o: psnews.c
+read-mapfile.o: read-mapfile.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h read-mapfile.h dvi-draw.h
+search-internal.o: search-internal.c xdvi-config.h c-auto.h xdvi.h \
+ xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ dvi-init.h dvi-draw.h search-internal.h \
+ dvisel.h \
+ print-internal.h \
+ events.h encodings.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ x_util.h string-utils.h my-vsnprintf.h \
+ pagehist.h
+special.o: special.c \
+ xdvi-config.h \
+ c-auto.h xdvi.h xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ $(kpathsea_srcdir)/c-fopen.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/line.h $(kpathsea_srcdir)/tex-file.h special.h events.h hypertex.h \
+ dvi.h dvi-init.h \
+ dvi-draw.h util.h \
+ $(kpathsea_srcdir)/hash.h \
+ image-magick.h \
+ my-snprintf.h string-utils.h \
+ my-vsnprintf.h psgs.h
+squeeze.o: squeeze.c \
+ $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/c-memstr.h
+string-utils.o: string-utils.c \
+ xdvi-config.h c-auto.h \
+ xdvi.h xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ string-utils.h my-vsnprintf.h util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ events.h
+tfmload.o: tfmload.c \
+ xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h tfmload.h
+util.o: util.c xdvi-config.h c-auto.h \
+ xdvi.h \
+ xdvi-debug.h version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ hypertex.h dvi-init.h special.h events.h \
+ string-utils.h my-vsnprintf.h $(kpathsea_srcdir)/tex-file.h util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ x_util.h \
+ search-internal.h \
+ dvisel.h \
+ print-internal.h \
+ encodings.h filehist.h
+vf.o: vf.c xdvi-config.h c-auto.h dvi.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h dvi-init.h dvi-draw.h
+xdvi.o: xdvi.c xdvi-config.h c-auto.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ events.h \
+ xserver-info.h $(kpathsea_srcdir)/c-fopen.h \
+ $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-ctype.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/proginit.h \
+ $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-hush.h $(kpathsea_srcdir)/tex-make.h \
+ string-utils.h my-vsnprintf.h $(kpathsea_srcdir)/expand.h translations.h \
+ dvi-init.h c-openmx.h x_util.h \
+ dvi-draw.h \
+ util.h $(kpathsea_srcdir)/hash.h \
+ my-snprintf.h hypertex.h pagehist.h filehist.h \
+ print-internal.h \
+ pixmaps/time16.xbm \
+ pixmaps/time16_mask.xbm pixmaps/magglass.xbm pixmaps/magglass_mask.xbm \
+ pixmaps/drag_vert.xbm pixmaps/drag_vert_mask.xbm pixmaps/drag_horiz.xbm \
+ pixmaps/drag_horiz_mask.xbm pixmaps/drag_omni.xbm \
+ pixmaps/drag_omni_mask.xbm
+xserver-info.o: xserver-info.c xdvi.h xdvi-config.h c-auto.h xdvi-debug.h \
+ version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xserver-info.h
+x_util.o: x_util.c xdvi-config.h c-auto.h \
+ x_util.h xdvi.h xdvi-debug.h version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/getopt.h \
+ $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ string-utils.h my-vsnprintf.h util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ events.h
diff --git a/Build/source/texk/xdvik/dvi-draw.c b/Build/source/texk/xdvik/dvi-draw.c
new file mode 100644
index 00000000000..12e4cabca73
--- /dev/null
+++ b/Build/source/texk/xdvik/dvi-draw.c
@@ -0,0 +1,6794 @@
+/* The rest of the code has the following copyright:
+
+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
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <stdarg.h>
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <setjmp.h>
+
+#define USE_HASH
+
+#include <ctype.h>
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+#include "kpathsea/magstep.h"
+#include "kpathsea/tex-file.h"
+#include "kpathsea/c-vararg.h"
+
+#include <string.h>
+
+#include "dvi.h"
+#include "string-utils.h"
+#include "util.h"
+#include "x_util.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "hypertex.h"
+#include "special.h"
+#include "tfmload.h"
+#include "read-mapfile.h"
+#include "my-snprintf.h"
+#include "kpathsea/tex-file.h"
+#include "mag.h"
+#include "message-window.h"
+
+#include "dvi-draw.h"
+#include "search-internal.h"
+#include "encodings.h"
+#include "pagesel.h"
+#include "pagehist.h"
+
+#ifdef RGB_ANTI_ALIASING
+#define TRACE_AA 0
+#define TRACE_AA1 1
+#define TRACE_AA3 0
+#else
+#define TRACE_AA 0
+#define TRACE_AA1 0
+#define TRACE_AA3 0
+#endif
+
+#define MY_DEBUG 1
+
+#if MY_DEBUG
+# define TRACE_FIND_VERBOSE(x) TRACE_FIND(x)
+#else
+# define TRACE_FIND_VERBOSE(x) /* as nothing */
+#endif
+
+#if PS && PS_GS
+#include "psgs.h"
+#endif /* PS && PS_GS */
+
+#ifdef DOPRNT /* define this if vfprintf gives you trouble */
+# define vfprintf(stream, message, args) _doprnt(message, args, stream)
+#endif
+
+#define BUF_SIZE 1024
+
+/*
+ * All calculations are done with shrink factor = 1, so we re-do some
+ * macros accordingly. Many of these are also defined in special.c.
+ */
+
+#define xpixel_conv(x) ((int) ((x) >> 16))
+#define xpixel_round(x) ((int) ROUNDUP(x, 1 << 16))
+
+#define G_PXL_H xpixel_conv(currinf.data.dvi_h)
+#define G_OFFSET_X (resource.xoffset_int << 16) + (3 << 15)
+#define G_OFFSET_Y (resource.yoffset_int << 16) + (3 << 15)
+
+#ifdef T1LIB
+/* hashing stuff to speed up checking whether a font or tfminfo file
+ has already been loaded.
+*/
+#define T1FONTS_INITIAL_HASHTABLE_SIZE 1031
+static hashTableT t1fonts_hash;
+static hashTableT tfminfo_hash;
+static hashTableT fontmaps_hash;
+static hashTableT font_warn_hash;
+
+typedef enum { FAILURE_BLANK = -2, FAILURE_PK = -1, SUCCESS = 0 } t1FontLoadStatusT;
+#endif
+
+#if PS
+int scanned_page_ps;
+int scanned_page_ps_bak;
+#endif
+
+#if COLOR
+int scanned_page_color;
+#endif
+
+int scanned_page_reset, scanned_page;
+
+struct drawinf currinf;
+Boolean htex_inside_href = False; /* whether we're inside a href */
+
+Boolean drawing_mag = False;
+
+#ifdef T1LIB
+
+# include "t1lib.h"
+
+/* Datastructures:
+
+ encodings[n]: Loaded from map file
+ [0] = 8r, <vector>
+ [1] = 8c, <vector>
+
+ The vectors are demand-loaded in 'load_encoded_font'
+*/
+
+struct encoding {
+ char *enc; /* This may be NULL. From dvips maps we get
+ encodings loaded by filename, and no name given */
+ char *file;
+ char **vector;
+};
+
+static struct encoding *encodings = NULL; /* Dynamic array = realloc when it gets full */
+static size_t enclidx = 0; /* global, for communication with find_T1_font */
+
+/*
+
+ t1fonts[n]: Built as xdvi loads t1 fonts
+ idx file short t1id loaded
+ [0] = /path/cmr10.pfb, cmr10 0 1
+ [1] = /path/prmr.pfa, prmr 1 0
+ [2] = /path/pcrr8a.pfa, pcrr8a 2 0
+
+ This array enumerates the loaded t1 fonts by full path name.
+ The integer `t1id' is the t1lib font id. The font will not be
+ extended/slanted/encoded. The `loaded' field indicates if
+ T1_LoadFont has been called for the font yet. Texfonts that need a
+ modified version of the t1 font must use T1_CopyFont to copy the
+ raw font and obtain the id of a new t1 font which can then be
+ modified. As described in the t1 docs a font must be loaded before
+ it can be copied.
+
+ Fonts that are copies of other fonts have NULL filenames. If any
+ font files are to be reused based on the file name, the raw font
+ must be reused, not a copy.
+
+ The `short' field contains the font as it was identified in the
+ fontmap. This is used to save searching; if two fonts are
+ identified the same way in the fontmap, they are the same font.
+
+*/
+
+struct t1font_info {
+ char *file;
+ char *shortname;
+ int t1id;
+ int loaded;
+};
+
+static struct t1font_info *t1fonts = NULL; /* Dynamic array */
+
+/*
+ fontmaps[n]: Loaded from map file, and extended with 'implied'
+ fonts as needed.
+ idx texname enc exten. slant filena. t1libid pathn. tfmidx
+ [0] = pcrr8rn 0 750 0 pcrr8a 2 ... 2
+ [1] = putro8r 0 0 0 putro8r 3 ... 3
+
+ The first 5 fields of this table are loaded from the font map
+ files, or filled out with default values when implied fonts are
+ set-up. The t1libid is -1 until the font is loaded or copied as
+ described under t1fonts. Once the dvi file reveals that the font
+ is needed, it is located on disk to ensure it exists, and the
+ pathname field is filled out. The t1 font is not loaded or
+ copied before it's needed because set_t1_char has been called to
+ draw a glyph from the font. The late loading is necessiated by the
+ high cost of loading fonts. If the font loading is concentrated at
+ startup of the program the startup-time becomes ecessively high due
+ to the high number of fonts used by the average LaTeX document.
+
+ A value of 0 for `extension'/`slant' means no extension/slant. If
+ the input values are decimal (less than 10) they're multiplied by
+ 1000 and 10000 respectively to obtain fixed-point integer values.
+ (This means that xdvi will translate entries like `0.81' to 810.)
+ Integer values have the advantage that they can be tested for
+ exact equality on all architectures.
+*/
+
+struct fontmap {
+ char *texname;
+ int enc; /* Index in encoding array */
+ int extension; /* Fixed point, *1000 */
+ int slant; /* Fixed point, *10000, some font slantings have 4
+ significant digits, all after the decimalpoint */
+ char *filename; /* Name of the t1 font file as given in map/dvi */
+
+ int t1libid; /* The t1lib id of this font, or -1 if not set up */
+ char *pathname; /* Full path of the font, once needed and located */
+ int tfmidx; /* Index in tfminfo array, or -1 */
+ Boolean warned_about; /* whether a warning message about this font has been displayed yet */
+ /*
+ if the font file was not readable for some reason (e.g. corrupt,
+ or encrypted for proprietry distribution), load_font_now() will
+ try to load a PK version via load_font() instead. If this is
+ successful, it will set force_pk to true, which will tell
+ get_t1_glyph() to return immediately, and just use the standard
+ set_char() routine to set the PK glyph. If even that fails,
+ get_t1_glyph() returns an error status in a special flag that's
+ evaluated by set_t1_char().
+ */
+ Boolean force_pk;
+};
+
+static struct fontmap *fontmaps = NULL;
+static size_t g_maplidx = 0; /* global, for communication with find_texfont */
+
+/*
+ widthinfo[n]: TFM width info, loaded on demand as the fonts are used.
+ idx texname widths
+ [0] = cmr10 ...
+ [1] = ptmr8r ...
+ [2] = pcrr8rn ...
+ [3] = putro8r ...
+
+ The widthinfo is loaded from the font tfm file because the type1
+ width information isn't precise enough to avoid accumulating
+ rounding errors that make things visibly misaligned. This is
+ esp. noticeable in tables (for the lines separating the columns).
+
+ For other than "design" sizes the widths are scaled up or down.
+
+*/
+
+struct tfminfos {
+ const char *texname;
+ long designsize;
+ long widths[256];
+ long fontdimen2; /* width of word spacing in this font */
+};
+
+static struct tfminfos *tfminfo = NULL;
+
+/* For file reading */
+# define BUFFER_SIZE 1024
+
+/* This is the conversion factor from TeXs pt to TeXs bp (big point).
+ Maximum machine precision is needed to keep it accurate. */
+/* UNUSED */
+/* static double bp_fac=72.0/72.27; */
+
+/* Try to convert from PS charspace units to DVI units with minimal
+ loss of significant digits */
+# define t1_dvi_conv(x) ((((int) (x)) << 16)/1000)
+/* Convert from DVI units to TeX pt */
+# define dvi_pt_conv(x) (((long) ((x)*dimconv)) >> 19)
+
+/* Convert from TFM units to DVI units */
+# define tfm_dvi_conv(x) (((int) (x)) >> 1)
+
+static Boolean padMismatch = False; /* Does t1lib padding match xdvi required padding? */
+static int archpad;
+# define T1PAD(bits, pad) (((bits) + (pad) - 1) & -(pad))
+
+static struct glyph *get_t1_glyph(
+# ifdef TEXXET
+ wide_ubyte cmd,
+# endif
+ wide_ubyte ch, t1FontLoadStatusT *flag,
+ Boolean is_geom_scan);
+
+# ifdef WORDS_BIGENDIAN
+unsigned char rbits[] = {
+ 0x00, /* 00000000 -> 00000000 */
+ 0x80, /* 00000001 -> 10000000 */
+ 0x40, /* 00000010 -> 01000000 */
+ 0xC0, /* 00000011 -> 11000000 */
+ 0x20, /* 00000100 -> 00100000 */
+ 0xA0, /* 00000101 -> 10100000 */
+ 0x60, /* 00000110 -> 01100000 */
+ 0xE0, /* 00000111 -> 11100000 */
+ 0x10, /* 00001000 -> 00010000 */
+ 0x90, /* 00001001 -> 10010000 */
+ 0x50, /* 00001010 -> 01010000 */
+ 0xD0, /* 00001011 -> 11010000 */
+ 0x30, /* 00001100 -> 00110000 */
+ 0xB0, /* 00001101 -> 10110000 */
+ 0x70, /* 00001110 -> 01110000 */
+ 0xF0, /* 00001111 -> 11110000 */
+ 0x08, /* 00010000 -> 00001000 */
+ 0x88, /* 00010001 -> 10001000 */
+ 0x48, /* 00010010 -> 01001000 */
+ 0xC8, /* 00010011 -> 11001000 */
+ 0x28, /* 00010100 -> 00101000 */
+ 0xA8, /* 00010101 -> 10101000 */
+ 0x68, /* 00010110 -> 01101000 */
+ 0xE8, /* 00010111 -> 11101000 */
+ 0x18, /* 00011000 -> 00011000 */
+ 0x98, /* 00011001 -> 10011000 */
+ 0x58, /* 00011010 -> 01011000 */
+ 0xD8, /* 00011011 -> 11011000 */
+ 0x38, /* 00011100 -> 00111000 */
+ 0xB8, /* 00011101 -> 10111000 */
+ 0x78, /* 00011110 -> 01111000 */
+ 0xF8, /* 00011111 -> 11111000 */
+ 0x04, /* 00100000 -> 00000100 */
+ 0x84, /* 00100001 -> 10000100 */
+ 0x44, /* 00100010 -> 01000100 */
+ 0xC4, /* 00100011 -> 11000100 */
+ 0x24, /* 00100100 -> 00100100 */
+ 0xA4, /* 00100101 -> 10100100 */
+ 0x64, /* 00100110 -> 01100100 */
+ 0xE4, /* 00100111 -> 11100100 */
+ 0x14, /* 00101000 -> 00010100 */
+ 0x94, /* 00101001 -> 10010100 */
+ 0x54, /* 00101010 -> 01010100 */
+ 0xD4, /* 00101011 -> 11010100 */
+ 0x34, /* 00101100 -> 00110100 */
+ 0xB4, /* 00101101 -> 10110100 */
+ 0x74, /* 00101110 -> 01110100 */
+ 0xF4, /* 00101111 -> 11110100 */
+ 0x0C, /* 00110000 -> 00001100 */
+ 0x8C, /* 00110001 -> 10001100 */
+ 0x4C, /* 00110010 -> 01001100 */
+ 0xCC, /* 00110011 -> 11001100 */
+ 0x2C, /* 00110100 -> 00101100 */
+ 0xAC, /* 00110101 -> 10101100 */
+ 0x6C, /* 00110110 -> 01101100 */
+ 0xEC, /* 00110111 -> 11101100 */
+ 0x1C, /* 00111000 -> 00011100 */
+ 0x9C, /* 00111001 -> 10011100 */
+ 0x5C, /* 00111010 -> 01011100 */
+ 0xDC, /* 00111011 -> 11011100 */
+ 0x3C, /* 00111100 -> 00111100 */
+ 0xBC, /* 00111101 -> 10111100 */
+ 0x7C, /* 00111110 -> 01111100 */
+ 0xFC, /* 00111111 -> 11111100 */
+ 0x02, /* 01000000 -> 00000010 */
+ 0x82, /* 01000001 -> 10000010 */
+ 0x42, /* 01000010 -> 01000010 */
+ 0xC2, /* 01000011 -> 11000010 */
+ 0x22, /* 01000100 -> 00100010 */
+ 0xA2, /* 01000101 -> 10100010 */
+ 0x62, /* 01000110 -> 01100010 */
+ 0xE2, /* 01000111 -> 11100010 */
+ 0x12, /* 01001000 -> 00010010 */
+ 0x92, /* 01001001 -> 10010010 */
+ 0x52, /* 01001010 -> 01010010 */
+ 0xD2, /* 01001011 -> 11010010 */
+ 0x32, /* 01001100 -> 00110010 */
+ 0xB2, /* 01001101 -> 10110010 */
+ 0x72, /* 01001110 -> 01110010 */
+ 0xF2, /* 01001111 -> 11110010 */
+ 0x0A, /* 01010000 -> 00001010 */
+ 0x8A, /* 01010001 -> 10001010 */
+ 0x4A, /* 01010010 -> 01001010 */
+ 0xCA, /* 01010011 -> 11001010 */
+ 0x2A, /* 01010100 -> 00101010 */
+ 0xAA, /* 01010101 -> 10101010 */
+ 0x6A, /* 01010110 -> 01101010 */
+ 0xEA, /* 01010111 -> 11101010 */
+ 0x1A, /* 01011000 -> 00011010 */
+ 0x9A, /* 01011001 -> 10011010 */
+ 0x5A, /* 01011010 -> 01011010 */
+ 0xDA, /* 01011011 -> 11011010 */
+ 0x3A, /* 01011100 -> 00111010 */
+ 0xBA, /* 01011101 -> 10111010 */
+ 0x7A, /* 01011110 -> 01111010 */
+ 0xFA, /* 01011111 -> 11111010 */
+ 0x06, /* 01100000 -> 00000110 */
+ 0x86, /* 01100001 -> 10000110 */
+ 0x46, /* 01100010 -> 01000110 */
+ 0xC6, /* 01100011 -> 11000110 */
+ 0x26, /* 01100100 -> 00100110 */
+ 0xA6, /* 01100101 -> 10100110 */
+ 0x66, /* 01100110 -> 01100110 */
+ 0xE6, /* 01100111 -> 11100110 */
+ 0x16, /* 01101000 -> 00010110 */
+ 0x96, /* 01101001 -> 10010110 */
+ 0x56, /* 01101010 -> 01010110 */
+ 0xD6, /* 01101011 -> 11010110 */
+ 0x36, /* 01101100 -> 00110110 */
+ 0xB6, /* 01101101 -> 10110110 */
+ 0x76, /* 01101110 -> 01110110 */
+ 0xF6, /* 01101111 -> 11110110 */
+ 0x0E, /* 01110000 -> 00001110 */
+ 0x8E, /* 01110001 -> 10001110 */
+ 0x4E, /* 01110010 -> 01001110 */
+ 0xCE, /* 01110011 -> 11001110 */
+ 0x2E, /* 01110100 -> 00101110 */
+ 0xAE, /* 01110101 -> 10101110 */
+ 0x6E, /* 01110110 -> 01101110 */
+ 0xEE, /* 01110111 -> 11101110 */
+ 0x1E, /* 01111000 -> 00011110 */
+ 0x9E, /* 01111001 -> 10011110 */
+ 0x5E, /* 01111010 -> 01011110 */
+ 0xDE, /* 01111011 -> 11011110 */
+ 0x3E, /* 01111100 -> 00111110 */
+ 0xBE, /* 01111101 -> 10111110 */
+ 0x7E, /* 01111110 -> 01111110 */
+ 0xFE, /* 01111111 -> 11111110 */
+ 0x01, /* 10000000 -> 00000001 */
+ 0x81, /* 10000001 -> 10000001 */
+ 0x41, /* 10000010 -> 01000001 */
+ 0xC1, /* 10000011 -> 11000001 */
+ 0x21, /* 10000100 -> 00100001 */
+ 0xA1, /* 10000101 -> 10100001 */
+ 0x61, /* 10000110 -> 01100001 */
+ 0xE1, /* 10000111 -> 11100001 */
+ 0x11, /* 10001000 -> 00010001 */
+ 0x91, /* 10001001 -> 10010001 */
+ 0x51, /* 10001010 -> 01010001 */
+ 0xD1, /* 10001011 -> 11010001 */
+ 0x31, /* 10001100 -> 00110001 */
+ 0xB1, /* 10001101 -> 10110001 */
+ 0x71, /* 10001110 -> 01110001 */
+ 0xF1, /* 10001111 -> 11110001 */
+ 0x09, /* 10010000 -> 00001001 */
+ 0x89, /* 10010001 -> 10001001 */
+ 0x49, /* 10010010 -> 01001001 */
+ 0xC9, /* 10010011 -> 11001001 */
+ 0x29, /* 10010100 -> 00101001 */
+ 0xA9, /* 10010101 -> 10101001 */
+ 0x69, /* 10010110 -> 01101001 */
+ 0xE9, /* 10010111 -> 11101001 */
+ 0x19, /* 10011000 -> 00011001 */
+ 0x99, /* 10011001 -> 10011001 */
+ 0x59, /* 10011010 -> 01011001 */
+ 0xD9, /* 10011011 -> 11011001 */
+ 0x39, /* 10011100 -> 00111001 */
+ 0xB9, /* 10011101 -> 10111001 */
+ 0x79, /* 10011110 -> 01111001 */
+ 0xF9, /* 10011111 -> 11111001 */
+ 0x05, /* 10100000 -> 00000101 */
+ 0x85, /* 10100001 -> 10000101 */
+ 0x45, /* 10100010 -> 01000101 */
+ 0xC5, /* 10100011 -> 11000101 */
+ 0x25, /* 10100100 -> 00100101 */
+ 0xA5, /* 10100101 -> 10100101 */
+ 0x65, /* 10100110 -> 01100101 */
+ 0xE5, /* 10100111 -> 11100101 */
+ 0x15, /* 10101000 -> 00010101 */
+ 0x95, /* 10101001 -> 10010101 */
+ 0x55, /* 10101010 -> 01010101 */
+ 0xD5, /* 10101011 -> 11010101 */
+ 0x35, /* 10101100 -> 00110101 */
+ 0xB5, /* 10101101 -> 10110101 */
+ 0x75, /* 10101110 -> 01110101 */
+ 0xF5, /* 10101111 -> 11110101 */
+ 0x0D, /* 10110000 -> 00001101 */
+ 0x8D, /* 10110001 -> 10001101 */
+ 0x4D, /* 10110010 -> 01001101 */
+ 0xCD, /* 10110011 -> 11001101 */
+ 0x2D, /* 10110100 -> 00101101 */
+ 0xAD, /* 10110101 -> 10101101 */
+ 0x6D, /* 10110110 -> 01101101 */
+ 0xED, /* 10110111 -> 11101101 */
+ 0x1D, /* 10111000 -> 00011101 */
+ 0x9D, /* 10111001 -> 10011101 */
+ 0x5D, /* 10111010 -> 01011101 */
+ 0xDD, /* 10111011 -> 11011101 */
+ 0x3D, /* 10111100 -> 00111101 */
+ 0xBD, /* 10111101 -> 10111101 */
+ 0x7D, /* 10111110 -> 01111101 */
+ 0xFD, /* 10111111 -> 11111101 */
+ 0x03, /* 11000000 -> 00000011 */
+ 0x83, /* 11000001 -> 10000011 */
+ 0x43, /* 11000010 -> 01000011 */
+ 0xC3, /* 11000011 -> 11000011 */
+ 0x23, /* 11000100 -> 00100011 */
+ 0xA3, /* 11000101 -> 10100011 */
+ 0x63, /* 11000110 -> 01100011 */
+ 0xE3, /* 11000111 -> 11100011 */
+ 0x13, /* 11001000 -> 00010011 */
+ 0x93, /* 11001001 -> 10010011 */
+ 0x53, /* 11001010 -> 01010011 */
+ 0xD3, /* 11001011 -> 11010011 */
+ 0x33, /* 11001100 -> 00110011 */
+ 0xB3, /* 11001101 -> 10110011 */
+ 0x73, /* 11001110 -> 01110011 */
+ 0xF3, /* 11001111 -> 11110011 */
+ 0x0B, /* 11010000 -> 00001011 */
+ 0x8B, /* 11010001 -> 10001011 */
+ 0x4B, /* 11010010 -> 01001011 */
+ 0xCB, /* 11010011 -> 11001011 */
+ 0x2B, /* 11010100 -> 00101011 */
+ 0xAB, /* 11010101 -> 10101011 */
+ 0x6B, /* 11010110 -> 01101011 */
+ 0xEB, /* 11010111 -> 11101011 */
+ 0x1B, /* 11011000 -> 00011011 */
+ 0x9B, /* 11011001 -> 10011011 */
+ 0x5B, /* 11011010 -> 01011011 */
+ 0xDB, /* 11011011 -> 11011011 */
+ 0x3B, /* 11011100 -> 00111011 */
+ 0xBB, /* 11011101 -> 10111011 */
+ 0x7B, /* 11011110 -> 01111011 */
+ 0xFB, /* 11011111 -> 11111011 */
+ 0x07, /* 11100000 -> 00000111 */
+ 0x87, /* 11100001 -> 10000111 */
+ 0x47, /* 11100010 -> 01000111 */
+ 0xC7, /* 11100011 -> 11000111 */
+ 0x27, /* 11100100 -> 00100111 */
+ 0xA7, /* 11100101 -> 10100111 */
+ 0x67, /* 11100110 -> 01100111 */
+ 0xE7, /* 11100111 -> 11100111 */
+ 0x17, /* 11101000 -> 00010111 */
+ 0x97, /* 11101001 -> 10010111 */
+ 0x57, /* 11101010 -> 01010111 */
+ 0xD7, /* 11101011 -> 11010111 */
+ 0x37, /* 11101100 -> 00110111 */
+ 0xB7, /* 11101101 -> 10110111 */
+ 0x77, /* 11101110 -> 01110111 */
+ 0xF7, /* 11101111 -> 11110111 */
+ 0x0F, /* 11110000 -> 00001111 */
+ 0x8F, /* 11110001 -> 10001111 */
+ 0x4F, /* 11110010 -> 01001111 */
+ 0xCF, /* 11110011 -> 11001111 */
+ 0x2F, /* 11110100 -> 00101111 */
+ 0xAF, /* 11110101 -> 10101111 */
+ 0x6F, /* 11110110 -> 01101111 */
+ 0xEF, /* 11110111 -> 11101111 */
+ 0x1F, /* 11111000 -> 00011111 */
+ 0x9F, /* 11111001 -> 10011111 */
+ 0x5F, /* 11111010 -> 01011111 */
+ 0xDF, /* 11111011 -> 11011111 */
+ 0x3F, /* 11111100 -> 00111111 */
+ 0xBF, /* 11111101 -> 10111111 */
+ 0x7F, /* 11111110 -> 01111111 */
+ 0xFF /* 11111111 -> 11111111 */
+};
+# endif /* WORDS_BIGENDIAN */
+#endif /* T1LIB */
+
+static struct frame frame0; /* dummy head of list */
+#ifdef TEXXET
+static struct frame *scan_frame; /* head frame for scanning */
+#endif
+
+static const char *const reverse_search_helptext =
+"Forward/reverse search allows you to jump from a point "
+"in the DVI file to the corresponding location in the .tex source file, and vice versa. "
+"To make this possible, the .tex file needs to be compiled with source special support. "
+"This can be done by using either a package like \"srcltx.sty\" or \"srctex.sty\", "
+"or a command-line switch like \"-src\" for the TeX executable. "
+"See the xdvi man page (section SOURCE SPECIALS) "
+"for more information about this.";
+
+static ubyte dvi_buffer[DVI_BUFFER_LEN];
+ubyte *G_dvi_buf_ptr = dvi_buffer;
+static struct frame *current_frame;
+
+/* Points to drawinf record containing current dvi file location (for update by
+ geom_scan). */
+static struct drawinf *dvi_pointer_frame = NULL;
+
+#ifdef TEXXET
+#define DIR currinf.dir
+#else
+#define DIR 1
+#endif
+
+/*
+ * Explanation of the following constant:
+ * offset_[xy] << 16: margin (defaults to one inch)
+ * currwin.shrinkfactor << 16: one pixel page border
+ * currwin.shrinkfactor << 15: rounding for pixel_conv
+ */
+#define OFFSET_X (resource.xoffset_int << 16) + (currwin.shrinkfactor * 3 << 15)
+#define OFFSET_Y (resource.yoffset_int << 16) + (currwin.shrinkfactor * 3 << 15)
+
+#if (BMBYTES == 1)
+bmUnitT bit_masks[] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff
+};
+#else
+#if (BMBYTES == 2)
+bmUnitT bit_masks[] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff, 0x1ff, 0x3ff, 0x7ff,
+ 0xfff, 0x1fff, 0x3fff, 0x7fff,
+ 0xffff
+};
+#else /* BMBYTES == 4 */
+bmUnitT bit_masks[] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff, 0x1ff, 0x3ff, 0x7ff,
+ 0xfff, 0x1fff, 0x3fff, 0x7fff,
+ 0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
+ 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
+ 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
+ 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+#endif
+#endif
+
+#ifdef VMS
+#define off_t int
+#endif
+extern off_t lseek();
+
+#ifndef SEEK_SET /* if <unistd.h> is not provided (or for <X11R5) */
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+static void draw_part(FILE *fp, struct frame *minframe, double current_dimconv);
+
+static void source_fwd_draw_box(void);
+
+
+
+/*
+ * X routines.
+ */
+
+/*
+ * Put a rectangle on the screen.
+ */
+static void
+put_rule(int x, int y, unsigned int w, unsigned int h)
+{
+ if (htex_inside_href)
+ htex_record_position(x, y, w, h);
+ if (x < globals.win_expose.max_x && x + (int)w >= globals.win_expose.min_x && y < globals.win_expose.max_y && y + (int)h >= globals.win_expose.min_y) {
+ if (--globals.ev.ctr == 0) {
+ if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
+/* fprintf(stderr, "longjmp1!\n"); */
+ longjmp(globals.ev.canit, 1);
+ }
+ }
+#if COLOR
+ if (fg_active != fg_current)
+ do_color_change();
+#endif
+ XFillRectangle(DISP, currwin.win,
+ globals.gc.rule,
+ x - currwin.base_x,
+ y - currwin.base_y,
+ w ? w : 1,
+ h ? h : 1);
+ }
+}
+
+static void
+put_bitmap(struct bitmap *bitmap, int x, int y)
+{
+ if (globals.debug & DBG_BITMAP)
+ printf("X(%d,%d)\n", x - currwin.base_x, y - currwin.base_y);
+ if (htex_inside_href)
+ htex_record_position(x, y, bitmap->w, bitmap->h);
+ if (x < globals.win_expose.max_x && x + (int)bitmap->w >= globals.win_expose.min_x &&
+ y < globals.win_expose.max_y && y + (int)bitmap->h >= globals.win_expose.min_y) {
+ if (--globals.ev.ctr == 0)
+ if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
+/* fprintf(stderr, "longjmp2!\n"); */
+ longjmp(globals.ev.canit, 1);
+ }
+#if COLOR
+ if (fg_active != fg_current)
+ do_color_change();
+#endif
+ G_image->width = bitmap->w;
+ G_image->height = bitmap->h;
+ G_image->data = bitmap->bits;
+ G_image->bytes_per_line = bitmap->bytes_wide;
+ XPutImage(DISP, currwin.win, globals.gc.fore, G_image,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y, bitmap->w, bitmap->h);
+ if (globals.gc.fore2) {
+ XPutImage(DISP, currwin.win, globals.gc.fore2, G_image,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ bitmap->w, bitmap->h);
+ }
+ }
+}
+
+#if GREY
+
+/* Anti-aliasing stuff.
+ The method used here is supersampling of the unshrunk glyph (this
+ also means that no anti-aliasing happens at shrink 1). A sample
+ of the number of bits that are `on' in the unsrunk glyph determines
+ the grey level of the shrunk image.
+*/
+
+/* Pixel lookup tables for anti-aliasing: These store all possible
+ supersampling values (i.e. number of bits set in the unshrunk
+ image) for the given shrink factor. E.g. at shrink level 2, the
+ size of the pixel table is 4; in other words, 1 pixel in the shrunk
+ image corresponds to 4 pixels in the unshrunk image. Thus, the possible
+ values for shink level 2 are: black, 1/4 (0x404040), 1/2 (0x808080),
+ 3/4 (0xc0c0c0) and white (0xffffff).
+*/
+static Pixel *pixeltbl;
+static Pixel *pixeltbl_gc2; /* drawing to globals.gc.fore2 (compare pixmap2_gc2) */
+
+static void shrink_glyph_grey(struct glyph *);
+
+static void
+put_image(struct glyph *g, int x, int y)
+{
+ XImage *img = g->image2;
+
+ if (htex_inside_href)
+ htex_record_position(x, y, img->width, img->height);
+ if (x < globals.win_expose.max_x && x + img->width >= globals.win_expose.min_x &&
+ y < globals.win_expose.max_y && y + img->height >= globals.win_expose.min_y) {
+ if (--globals.ev.ctr == 0)
+ if (read_events(EV_NOWAIT) & EV_GE_MAG_GONE) {
+/* fprintf(stderr, "longjmp3!\n"); */
+ longjmp(globals.ev.canit, 1);
+ }
+
+#if COLOR
+ if (g->fg != fg_current) /* if color change since last use */
+ shrink_glyph_grey(g);
+ else if (fg_active != fg_current) /* if GCs need updating */
+ do_color_change();
+#endif
+ /* TODO: Can we increase gamma locally to make the inverted text more readable?
+
+ and to draw the background, so something like this:
+ XFillRectangle(DISP, currwin.win, globals.gc.fore, x - currwin.base_x, y - currwin.base_y,
+ (unsigned int)img->width * 2, (unsigned int)img->height * 2);
+
+ test this with color changes!!
+ */
+ /*TEST_DELAY("check point 1 ...")*/
+ XPutImage(DISP, currwin.win, globals.gc.fore, img,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ (unsigned int)img->width, (unsigned int)img->height);
+ /*TEST_DELAY("check point 2 ...")*/
+
+ if (globals.gc.fore2 != NULL) {
+ img->data = g->pixmap2_gc2;
+ XPutImage(DISP, currwin.win, globals.gc.fore2, img,
+ 0, 0,
+ x - currwin.base_x, y - currwin.base_y,
+ (unsigned int)img->width, (unsigned int)img->height);
+ img->data = g->pixmap2;
+ }
+ /*TEST_DELAY("check point 3 ...")*/
+ }
+}
+#endif /* GREY */
+
+/*
+ * Draw the border of a rectangle on the screen.
+ * This should be replaced by a grey background both in Xaw and Motif
+ * as soon as #470325 is fixed (see also FIXED_FLUSHING_PAGING).
+ */
+static void
+draw_border(int x, int y, unsigned int width, unsigned int height, GC ourGC)
+{
+ --width;
+ --height;
+ XDrawRectangle(DISP, currwin.win, ourGC, x, y, width, height);
+}
+
+
+/*
+ * Byte reading routines for dvi file.
+ */
+
+#define xtell(fp, pos) (lseek(fileno(fp), 0L, SEEK_CUR) - \
+ (currinf.end - (pos)))
+
+static ubyte
+xxone(FILE *fp)
+{
+ if (currinf.virtual) {
+ ++currinf.pos;
+ return EOP;
+ }
+
+ currinf.end = G_dvi_buf_ptr
+ + read(fileno(fp), (char *)(currinf.pos = G_dvi_buf_ptr), DVI_BUFFER_LEN);
+ return currinf.end > G_dvi_buf_ptr ? *(currinf.pos)++ : EOF;
+}
+
+#define xone(fp) (currinf.pos < currinf.end ? *(currinf.pos)++ : xxone(fp))
+
+static unsigned long
+xnum(FILE *fp, ubyte size)
+{
+ long x = 0;
+
+ while (size--)
+ x = (x << 8) | xone(fp);
+ return x;
+}
+
+static long
+xsnum(FILE *fp, ubyte size)
+{
+ long x;
+
+#if __STDC__
+ x = (signed char)xone(fp);
+#else
+ x = xone(fp);
+ if (x & 0x80)
+ x -= 0x100;
+#endif
+ while (--size)
+ x = (x << 8) | xone(fp);
+ return x;
+}
+
+#define xsfour(fp) xsnum(fp, 4)
+
+static void
+xskip(FILE *fp, long offset)
+{
+ currinf.pos += offset;
+ if (!currinf.virtual && currinf.pos > currinf.end)
+ (void)lseek(fileno(fp), (long)(currinf.pos - currinf.end), SEEK_CUR);
+}
+
+void
+dvi_fmt_error(const char *message, ...)
+{
+
+ va_list args;
+ va_start(args, message);
+ fprintf(stderr, "%s: ", globals.program_name);
+ (void)vfprintf(stderr, message, args);
+ va_end(args);
+ if (currinf.virtual)
+ fprintf(stderr, " in virtual font %s\n", currinf.virtual->fontname);
+ else
+ fprintf(stderr, ", offset %ld\n", (long)xtell(globals.dvi_file.bak_fp, currinf.pos - 1));
+ /* #ifndef NDEBUG */
+ /* xdvi_exit(EXIT_FAILURE); */
+ /* #else */
+ XDVI_ABORT((stderr, "I'll abort now, to help you debugging this."));
+ /* #endif */
+}
+
+
+/*
+ * Code for debugging options.
+ */
+
+static void
+print_bitmap(struct bitmap *bitmap)
+{
+ bmUnitT *ptr = (bmUnitT *)bitmap->bits;
+ int x, y, i;
+
+ ASSERT(ptr != NULL, "Invalid bitmap bits");
+
+ printf("w = %d, h = %d, bytes wide = %d\n",
+ bitmap->w, bitmap->h, bitmap->bytes_wide);
+ for (y = 0; y < (int)bitmap->h; ++y) {
+ for (x = bitmap->bytes_wide; x > 0; x -= BMBYTES) {
+#ifdef WORDS_BIGENDIAN
+ for (i = BMBITS - 1; i >= 0; --i)
+ putchar((*ptr & (1 << i)) ? '@' : '.');
+#else
+ for (i = 0; i < BMBITS; ++i)
+ putchar((*ptr & (1 << i)) ? '@' : '.');
+#endif
+ ++ptr;
+ }
+ putchar('\n');
+ }
+}
+
+static void
+print_char(ubyte ch, struct glyph *g)
+{
+ printf("char %d", ch);
+ if (isprint(ch))
+ printf(" (%c)", ch);
+ putchar('\n');
+ printf("x = %d, y = %d, dvi = %ld\n", g->x, g->y, g->dvi_adv);
+ print_bitmap(&g->bitmap);
+}
+
+static const char *dvi_table1[] = {
+ "SET1", "SET2", NULL, NULL, "SETRULE", "PUT1", "PUT2", NULL,
+ NULL, "PUTRULE", "NOP", "BOP", "EOP", "PUSH", "POP", "RIGHT1",
+ "RIGHT2", "RIGHT3", "RIGHT4", "W0", "W1", "W2", "W3", "W4",
+ "X0", "X1", "X2", "X3", "X4", "DOWN1", "DOWN2", "DOWN3",
+ "DOWN4", "Y0", "Y1", "Y2", "Y3", "Y4", "Z0", "Z1",
+ "Z2", "Z3", "Z4"
+};
+
+static const char *dvi_table2[] = {
+ "FNT1", "FNT2", "FNT3", "FNT4", "XXX1", "XXX2", "XXX3", "XXX4",
+ "FNTDEF1", "FNTDEF2", "FNTDEF3", "FNTDEF4", "PRE", "POST", "POSTPOST",
+ "SREFL", "EREFL", NULL, NULL, NULL, NULL
+};
+
+static void
+print_dvi(ubyte ch)
+{
+ const char *s;
+
+ fprintf(stderr, "%4d %4d ", PXL_H, PXL_V);
+ if (ch <= (ubyte) (SETCHAR0 + 127)) {
+ fprintf(stderr, "SETCHAR%-3d", ch - SETCHAR0);
+ if (isprint(ch))
+ fprintf(stderr, " (%c)", ch);
+ fputc('\n', stderr);
+ return;
+ }
+ else if (ch < FNTNUM0)
+ s = dvi_table1[ch - 128];
+ else if (ch <= (ubyte) (FNTNUM0 + 63)) {
+ fprintf(stderr, "FNTNUM%d\n", ch - FNTNUM0);
+ return;
+ }
+ else
+ s = dvi_table2[ch - (FNTNUM0 + 64)];
+ if (s) {
+ fputs(s, stderr);
+ fputc('\n', stderr);
+ }
+ else
+ XDVI_FATAL((stderr, "print_dvi: unknown op-code %d", ch));
+}
+
+
+/*
+ * Count the number of set bits in a 4x4-region of the bitmap
+ */
+
+static char sample_count[] = {
+ 0, 1, 1, 2,
+ 1, 2, 2, 3,
+ 1, 2, 2, 3,
+ 2, 3, 3, 4
+};
+
+/*
+ * For greyscaling, return the number of bits that are set in a given region
+ * of width w and height h of the bitmap `bits', starting horizontally after
+ * `bit_skip' bits, where `bytes_wide' is the same as the `bytes_wide' field
+ * in the bitmap struct (scan line width in bytes).
+ * Note that `bits' is really a one-dimensional array, i.e. all the rows
+ * are put in sequence into one single row.
+ */
+static int
+sample(bmUnitT *bits, int bytes_wide, int bit_skip, int w, int h)
+{
+ bmUnitT *beg_ptr, *end_ptr, *curr_ptr;
+ int bits_left;
+ int n, bit_shift, wid;
+
+#if TRACE_AA
+ fprintf(stderr, "sample: %d bytes wide, %d skip, %d w, %d h\n", bytes_wide, bit_skip, w, h);
+#endif
+
+ beg_ptr = bits + bit_skip / BMBITS;
+ end_ptr = ADD(bits, h * bytes_wide);
+
+#if TRACE_AA
+ fprintf(stderr, "beg_ptr: %p, end: %p\n", (void *)beg_ptr, (void *)end_ptr);
+#endif
+
+ bits_left = w;
+#ifdef WORDS_BIGENDIAN
+ bit_shift = BMBITS - bit_skip % BMBITS;
+#else
+ bit_shift = bit_skip % BMBITS;
+#endif
+#if TRACE_AA
+ fprintf(stderr, "shift: %d\n", bit_shift);
+#endif
+ n = 0;
+
+ while (bits_left) {
+#ifdef WORDS_BIGENDIAN
+ wid = bit_shift;
+#else
+ wid = BMBITS - bit_shift;
+#endif
+ if (wid > bits_left)
+ wid = bits_left;
+ if (wid > 4) /* why? */
+ wid = 4;
+#ifdef WORDS_BIGENDIAN
+ bit_shift -= wid;
+#endif
+ for (curr_ptr = beg_ptr;
+ curr_ptr < end_ptr;
+ curr_ptr = ADD(curr_ptr, bytes_wide)) {
+#if TRACE_AA
+ int i;
+ for (i = 0; i < bytes_wide; i++) {
+ fprintf(stderr, "%d ", *(curr_ptr + i));
+ }
+ fprintf(stderr, "\nMask: %d; count: %d\n", wid,
+ sample_count[ (*curr_ptr >> bit_shift) & bit_masks[wid] ]);
+#endif
+ n += sample_count[ (*curr_ptr >> bit_shift) & bit_masks[wid] ];
+ }
+#ifdef WORDS_BIGENDIAN
+ if (bit_shift == 0) {
+ bit_shift = BMBITS;
+ ++beg_ptr;
+ }
+#else
+ bit_shift += wid;
+ if (bit_shift == BMBITS) {
+ bit_shift = 0;
+ ++beg_ptr;
+ }
+#endif
+ bits_left -= wid;
+ /* fprintf(stderr, "bits_left: %d\n", bits_left); */
+ }
+ return n;
+}
+
+static void
+shrink_glyph(struct glyph *g)
+{
+ int shrunk_bytes_wide, shrunk_height;
+ int rows_left, rows, init_cols;
+ int cols_left;
+ int cols;
+ bmUnitT *unshrunk_ptr, *shrunk_ptr;
+ bmUnitT m, *cp;
+ /* threshold for which a bit will be set to `on' in the shrunken bitmap */
+ int min_sample = currwin.shrinkfactor * currwin.shrinkfactor * resource.density / 100;
+ int row_num;
+
+ /* These machinations ensure that the character is shrunk according to
+ its hot point, rather than its upper left-hand corner. */
+ g->x2 = g->x / currwin.shrinkfactor;
+ init_cols = g->x - g->x2 * currwin.shrinkfactor;
+ if (init_cols <= 0)
+ init_cols += currwin.shrinkfactor;
+ else
+ ++g->x2;
+ g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
+ /* include row zero with the positively numbered rows */
+ row_num = g->y + 1;
+ g->y2 = row_num / currwin.shrinkfactor;
+ rows = row_num - g->y2 * currwin.shrinkfactor;
+ if (rows <= 0) {
+ rows += currwin.shrinkfactor;
+ --g->y2;
+ }
+ g->bitmap2.h = shrunk_height
+ = g->y2 + ROUNDUP((int)g->bitmap.h - row_num, currwin.shrinkfactor) + 1;
+ alloc_bitmap(&g->bitmap2);
+
+ unshrunk_ptr = (bmUnitT *) g->bitmap.bits;
+ shrunk_ptr = (bmUnitT *) g->bitmap2.bits;
+ shrunk_bytes_wide = g->bitmap2.bytes_wide;
+ rows_left = g->bitmap.h;
+ memset((char *)shrunk_ptr, '\0', shrunk_bytes_wide * shrunk_height);
+
+ while (rows_left) {
+ if (rows > rows_left)
+ rows = rows_left;
+ cols_left = g->bitmap.w;
+#ifndef WORDS_BIGENDIAN
+ m = 1; /* XXX was (1 << 0) */
+#else
+ m = ((bmUnitT)1 << (BMBITS - 1));
+#endif
+ cp = shrunk_ptr;
+ cols = init_cols;
+ while (cols_left) {
+ /* ??? */
+ if (cols > cols_left)
+ cols = cols_left;
+ /* set a bit to `on' if it's over the threshold */
+ if (sample(unshrunk_ptr, g->bitmap.bytes_wide,
+ (int)g->bitmap.w - cols_left, cols, rows)
+ >= min_sample)
+ *cp |= m;
+#ifndef WORDS_BIGENDIAN
+ if (m == ((bmUnitT)1 << (BMBITS - 1))) {
+ m = 1; /* XXX was (1 << 0) */
+ ++cp;
+ }
+ else
+ m <<= 1;
+#else
+ if (m == 1) { /* XXX was (1 << 0) */
+ m = ((bmUnitT)1 << (BMBITS - 1));
+ ++cp;
+ }
+ else
+ m >>= 1;
+#endif
+ cols_left -= cols;
+ cols = currwin.shrinkfactor;
+ }
+ shrunk_ptr += shrunk_bytes_wide / sizeof(bmUnitT);
+ unshrunk_ptr += rows * g->bitmap.bytes_wide / sizeof(bmUnitT);
+/* *((char **)&shrunk_ptr) += shrunk_bytes_wide; */
+/* *((char **)&unshrunk_ptr) += rows * g->bitmap.bytes_wide; */
+ rows_left -= rows;
+ rows = currwin.shrinkfactor;
+ }
+ g->y2 = g->y / currwin.shrinkfactor;
+ if (globals.debug & DBG_BITMAP)
+ print_bitmap(&g->bitmap2);
+}
+
+#ifdef GREY
+
+#ifdef RGB_ANTI_ALIASING
+/* void */
+/* filter_colors(Pixel *p1, Pixel *p2) */
+/* { */
+/* Pixel res1, res2; */
+
+/* int res1_r = *p1 & G_visual->red_mask; */
+/* int res1_g = *p1 & G_visual->green_mask; */
+/* int res1_b = *p1 & G_visual->blue_mask; */
+
+/* int res2_r = *p2 & G_visual->red_mask; */
+/* int res2_g = *p2 & G_visual->green_mask; */
+/* int res2_b = *p2 & G_visual->blue_mask; */
+/* } */
+
+static void
+color_filter_image(struct glyph *g)
+{
+ int rows = g->bitmap2.h;
+ int cols = g->bitmap2.w;
+ int i, j, k;
+ int arr_size = rows * cols * 3;
+ unsigned char *arr = xmalloc(arr_size * sizeof *arr);
+ unsigned char *arr2 = xmalloc(arr_size * sizeof *arr2);
+
+ fprintf(stderr, "total: %d\n", arr_size);
+
+ for (i = 0, j = 0; j < rows; j++) {
+ for (k = 0; k < cols; k++) {
+ Pixel p = XGetPixel(g->image2, k, j);
+#if TRACE_AA3
+ fprintf(stderr, "k: %d, j: %d, idx: %d\n", k, j, i);
+#endif
+ arr[i] = (p & G_visual->red_mask) >> 16;
+ arr[i + 1] = (p & G_visual->green_mask) >> 8;
+ arr[i + 2] = (p & G_visual->blue_mask);
+#if TRACE_AA3
+ fprintf(stderr, "0x%.6lX -> %d, %d, %d\n", p, arr[i], arr[i + 1], arr[i + 2]);
+#endif
+ i += 3;
+ }
+ }
+
+ for (i = 0; i < arr_size; i++) {
+ if (i == 0) { /* merge two elems */
+ if (i == arr_size - 1) /* only one elem, do nothing */
+ break;
+ arr2[i] = (int)(resource.subpixel_energy[0] * arr[i] +
+ resource.subpixel_energy[1] * arr[i + 1] + 0.5);
+ }
+ else if (i == arr_size - 1) { /* merge two elems */
+ if (i == 0) /* only one elem, do nothing */
+ break;
+ arr2[i] = (int)(resource.subpixel_energy[1] * arr[i - 1] +
+ resource.subpixel_energy[0] * arr[i] + 0.5);
+ }
+ else { /* merge three elems */
+ arr2[i] = (int)(resource.subpixel_energy[1] * arr[i - 1] +
+ resource.subpixel_energy[0] * arr[i] +
+ resource.subpixel_energy[1] * arr[i + 1] + 0.5);
+#if TRACE_AA3
+ fprintf(stderr, "%d, %d, %d -> %d\n", arr[i - 1], arr[i], arr[i + 1], arr2[i]);
+#endif
+ }
+ }
+
+ for (i = 0, j = 0; j < rows; j++) {
+ for (k = 0; k < cols; k++) {
+ Pixel p = arr2[i] << 16 | (arr2[i + 1] << 8) | arr2[i + 2];
+#if TRACE_AA3
+ fprintf(stderr, "%d, %d, %d -> 0x%.6lX\n", arr2[i], arr2[i + 1], arr2[i + 2], p);
+#endif
+ XPutPixel(g->image2, k, j, p);
+ i += 3;
+ }
+ }
+
+ free(arr);
+ free(arr2);
+}
+
+#endif
+
+static void
+shrink_glyph_grey(struct glyph *g)
+{
+ int rows_left, rows, init_cols;
+ int cols_left;
+ int cols;
+ int x, y;
+ long thesample;
+/* int min_sample = currwin.shrinkfactor * currwin.shrinkfactor * resource.density / 100; */
+ Pixel onoff, onoff2;
+ bmUnitT *unshrunk_ptr;
+ unsigned int size;
+ int row_num;
+ int actual_w;
+
+#if COLOR
+ if (fg_active != fg_current) {
+ do_color_change();
+ }
+#endif
+
+ /* TODO: rounding errors causing color fringing (see HACK comment below):
+
+ \documentclass{article}
+ \pagestyle{empty}
+
+ \begin{document}
+ l
+ \end{document}
+
+ With ./xdvi-xaw.bin -name xdvi -subpixel rgb -s 4 ./test.dvi:
+
+ subpixel order: rgb = 1
+ g->x2: 0, init_cols: -2
+ AFTER: g->x2: 0, init_cols: 2
+
+ but with ./xdvi-xaw.bin -name xdvi -s 4 ./test.dvi:
+
+ g->x2: 0, init_cols: -3
+ AFTER: g->x2: 0, init_cols: 1
+ */
+
+ /* These machinations ensure that the character is shrunk according to
+ its hot point, rather than its upper left-hand corner. */
+#ifdef RGB_ANTI_ALIASING
+ if (resource.subpixel_order == SUBPIXEL_NONE)
+ g->x2 = g->x / currwin.shrinkfactor;
+ else {
+ if (g->x < 0)
+ g->x2 = (int)(g->x / 3.0 - 0.5) / currwin.shrinkfactor;
+ else
+ g->x2 = (int)(g->x / 3.0 + 0.5) / currwin.shrinkfactor;
+ }
+
+ if (resource.subpixel_order == SUBPIXEL_NONE)
+ init_cols = g->x - g->x2 * currwin.shrinkfactor;
+ else {
+ if (g->x < 0)
+ init_cols = (int)(g->x / 3.0 - 0.5) - g->x2 * currwin.shrinkfactor;
+ else
+ init_cols = (int)(g->x / 3.0 + 0.5) - g->x2 * currwin.shrinkfactor;
+ fprintf(stderr, "g->x: %d, g->x2: %d, init_cols: %d\n", g->x, g->x2, init_cols);
+ }
+#else
+ g->x2 = g->x / currwin.shrinkfactor;
+ init_cols = g->x - g->x2 * currwin.shrinkfactor;
+#endif
+
+ if (init_cols <= 0)
+ init_cols += currwin.shrinkfactor;
+ else
+ ++(g->x2);
+
+#ifdef RGB_ANTI_ALIASING
+
+ if (resource.subpixel_order == SUBPIXEL_NONE)
+ g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
+ else {
+ fprintf(stderr, "AFTER: g->x2: %d, init_cols: %d\n", g->x2, init_cols);
+/* fprintf(stderr, "g->bitmap.w / 3.0 + 0.5: %d; g->x / 3.0: %d; all: %d, %d\n", */
+/* (int)(g->bitmap.w / 3.0 + 0.5), */
+/* (int)(g->x / 3.0), */
+/* (int)((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0), */
+/* g->x2 + (int)((((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0) + currwin.shrinkfactor - 1) / currwin.shrinkfactor)); */
+ g->bitmap2.w = g->x2 + ROUNDUP((int)((g->bitmap.w / 3.0 + 0.5) - g->x / 3.0), currwin.shrinkfactor);
+/* fprintf(stderr, "g->bitmap.w: %d\n", g->bitmap2.w); */
+ }
+#else
+ g->bitmap2.w = g->x2 + ROUNDUP((int)g->bitmap.w - g->x, currwin.shrinkfactor);
+#endif
+
+ /* include row zero with the positively numbered rows */
+ row_num = g->y + 1;
+#ifdef DBG_AA
+ fprintf(stderr, "row_num: %d\n", row_num);
+#endif /* DBG_AA */
+ /* g->y2 is the new height of the image: */
+ g->y2 = row_num / currwin.shrinkfactor;
+#ifdef DBG_AA
+ fprintf(stderr, "g->y2: %d\n", g->y2);
+#endif /* DBG_AA */
+ /* in C89 and before, result of division can `truncate towards negative infinity'
+ (i.e., round to the larger digit) for negative quotients, hence we need
+ to test for rows < 0. OTOH, if rows = 0, use currwin.shrinkfactor instead
+ (why?)
+ */
+ if ((rows = row_num - g->y2 * currwin.shrinkfactor) <= 0) {
+ rows += currwin.shrinkfactor;
+ --(g->y2);
+ }
+ g->bitmap2.h = g->y2 + ROUNDUP((int)g->bitmap.h - row_num, currwin.shrinkfactor) + 1;
+
+#if TRACE_AA1
+ if (resource.subpixel_order != SUBPIXEL_NONE) {
+ fprintf(stderr, "\nbitmap.h: %d, bitmap.w: %d\n", g->bitmap2.h, g->bitmap2.w);
+ }
+#endif /* DBG_AA */
+
+ /* allocate pixmap for antialiasing ... */
+ if (g->pixmap2 == NULL) {
+ g->image2 = XCreateImage(DISP, G_visual, G_depth, ZPixmap,
+ 0, (char *)NULL, g->bitmap2.w, g->bitmap2.h,
+ BMBITS, 0);
+ size = g->image2->bytes_per_line * g->bitmap2.h;
+ g->pixmap2 = g->image2->data = xmalloc(size != 0 ? size : 1);
+ }
+ /* ... and the pixmap used for globals.gc.fore2: */
+ if (globals.gc.fore2 != NULL && g->pixmap2_gc2 == NULL) {
+ size = g->image2->bytes_per_line * g->bitmap2.h;
+ g->pixmap2_gc2 = xmalloc(size != 0 ? size : 1);
+ }
+
+#if 0
+ if (resource.subpixel_order != SUBPIXEL_NONE) {
+ fprintf(stderr, "\n============= BITMAP ==============\n");
+ print_bitmap(&g->bitmap);
+ }
+#endif
+
+ unshrunk_ptr = (bmUnitT *)g->bitmap.bits;
+ actual_w = g->bitmap.w;
+ rows_left = g->bitmap.h;
+ y = 0;
+ /* the basic algorithm is the same as in the nogrey code, with the main
+ exception that the return value of sample() is used. */
+ while (rows_left) {
+#ifdef RGB_ANTI_ALIASING
+ Pixel pixel = 0;
+ Pixel pixel2 = 0;
+#endif
+ x = 0;
+ if (rows > rows_left) /* why - extra safety? */
+ rows = rows_left;
+ cols_left = g->bitmap.w;
+/* fprintf(stderr, "init_cols: %d\n", init_cols); */
+ cols = init_cols;
+ while (cols_left) {
+ if (cols > cols_left) /* why - extra safety? */
+ cols = cols_left;
+
+ thesample = sample(unshrunk_ptr, g->bitmap.bytes_wide,
+ (int)g->bitmap.w - cols_left, cols, rows);
+
+/* if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[2] != 0) */
+/* onoff = thesample >= min_sample ? 0xffffff : 0; */
+/* else */
+ onoff = pixeltbl[thesample];
+
+#ifdef XSERVER_INFO
+ if (globals.debug & DBG_PK) {
+ int c;
+/* fprintf(stderr, "onoff: %d\n", onoff); */
+ if (onoff > 65536)
+ c = onoff / 65536;
+ else if (onoff > 256)
+ c = onoff / 256;
+ else
+ c = onoff;
+ if (c == 0)
+ fprintf(stdout, ",..");
+ else
+ fprintf(stdout, ",%.2x", c);
+ }
+#endif
+
+#ifdef RGB_ANTI_ALIASING
+ if (resource.subpixel_order != SUBPIXEL_NONE) {
+ int div = x / 3;
+ int rest = x % 3;
+
+ if (resource.subpixel_order == SUBPIXEL_RGB) {
+ if (rest == 0)
+ pixel = onoff & G_visual->red_mask;
+ else if (rest == 1)
+ pixel |= onoff & G_visual->green_mask;
+ else
+ pixel |= onoff & G_visual->blue_mask;
+ }
+ else { /* SUBPIXEL_BGR */
+ if (rest == 0)
+ pixel = onoff & G_visual->blue_mask;
+ else if (rest == 1)
+ pixel |= onoff & G_visual->green_mask;
+ else
+ pixel |= onoff & G_visual->red_mask;
+ }
+
+#if 0 && TRACE_AA1
+ fprintf(stderr, "sample: %ld; row %d, col %d, left %d: 0x%.6lx; pixel: 0x%.6lx at pos %d,%d (x:%d)\n",
+ thesample, rows, cols, cols_left, onoff, pixel, div, y, x);
+#endif /* TRACE_AA */
+ fprintf(stderr, "pixel at %d\n", div);
+ XPutPixel(g->image2, div, y, pixel);
+
+ /* HACK to fix color fringing problem */
+ if (div + 1 < g->bitmap2.w) {
+ fprintf(stderr, "rest pixel at %d\n", div);
+ XPutPixel(g->image2, div + 1, y, 0);
+ }
+ }
+ else {
+#if 0 && TRACE_AA1
+ fprintf(stderr, "sample: %ld; row %d, col %d, left %d: 0x%.6lx at pos %d, %d\n",
+ thesample, rows, cols, cols_left, onoff, x, y);
+#endif /* TRACE_AA */
+ XPutPixel(g->image2, x, y, onoff);
+ }
+#else
+ XPutPixel(g->image2, x, y, onoff);
+#endif /* RGB_ANTI_ALIASING */
+ if (globals.gc.fore2 != NULL) {
+ onoff2 = pixeltbl_gc2[thesample];
+#ifdef RGB_ANTI_ALIASING
+ if (resource.subpixel_order != SUBPIXEL_NONE) {
+ int div = x / 3;
+ int rest = x % 3;
+
+ if (resource.subpixel_order == SUBPIXEL_RGB) {
+ if (rest == 0)
+ pixel2 = onoff2 & G_visual->red_mask;
+ else if (rest == 1)
+ pixel2 |= onoff2 & G_visual->green_mask;
+ else
+ pixel2 |= onoff2 & G_visual->blue_mask;
+ }
+ else { /* SUBPIXEL_BGR */
+ if (rest == 0)
+ pixel2 = onoff2 & G_visual->blue_mask;
+ else if (rest == 1)
+ pixel2 |= onoff2 & G_visual->green_mask;
+ else
+ pixel2 |= onoff2 & G_visual->red_mask;
+ }
+
+ g->image2->data = g->pixmap2_gc2;
+#if TRACE_AA1
+ fprintf(stderr, "fore2 at %d, %d\n", div, y);
+#endif
+ XPutPixel(g->image2, div, y, pixel2);
+ g->image2->data = g->pixmap2;
+ }
+ else {
+#else /* RGB_ANTI_ALIASING */
+ g->image2->data = g->pixmap2_gc2;
+ XPutPixel(g->image2, x, y, onoff2);
+ g->image2->data = g->pixmap2;
+#endif
+#ifdef RGB_ANTI_ALIASING
+ }
+#endif
+ }
+
+#if 0 && TRACE_AA1
+ fprintf(stderr, "subtracting %d from %d: %d\n", cols, cols_left, cols_left - cols);
+#endif
+ cols_left -= cols;
+ cols = currwin.shrinkfactor;
+ x++;
+ }
+ /* advance pointer by the number of rows covered */
+/* fprintf(stderr, "++: %d; %d, %d\n", rows * g->bitmap.bytes_wide, g->bitmap.bytes_wide, sizeof(bmUnitT)); */
+ unshrunk_ptr += rows * g->bitmap.bytes_wide / sizeof(bmUnitT);
+/* *((char **)&unshrunk_ptr) += rows * g->bitmap.bytes_wide; */
+ rows_left -= rows;
+ rows = currwin.shrinkfactor;
+ y++;
+#ifdef XSERVER_INFO
+ if (globals.debug & DBG_PK)
+ fprintf(stdout, "\n");
+#endif
+ }
+#ifdef XSERVER_INFO
+ if (globals.debug & DBG_PK)
+ fprintf(stdout, "\n");
+#endif
+
+#if 0
+ fprintf(stderr, "y: %d, bitmap.h: %d\n", y, (int)g->bitmap2.h);
+#endif /* DBG_AA */
+
+ /* fill remaining rows not covered before (how?) */
+ while (y < (int)g->bitmap2.h) {
+ for (x = 0; x < (int)g->bitmap2.w; x++) {
+/* int c = *pixeltbl; */
+#if TRACE_AA1
+ fprintf(stderr, "Remaining at %d, %d: 0x%.6lx\n", x, y, *pixeltbl);
+#endif
+ XPutPixel(g->image2, x, y, *pixeltbl);
+/* if (c == 0) */
+/* fprintf(stdout, ",.."); */
+/* else */
+/* fprintf(stdout, ",%.2x", c); */
+ if (globals.gc.fore2 != NULL) {
+ g->image2->data = g->pixmap2_gc2;
+#if TRACE_AA1
+ fprintf(stderr, "image2 at %d, %d: 0x%.6lx\n", x, y, *pixeltbl_gc2);
+#endif
+ XPutPixel(g->image2, x, y, *pixeltbl_gc2);
+ g->image2->data = g->pixmap2;
+ }
+ }
+ y++;
+ }
+
+#ifdef RGB_ANTI_ALIASING
+ if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[1] != 0)
+ color_filter_image(g);
+ if (resource.subpixel_order != SUBPIXEL_NONE && resource.subpixel_energy[2] != 0)
+ color_filter_image(g);
+#endif
+
+ g->y2 = g->y / currwin.shrinkfactor;
+#if COLOR
+ g->fg = fg_current;
+#endif
+}
+#endif /* GREY */
+
+/*
+ * Find font #n.
+ */
+
+static void
+change_font(unsigned long n)
+{
+ struct tn *tnp;
+
+ if (n < currinf.tn_table_len)
+ currinf.fontp = currinf.tn_table[n];
+ else {
+ currinf.fontp = NULL;
+ for (tnp = currinf.tn_head; tnp != NULL; tnp = tnp->next)
+ if (tnp->TeXnumber == n) {
+ currinf.fontp = tnp->fontp;
+ break;
+ }
+ }
+ if (currinf.fontp == NULL)
+ XDVI_FATAL((stderr, "Non-existent font number %ld", n));
+ if (currinf.fontp->set_char_p == NULL)
+ XDVI_FATAL((stderr, "No procedure to set font %ld, %s", n, currinf.fontp->fontname));
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+}
+
+
+/*
+ * Open a font file.
+ */
+
+static void
+open_font_file(struct font *fontp)
+{
+ if (fontp->file == NULL) {
+ fontp->file = XFOPEN(fontp->filename, OPEN_MODE);
+ if (fontp->file == NULL)
+ XDVI_FATAL((stderr, "Couldn't re-locate font file `%s'", fontp->filename));
+ }
+}
+
+/*
+ * Read and return a 0-terminated special string allocated in static memory
+ * (i.e. contents will be overwritten by next call of this function).
+ */
+
+static char *
+read_special(FILE *fp, long nbytes)
+{
+ static char *spcl = NULL;
+ static long spcl_len = -1;
+ char *p;
+
+ if (nbytes > spcl_len) {
+ spcl = xrealloc(spcl, (unsigned)nbytes + 1);
+ spcl_len = nbytes;
+ }
+ p = spcl;
+ for (;;) {
+ int i = currinf.end - currinf.pos;
+
+ if (i > nbytes)
+ i = nbytes;
+ memcpy(p, (char *)currinf.pos, i);
+ currinf.pos += i;
+ p += i;
+ nbytes -= i;
+ if (nbytes == 0)
+ break;
+ (void)xxone(fp);
+ --currinf.pos;
+ }
+ *p = '\0';
+ return spcl;
+}
+
+/*
+ * Table used for scanning. If >= 0, then skip that many bytes.
+ * M1 means end of page, M2 means special, M3 means FNTDEF,
+ * M4 means unrecognizable, and M5 means doesn't belong here.
+ */
+
+#define M1 255
+#define M2 254
+#define M3 253
+#define M4 252
+#define M5 251
+#define MM 251
+
+static ubyte scantable[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* chars 0 - 127 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, /* SET1,SET2 (128,129) */
+ /* -,-,SETRULE,PUT1,PUT2,-,-,PUTRULE,NOP,BOP (130-139) */
+ M4, M4, 8, 1, 2, M4, M4, 8, 0, 44,
+ M1, 0, 0, 1, 2, 3, 4, 0, 1, 2, /* EOP,PUSH,POP,RIGHT1-4,W0M2 (140-149) */
+ 3, 4, 0, 1, 2, 3, 4, 1, 2, 3, /* W3-4,X0-4,DOWN1-3 (150-159) */
+ 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, /* DOWN4,Y0-4,Z0-3 (160-169) */
+ 4, /* Z4 (170) */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* change font 171 - 234 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 2, 3, 4, M2, /* FNT1-4,XXX1 (235-239) */
+ /* XXX2-4,FNTDEF1-4,PRE,POST,POSTPOST (240-249) */
+ M2, M2, M2, M3, M3, M3, M3, M5, M5, M5,
+ 0, 0, M4, M4, M4, M4
+}; /* SREFL,EREFL,-,-,-,- (250-255) */
+
+/*
+ * This is the generic scanning routine. It assumes that currinf, etc.
+ * are ready to go at the start of the page to be scanned.
+ */
+
+
+
+Boolean
+spcl_scan(Boolean (*spcl_proc)(char *str, int str_len, void *data), void *data, Boolean return_if_found, FILE *fp)
+{
+ ubyte ch;
+ ubyte n;
+ long a;
+
+ for (;;) {
+ ch = xone(fp);
+/* print_dvi(ch); */
+ n = scantable[ch];
+ if (n < MM)
+ while (n-- != 0)
+ (void)xone(fp);
+ else if (n == M1)
+ break; /* end of page */
+ else
+ switch (n) {
+ case M2: /* special */
+ a = xnum(fp, ch - XXX1 + 1);
+ if (a > 0) {
+ if (spcl_proc(read_special(fp, a), a, data) && return_if_found) {
+ return True;
+ }
+ }
+ break;
+ case M3: /* FNTDEF */
+ xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
+ ch = xone(fp);
+ xskip(fp, (long)ch + (long)xone(fp));
+ break;
+ case M4: /* unrecognizable */
+ XDVI_FATAL((stderr, "unknown op-code %d", ch));
+ break;
+ case M5: /* doesn't belong */
+ dvi_fmt_error("spcl_scan: shouldn't happen: %s encountered",
+ dvi_table2[ch - (FNTNUM0 + 64)]);
+ break;
+ }
+ }
+ return False;
+}
+
+#define xspell_conv(n) spell_conv0(n, current_dimconv)
+
+/*
+ * Prescanning routine for dvi file. This looks for specials like
+ * `header=' and `!'.
+ */
+
+void
+prescan(FILE *fp)
+{
+ if (fp == NULL) {
+ return;
+ }
+
+ TRACE_FILES((stderr, "prescan on %p", (void *)fp));
+
+ (void)lseek(fileno(fp), pageinfo_get_offset(scanned_page + 1), SEEK_SET);
+ G_dvi_buf_ptr = dvi_buffer;
+ currinf.pos = currinf.end = G_dvi_buf_ptr;
+ for (;;) {
+ if (scanned_page == -1) { /* on first page */
+ TRACE_FILES((stderr, "prescan on page 1"));
+ pageinfo_set_page_width(scanned_page + 1, pageinfo_get_page_width(total_pages));
+ pageinfo_set_page_height(scanned_page + 1, pageinfo_get_page_height(total_pages));
+ pageinfo_set_window_width(scanned_page + 1, pageinfo_get_window_width(total_pages));
+ pageinfo_set_window_height(scanned_page + 1, pageinfo_get_window_height(total_pages));
+ }
+ else {
+ TRACE_FILES((stderr, "prescan on page %d", scanned_page));
+ pageinfo_set_page_width(scanned_page + 1, pageinfo_get_page_width(scanned_page));
+ pageinfo_set_page_height(scanned_page + 1, pageinfo_get_page_height(scanned_page));
+ pageinfo_set_window_width(scanned_page + 1, pageinfo_get_window_width(scanned_page));
+ pageinfo_set_window_height(scanned_page + 1, pageinfo_get_window_height(scanned_page));
+ }
+ if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE) {
+ break;
+ }
+ /* NOTE: longjmp(globals.ev.canit) should not be done within
+ read_events(). */
+ htex_prescan_save();
+ htex_prescan_initpage();
+
+ if (!setjmp(globals.ev.canit)) {
+ struct htex_prescan_data data;
+ int pre_depth, depth;
+ data.pageno = scanned_page + 1;
+ data.scan_type = HTEX_ANCHOR_NUM; /* just for the anchor numbers */
+ pre_depth = htex_prescan_get_depth();
+ (void)spcl_scan(scan_special, &data, False, fp);
+
+ depth = htex_prescan_get_depth();
+
+ if (depth > pre_depth) {
+ /* we have a mismatched anchor. We currently don't deal with
+ _nested_ mismatched anchors (ugh), so there's only one
+ anchor string that can be used as info on the next page. */
+ int anchor_num = htex_prescan_get_mismatched_anchor_num(depth);
+ /* scan again to find the anchor string at anchor number `anchor_num' */
+ (void)lseek(fileno(fp), pageinfo_get_offset(scanned_page + 1), SEEK_SET);
+ currinf.pos = currinf.end = G_dvi_buf_ptr;
+ data.anchor_num = anchor_num;
+ data.scan_type = HTEX_ANCHOR_STRING;
+ htex_prescan_reset_firstpass();
+ (void)spcl_scan(scan_special, &data, False, fp);
+ depth = htex_prescan_get_depth();
+ }
+ else if (depth > 0 && scanned_page >= 0) { /* mismatch was on a previous page */
+ htex_prescan_carry_over(scanned_page, scanned_page + 1);
+ }
+ }
+ else { /* if interrupted */
+ htex_prescan_restore(scanned_page + 1);
+#if PS
+ psp.interrupt();
+#endif
+ break;
+ }
+ if (globals.ev.flags & EV_GE_NEWPAGE)
+ break;
+ ++scanned_page;
+#if COLOR
+ if (scanned_page_color < scanned_page) {
+ scan_color_eop();
+ scanned_page_color = scanned_page;
+ }
+#endif
+#if PS
+ if (scanned_page_ps < scanned_page)
+ scanned_page_ps = scanned_page;
+#endif
+ if (scanned_page >= current_page)
+ break;
+ }
+
+#if PS
+ if (!(globals.ev.flags & EV_GE_NEWPAGE))
+ psp.endheader();
+#endif
+}
+
+/*
+ * Routines to print characters.
+ */
+
+setcharRetvalT
+set_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch)
+{
+ struct glyph *g;
+#ifdef TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar)
+ realloc_font(currinf.fontp, (wide_ubyte)ch);
+ if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
+ if (g->addr == 0) {
+ if (!resource.hush_chars)
+ XDVI_WARNING((stderr, "Character %d not defined in font %s", ch, currinf.fontp->fontname));
+ g->addr = -1;
+#ifdef TEXXET
+ return;
+#else
+ return 0L;
+#endif
+ }
+ if (g->addr == -1) {
+#ifdef TEXXET
+ return;
+#else
+ return 0L; /* previously flagged missing char */
+#endif
+ }
+ open_font_file(currinf.fontp);
+ fseek(currinf.fontp->file, g->addr, SEEK_SET);
+ (*currinf.fontp->read_char) (currinf.fontp, ch);
+ if (globals.debug & DBG_BITMAP)
+ print_char((ubyte) ch, g);
+ currinf.fontp->timestamp = ++current_timestamp;
+ }
+
+#ifdef TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= g->dvi_adv;
+
+ if (scan_frame == NULL) {
+#endif
+
+#ifdef RGB_ANTI_ALIASING
+ if (currwin.shrinkfactor == -1) {
+ put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
+ }
+#ifdef __GNUC__
+#warning TODO: implement horizontal AA at shrink 1
+#endif
+#else
+ if (currwin.shrinkfactor == 1) {
+ put_bitmap(&g->bitmap, PXL_H - g->x, PXL_V - g->y);
+ }
+#endif
+ else {
+#ifdef GREY
+ if (resource.use_grey) {
+ if (g->pixmap2 == NULL) {
+#ifdef DBG_AA
+ fprintf(stderr, "shinking the bitmap!\n");
+#endif /* DBG_AA */
+/* print_bitmap(&g->bitmap); */
+ shrink_glyph_grey(g);
+ }
+ put_image(g, PXL_H - g->x2, PXL_V - g->y2);
+ }
+ else {
+ if (g->bitmap2.bits == NULL) {
+ shrink_glyph(g);
+ }
+ put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
+ }
+#else
+ if (g->bitmap2.bits == NULL) {
+ shrink_glyph(g);
+ }
+ put_bitmap(&g->bitmap2, PXL_H - g->x2, PXL_V - g->y2);
+#endif
+ }
+#ifdef TEXXET
+ }
+ if (cmd == PUT1 || (resource.omega && cmd == PUT2))
+ DVI_H = dvi_h_sav;
+ else if (currinf.dir > 0)
+ DVI_H += g->dvi_adv;
+ return;
+#else
+ return g->dvi_adv;
+#endif
+}
+
+/*
+ * Routines to print characters.
+ */
+
+static setcharRetvalT
+set_empty_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch)
+{
+#ifdef TEXXET
+ UNUSED(cmd);
+#endif
+ UNUSED(ch);
+#ifdef TEXXET
+ return;
+#else
+ return 0L;
+#endif
+}
+
+setcharRetvalT
+load_n_set_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch)
+{
+ if (!load_font(currinf.fontp, resource.t1lib)) { /* if not found */
+ if (globals.ev.flags & EV_GE_NEWDOC) { /* if abort */
+ longjmp(globals.ev.canit, 1);
+ }
+
+ /* FIXME: does this need to be replaced by GUI warning, or has this case already been covered? */
+ XDVI_WARNING((stderr, "load_n_set_char: Character(s) will be left blank."));
+ currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
+
+#ifdef TEXXET
+ return;
+#else
+ return 0L;
+#endif
+ }
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+#ifdef TEXXET
+ (*currinf.set_char_p) (cmd, ch);
+ return;
+#else
+ return (*currinf.set_char_p) (ch);
+#endif
+}
+
+setcharRetvalT
+set_vf_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch)
+{
+ struct macro *m;
+ struct drawinf oldinfo;
+ wide_ubyte oldmaxchar;
+ static ubyte c;
+#ifdef TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar)
+ realloc_virtual_font(currinf.fontp, ch);
+ if ((m = &currinf.fontp->macro[ch])->pos == NULL) {
+ if (!resource.hush_chars)
+ XDVI_WARNING((stderr, "Character %d not defined in font %s", ch, currinf.fontp->fontname));
+ m->pos = m->end = &c;
+#ifdef TEXXET
+ return;
+#else
+ return 0L;
+#endif
+ }
+#ifdef TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= m->dvi_adv;
+ if (scan_frame == NULL) {
+#endif
+ oldinfo = currinf;
+ if (!currinf.virtual)
+ dvi_pointer_frame = &oldinfo;
+ oldmaxchar = maxchar;
+ WW = XX = YY = ZZ = 0;
+ currinf.tn_table_len = VFTABLELEN;
+ currinf.tn_table = currinf.fontp->vf_table;
+ currinf.tn_head = currinf.fontp->vf_chain;
+ currinf.pos = m->pos;
+ currinf.end = m->end;
+ currinf.virtual = currinf.fontp;
+
+ draw_part(globals.dvi_file.bak_fp, current_frame, currinf.fontp->dimconv);
+ if (currinf.pos != currinf.end + 1)
+ dvi_fmt_error("virtual character macro does not end correctly");
+ currinf = oldinfo;
+ if (!currinf.virtual)
+ dvi_pointer_frame = &currinf;
+ maxchar = oldmaxchar;
+#ifdef TEXXET
+ }
+ if (cmd == PUT1 || (resource.omega && cmd == PUT2))
+ DVI_H = dvi_h_sav;
+ else if (currinf.dir > 0)
+ DVI_H += m->dvi_adv;
+ return;
+#else
+ return m->dvi_adv;
+#endif
+}
+
+static setcharRetvalT
+set_no_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch)
+{
+ if (currinf.virtual) {
+ currinf.fontp = currinf.virtual->first_font;
+ if (currinf.fontp != NULL) {
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+#ifdef TEXXET
+ (*currinf.set_char_p) (cmd, ch);
+ return;
+#else
+ return (*currinf.set_char_p) (ch);
+#endif
+ }
+ }
+ dvi_fmt_error("set_no_char: attempt to set character of unknown font");
+ exit(0);
+ /* NOTREACHED */
+}
+
+
+/*
+ * Set rule. Arguments are coordinates of lower left corner.
+ */
+
+static void
+set_rule(int h, int w)
+{
+#ifdef TEXXET
+ put_rule(PXL_H - (currinf.dir < 0 ? w - 1 : 0), PXL_V - h + 1,
+ (unsigned int)w, (unsigned int)h);
+#else
+ put_rule(PXL_H, PXL_V - h + 1, (unsigned int)w, (unsigned int)h);
+#endif
+}
+
+
+/*
+ * Interpret a sequence of dvi bytes (either the page from the dvi file,
+ * or a character from a virtual font).
+ */
+
+static void
+draw_part(FILE *fp, struct frame *minframe, double current_dimconv)
+{
+ ubyte ch = 0;
+#ifdef TEXXET
+ struct drawinf oldinfo;
+ ubyte oldmaxchar = 0;
+ off_t file_pos = 0;
+ int refl_count = 0;
+#endif
+ int pause_cnt = 0;
+
+ globals.pausing.flag = False;
+
+ currinf.fontp = NULL;
+ currinf.set_char_p = set_no_char;
+#ifdef TEXXET
+ currinf.dir = 1;
+ scan_frame = NULL; /* indicates we're not scanning */
+#endif
+
+ for (;;) {
+ ch = xone(fp);
+ if (globals.debug & DBG_DVI) {
+ print_dvi(ch);
+ }
+ if (ch <= (ubyte)(SETCHAR0 + 127)) {
+#ifdef TEXXET
+ (*currinf.set_char_p) (ch, ch);
+#else
+ DVI_H += (*currinf.set_char_p) (ch);
+#endif
+ }
+ else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) {
+ change_font((unsigned long)(ch - FNTNUM0));
+ }
+ else {
+ long a, b;
+
+ switch (ch) {
+ case SET1:
+ case PUT1:
+#ifdef TEXXET
+ (*currinf.set_char_p) (ch, xone(fp));
+#else
+ a = (*currinf.set_char_p) (xone(fp));
+ if (ch != PUT1)
+ DVI_H += a;
+#endif
+ break;
+
+ case SET2:
+ case PUT2:
+ if (!resource.omega)
+ dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
+ __FILE__, __LINE__, ch);
+ else {
+#ifdef TEXXET
+ (*currinf.set_char_p) (ch, xnum(fp, 2));
+#else
+ a = (*currinf.set_char_p) (xnum(fp, 2));
+ if (ch != PUT2)
+ DVI_H += a;
+#endif
+ }
+ break;
+
+ case SETRULE:
+ /* Be careful, dvicopy outputs rules with
+ height = 0x80000000. We don't want any
+ SIGFPE here. */
+ a = xsfour(fp);
+ b = xspell_conv(xsfour(fp));
+ if (a > 0 && b > 0
+#ifdef TEXXET
+ && scan_frame == NULL
+#endif
+ ) {
+ set_rule(pixel_round(xspell_conv(a)), pixel_round(b));
+ }
+ DVI_H += DIR * b;
+ break;
+
+ case PUTRULE:
+ a = xspell_conv(xsfour(fp));
+ b = xspell_conv(xsfour(fp));
+ if (a > 0 && b > 0
+#ifdef TEXXET
+ && scan_frame == NULL
+#endif
+ ) {
+ set_rule(pixel_round(a), pixel_round(b));
+ }
+ break;
+
+ case NOP:
+ break;
+
+ case BOP:
+ xskip(fp, (long)11 * 4);
+ DVI_H = OFFSET_X;
+ DVI_V = OFFSET_Y;
+ PXL_V = pixel_conv(DVI_V);
+ WW = XX = YY = ZZ = 0;
+ break;
+
+ case EOP:
+ if (current_frame != minframe)
+ dvi_fmt_error("%s:%d: draw_part: stack not empty at EOP", __FILE__, __LINE__);
+ return;
+
+ case PUSH:
+ if (current_frame->next == NULL) {
+ struct frame *newp = xmalloc(sizeof *newp);
+
+ current_frame->next = newp;
+ newp->prev = current_frame;
+ newp->next = NULL;
+ }
+ current_frame = current_frame->next;
+ current_frame->data = currinf.data;
+ break;
+
+ case POP:
+ if (current_frame == minframe)
+ dvi_fmt_error("%s:%d: draw_part: more POPs than PUSHes", __FILE__, __LINE__);
+ currinf.data = current_frame->data;
+ current_frame = current_frame->prev;
+ break;
+
+#ifdef TEXXET
+ case SREFL:
+ if (scan_frame == NULL) {
+ /* we're not scanning: save some info. */
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ if (!currinf.virtual)
+ file_pos = xtell(fp, currinf.pos);
+ scan_frame = current_frame; /* now we're scanning */
+ refl_count = 0;
+ break;
+ }
+ /* we are scanning */
+ if (current_frame == scan_frame)
+ ++refl_count;
+ break;
+
+ case EREFL:
+ if (scan_frame != NULL) { /* if we're scanning */
+ if (current_frame == scan_frame && --refl_count < 0) {
+ /* we've hit the end of our scan */
+ scan_frame = NULL;
+ /* first: push */
+ if (current_frame->next == NULL) {
+ struct frame *newp = xmalloc(sizeof *newp);
+
+ current_frame->next = newp;
+ newp->prev = current_frame;
+ newp->next = NULL;
+ }
+ current_frame = current_frame->next;
+ current_frame->data = currinf.data;
+ /* next: restore old file position, XX, etc. */
+ if (!currinf.virtual) {
+ off_t bgn_pos = xtell(fp, G_dvi_buf_ptr);
+
+ if (file_pos >= bgn_pos) {
+ oldinfo.pos = dvi_buffer + (file_pos - bgn_pos);
+ oldinfo.end = currinf.end;
+ }
+ else {
+ (void)lseek(fileno(fp), file_pos, SEEK_SET);
+ oldinfo.pos = oldinfo.end;
+ }
+ }
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+ /* and then: recover position info. */
+ DVI_H = current_frame->data.dvi_h;
+ DVI_V = current_frame->data.dvi_v;
+ PXL_V = current_frame->data.pxl_v;
+ /* and finally, reverse direction */
+ currinf.dir = -currinf.dir;
+ }
+ break;
+ }
+ /* we're not scanning, */
+ /* so just reverse direction and then pop */
+ currinf.dir = -currinf.dir;
+ currinf.data = current_frame->data;
+ current_frame = current_frame->prev;
+ break;
+#endif /* TEXXET */
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ DVI_H += DIR * xspell_conv(xsnum(fp, ch - RIGHT1 + 1));
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ WW = xspell_conv(xsnum(fp, ch - W0));
+ case W0:
+ DVI_H += DIR * WW;
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ XX = xspell_conv(xsnum(fp, ch - X0));
+ case X0:
+ DVI_H += DIR * XX;
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ DVI_V += xspell_conv(xsnum(fp, ch - DOWN1 + 1));
+ PXL_V = pixel_conv(DVI_V);
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ YY = xspell_conv(xsnum(fp, ch - Y0));
+ case Y0:
+ DVI_V += YY;
+ PXL_V = pixel_conv(DVI_V);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ ZZ = xspell_conv(xsnum(fp, ch - Z0));
+ case Z0:
+ DVI_V += ZZ;
+ PXL_V = pixel_conv(DVI_V);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ case FNT4:
+ change_font(xnum(fp, ch - FNT1 + 1));
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ a = xnum(fp, ch - XXX1 + 1);
+ if (a > 0) {
+ char *p = read_special(fp, a);
+ if (resource.pause && strcmp(p, resource.pause_special) == 0) {
+ if (++pause_cnt > globals.pausing.num) {
+ globals.pausing.flag = True;
+ /* can't use longjmp(globals.ev.canit, 1); */
+ return;
+ }
+ }
+ applicationDoSpecial(p, a);
+ }
+ break;
+
+ case FNTDEF1:
+ case FNTDEF2:
+ case FNTDEF3:
+ case FNTDEF4:
+ xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
+ a = (long)xone(fp);
+ xskip(fp, a + (long)xone(fp));
+ break;
+
+#ifndef TEXXET
+ case SREFL:
+ case EREFL:
+#endif
+ case PRE:
+ case POST:
+ case POSTPOST:
+ dvi_fmt_error("%s:%d: draw_part: shouldn't happen: %s encountered",
+ __FILE__, __LINE__, dvi_table2[ch - (FNTNUM0 + 64)]);
+ break;
+
+ default:
+ dvi_fmt_error("%s:%d: draw_part: unknown op-code %d", __FILE__, __LINE__, ch);
+ } /* end switch */
+ } /* end else (ch not a SETCHAR or FNTNUM) */
+ } /* end for */
+}
+
+extern int waiting_for_anchor;
+
+static void
+warn_raw_postscript(void)
+{
+ static int *pagelist = NULL;
+ static int pagelist_size = 0;
+#ifdef PS
+ if (!resource.hush_stdout) {
+ if (total_pages >= pagelist_size) {
+ pagelist_size = total_pages + 1;
+ pagelist = xrealloc(pagelist, pagelist_size * sizeof *pagelist);
+ memset(pagelist, 0, pagelist_size * sizeof *pagelist);
+ }
+
+ ASSERT(pagelist_size > current_page, "pagelist_size too small");
+ if (pagelist[current_page] == 0) {
+ XDVI_WARNING((stderr, "Raw Postscript commands on page %d may be rendered incorrectly.",
+ current_page + 1));
+ pagelist[current_page] = 1;
+ }
+
+ /* too likely to overdraw important information */
+ /* statusline_print(STATUS_MEDIUM, */
+ /* "Warning: Postscript commands on this page may not display correctly."); */
+ }
+#endif /* PS */
+}
+
+void
+draw_page(void)
+{
+#if 0
+ volatile double save_gamma = 0.0;
+#endif /* 0 */
+ /* Check for changes in dvi file. */
+ if (dvi_file_changed()) {
+ return;
+ }
+
+ if (globals.dvi_file.bak_fp == NULL) {
+ return;
+ }
+
+#ifdef PS
+ have_raw_postscript = False;
+#endif
+
+#if COLOR
+ color_bottom = &fg_initial;
+ color_bot_size = 1;
+
+ if (page_colors.stack != NULL && current_page > 0) {
+ color_bottom = page_colors.stack[current_page - 1].colorstack;
+ color_bot_size = page_colors.stack[current_page - 1].stacksize;
+ }
+ rcs_top = NULL;
+ ASSERT(color_bot_size > 0, "color_bot_size mustn't become negative!");
+ ASSERT(color_bottom != NULL, "color_bottom mustn't become negative!");
+ set_fg_color(&color_bottom[color_bot_size - 1]);
+#endif /* COLOR */
+
+#if !FIXED_FLUSHING_PAGING
+ draw_border(-currwin.base_x, -currwin.base_y,
+ ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2,
+ ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2, globals.gc.high);
+#endif /* MOTIF */
+
+ (void) lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(current_page), SEEK_SET);
+
+ memset((char *)&currinf.data, '\0', sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+ dvi_pointer_frame = &currinf;
+ drawing_mag = (currwin.win == magnifier.win);
+ psfig_begun = False;
+
+ htex_initpage(False, False, current_page);
+
+ if (currwin.win == mane.win) {
+ XRectangle rect;
+ rect.x = globals.win_expose.min_x;
+ rect.y = globals.win_expose.min_y;
+ rect.width = globals.win_expose.max_x - globals.win_expose.min_x;
+ rect.height = globals.win_expose.max_y - globals.win_expose.min_y;
+/* fprintf(stderr, "clip: %d, %d, %d, %d\n", */
+/* globals.win_expose.min_x, */
+/* globals.win_expose.min_y, */
+/* globals.win_expose.max_x - globals.win_expose.min_x, */
+/* globals.win_expose.max_y - globals.win_expose.min_y); */
+#define SET_CLIP(gc) if (gc != NULL) XSetClipRectangles(DISP, gc, 0, 0, &rect, 1, Unsorted)
+#define CLEAR_CLIP(gc) if (gc != NULL) XSetClipMask(DISP, gc, None)
+ /* Set clip masks for all GC's */
+ SET_CLIP(globals.gc.fore);
+ SET_CLIP(globals.gc.fore2);
+ SET_CLIP(globals.gc.fore2_bak);
+ SET_CLIP(globals.gc.fore2_bak1);
+ SET_CLIP(globals.gc.rule);
+ SET_CLIP(globals.gc.high);
+ SET_CLIP(globals.gc.linkcolor);
+ SET_CLIP(globals.gc.copy);
+ }
+
+ if (!setjmp(globals.ev.canit)) {
+ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ ALL GLYPH DRAWING/RULE SETTING COMMANDS THAT MIGHT INVOKE
+ longjmp(globals.ev.canit)
+ MUST GO INSIDE THIS IF CASE, AND MUST NOT BE INVOKED FROM
+ SOMEWHERE ELSE!
+
+ Failure to check whether a command could (indirectly) invoke
+ such a drawing routine (like e.g. put_rule()) will result
+ in *really* strange bugs (see e.g. #616920, and probably also #471021).
+
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+ /* generate an expose event */
+ if (search_have_match(current_page)) {
+ search_erase_highlighting(False);
+ }
+ if (resource.mouse_mode == MOUSE_TEXT_MODE) {
+ text_change_region(TEXT_SEL_ERASE, NULL);
+ }
+ draw_part(globals.dvi_file.bak_fp, current_frame = &frame0, dimconv);
+
+ if (have_raw_postscript) {
+ warn_raw_postscript();
+ }
+ }
+ else {
+ /* If we were interrupted, put the expose event back, so that the
+ * region gets redrawn. The if statement is necessary because the
+ * magnifier may have been destroyed as part of the interrupt. */
+ if (currwin.win == mane.win || currwin.win == magnifier.win) {
+ expose(currwin.win == mane.win ? &mane : &magnifier,
+ globals.win_expose.min_x - currwin.base_x, globals.win_expose.min_y - currwin.base_y,
+ globals.win_expose.max_x - globals.win_expose.min_x, globals.win_expose.max_y - globals.win_expose.min_y);
+ }
+
+#ifdef PS
+ psp.interrupt();
+ /* reset this flag too, just to make sure ... */
+#if GS_PIXMAP_CLEARING_HACK
+ had_ps_specials = False;
+#endif
+#endif
+ globals.ev.flags &= ~EV_MAG_GONE;
+#if 0
+ if (search_have_match() && save_gamma != 0.0) {
+ resource.gamma = save_gamma;
+ do_color_change();
+ reset_fonts();
+ }
+#endif /* 0 */
+ }
+
+ drawing_mag = False;
+ dvi_pointer_frame = NULL;
+ if (currwin.win == mane.win) {
+ if (globals.src.fwd_box_page >= 0) {
+ source_fwd_draw_box(); /* draw box showing found source line */
+ }
+ htex_draw_anchormarkers();
+ }
+#ifdef PS
+ psp.endpage();
+#endif
+ if (currwin.win == mane.win && resource.postscript != 1) {
+ display_bboxes();
+ }
+ if (search_have_match(current_page)) {
+ /* highlight search match */
+ search_draw_inverted_regions();
+ }
+ if (currwin.win == mane.win && resource.mouse_mode == MOUSE_TEXT_MODE) {
+ /* highlight selection */
+ text_change_region(TEXT_SEL_REDRAW, NULL);
+ }
+ if (resource.mouse_mode == MOUSE_RULER_MODE) {
+ redraw_ruler();
+ }
+
+ clear_bboxes();
+
+ if (currwin.win == mane.win) {
+ CLEAR_CLIP(globals.gc.fore);
+ CLEAR_CLIP(globals.gc.fore2);
+ CLEAR_CLIP(globals.gc.fore2_bak);
+ CLEAR_CLIP(globals.gc.fore2_bak1);
+ CLEAR_CLIP(globals.gc.rule);
+ CLEAR_CLIP(globals.gc.high);
+ CLEAR_CLIP(globals.gc.linkcolor);
+ CLEAR_CLIP(globals.gc.copy);
+ }
+#undef SET_CLIP
+#undef CLEAR_CLIP
+
+ currwin.win = (Window) 0;
+}
+
+/* this sets the file-scope htex_anchor_type to the type of the anchor just scanned,
+ which is used by the drawing routines to determine whether current position is inside
+ an anchor. Called from special.c.
+ */
+void
+htex_do_special(const char *str, size_t len)
+{
+ if (INSIDE_MANE_WIN) {
+ htex_inside_href = htex_scan_anchor(str, len);
+ }
+}
+
+/*
+ * General dvi scanning routines. These are used for:
+ * o source special lookups and
+ * o finding the dimensions of links (if compiling with support for
+ * hypertext specials).
+ * This routine can be a bit slower than draw_page()/draw_part(), since
+ * it is not run that often; that is why it is a separate routine in
+ * spite of much duplication.
+ *
+ * Note that it does not use a separate copy of define_font().
+ */
+
+/*
+ * This set of routines can be called while draw_part() is active,
+ * so the global variables must be separate.
+ */
+
+static struct frame geom_frame0; /* dummy head of list */
+
+#ifdef TEXXET
+static struct frame *geom_scan_frame; /* head frame for scanning */
+#endif
+
+static struct frame *geom_current_frame;
+
+static uint32_t
+get_unicode_char(wide_ubyte ch, struct drawinf currinf, char *retbuf)
+{
+ /* attempt 1: if it's a Type1 font, get the Adobe character name
+ from T1lib's T1_GetCharName */
+ if (currinf.set_char_p == set_t1_char) {
+ int id = currinf.fontp->t1id;
+ int t1libid = fontmaps[id].t1libid;
+ char *char_name;
+ ASSERT(t1libid != -1, "Font must have been loaded at this point!");
+ char_name = T1_GetCharName(t1libid, ch);
+ TRACE_FIND_VERBOSE((stderr, "T1 char: %d = `%s' (id: %d; font: %s; enc: %d)",
+ ch, char_name,
+ currinf.fontp->t1id, fontmaps[currinf.fontp->t1id].texname,
+ fontmaps[currinf.fontp->t1id].enc));
+ return adobe2unicode_name(char_name);
+ }
+ else {
+ /* attempt 2: try to derive the encoding from the font name, by
+ looking it up in a list of known font names.
+ */
+ return guess_encoding(ch, currinf.fontp->fontname, retbuf);
+ }
+}
+
+#define MAX_CHARS 16 /* maximum number of unicode characters that one do_char can produce (rounded up ...) */
+static const size_t ALLOC_STEP = 1024;
+
+/* create a page break at BOP, unless we're at the start of the file */
+static void
+do_newpage(struct scan_info *info)
+{
+ struct word_info *w_info = (struct word_info *)info->data;
+ if (w_info->curr_buf_idx > 0) { /* not at start of file */
+ /* resize buffer if needed */
+ while (w_info->curr_buf_idx + MAX_CHARS >= w_info->txt_buf_size) {
+ w_info->txt_buf_size += ALLOC_STEP;
+ w_info->txt_buf = xrealloc(w_info->txt_buf, w_info->txt_buf_size);
+ }
+ w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
+ }
+}
+
+static void
+reset_bboxes(struct word_info *info)
+{
+ size_t i;
+ for (i = 0; i < info->bboxes_size; i++) {
+ info->bboxes[i].ulx = INT_MAX;
+ info->bboxes[i].uly = INT_MAX;
+ info->bboxes[i].lrx = 0;
+ info->bboxes[i].lry = 0;
+ }
+}
+
+static void
+delete_last_bbox(struct word_info *info)
+{
+ info->bboxes[info->bboxes_idx].ulx = INT_MAX;
+ info->bboxes[info->bboxes_idx].uly = INT_MAX;
+ info->bboxes[info->bboxes_idx].lrx = 0;
+ info->bboxes[info->bboxes_idx].lry = 0;
+}
+
+static void
+finish_bbox(struct word_info *info)
+{
+/* if (info->bboxes_idx == 0) /\* nothing to do *\/ */
+/* return; */
+
+ info->bboxes_idx++;
+ while (info->bboxes_idx + 1 > info->bboxes_size) {
+ /* re-allocate info */
+ info->bboxes_size += 32;
+ info->bboxes = xrealloc(info->bboxes, info->bboxes_size * sizeof *(info->bboxes));
+ }
+ info->bboxes[info->bboxes_idx].ulx = INT_MAX;
+ info->bboxes[info->bboxes_idx].uly = INT_MAX;
+ info->bboxes[info->bboxes_idx].lrx = 0;
+ info->bboxes[info->bboxes_idx].lry = 0;
+
+#if 0
+ fprintf(stderr, "========= finish_bbox: index=%d, boxes:\n", info->bboxes_idx);
+ {
+ int i;
+ for (i = 0; i < info->bboxes_idx; i++) {
+ fprintf(stderr, "%d: x %d, y %d, w %d, h %d\n",
+ i, info->bboxes[i].ulx, info->bboxes[i].uly, info->bboxes[i].lrx, info->bboxes[i].lry);
+ }
+ }
+#endif /* 0 */
+}
+
+static void
+create_bbox(struct word_info *info, int x, int y, int w, int h)
+{
+#if 0
+ fprintf(stderr, "++++++++++++++ inside match: %d,%d,%d,%d!\n", x,y,w,h);
+ XDrawRectangle(DISP, mane.win, globals.gc.high,
+ x / (double)currwin.shrinkfactor + 0.5,
+ y / (double)currwin.shrinkfactor + 0.5,
+ w / (double)currwin.shrinkfactor + 0.5,
+ h / (double)currwin.shrinkfactor + 0.5);
+#endif
+ while (info->bboxes_idx + 1 > info->bboxes_size) {
+ /* re-allocate info */
+ size_t old_size = info->bboxes_size;
+ size_t i;
+ info->bboxes_size += 32;
+ info->bboxes = xrealloc(info->bboxes, info->bboxes_size * sizeof *(info->bboxes));
+ for (i = old_size; i < info->bboxes_size; i++) {
+ info->bboxes[i].ulx = INT_MAX;
+ info->bboxes[i].uly = INT_MAX;
+ info->bboxes[i].lrx = 0;
+ info->bboxes[i].lry = 0;
+ }
+
+ }
+ /* adjust size of box */
+ if (x < info->bboxes[info->bboxes_idx].ulx)
+ info->bboxes[info->bboxes_idx].ulx = x;
+ if (y < info->bboxes[info->bboxes_idx].uly)
+ info->bboxes[info->bboxes_idx].uly = y;
+ if (x + w > info->bboxes[info->bboxes_idx].lrx)
+ info->bboxes[info->bboxes_idx].lrx = x + w;
+ if (y + h > info->bboxes[info->bboxes_idx].lry)
+ info->bboxes[info->bboxes_idx].lry = y + h;
+#if 0
+ fprintf(stderr, "dimens: %d, %d, %d, %d\n",
+ info->bboxes[info->bboxes_idx].ulx,
+ info->bboxes[info->bboxes_idx].uly,
+ info->bboxes[info->bboxes_idx].lrx,
+ info->bboxes[info->bboxes_idx].lry);
+ fprintf(stderr, "============ create_bbox: index=%d, boxes:\n", info->bboxes_idx);
+ {
+ int i;
+ for (i = 0; i <= info->bboxes_idx; i++) {
+ fprintf(stderr, "%d: x %d, y %d, w %d, h %d\n",
+ i, info->bboxes[i].ulx, info->bboxes[i].uly, info->bboxes[i].lrx, info->bboxes[i].lry);
+ }
+ }
+#endif /* 0 */
+}
+
+static void
+map_index_positions(const struct search_info *searchinfo,
+ const struct page_mapping *page_mapping,
+ int *from, int *to)
+{
+ *from = searchinfo->from_pos;
+ *to = searchinfo->to_pos;
+
+ if (*from >= page_mapping[0].offset) { /* on second page of scan */
+#if 0
+ fprintf(stderr, "current_page: %d, from: %d, to: %d; subtracting %d for pageinfo at index 0\n",
+ current_page, *from, *to, page_mapping[0].offset);
+#endif /* 0 */
+ if (page_mapping[0].offset != -1) {
+ ASSERT(page_mapping[0].offset != -1, "page_mapping not properly initialized?");
+ (*from) -= page_mapping[0].offset;
+ (*to) -= page_mapping[0].offset;
+ }
+ ASSERT(*from >= 0, "index must be > 0");
+ ASSERT(*to >= 0, "index must be > 0");
+
+ }
+}
+
+/* decrement curr_buf_idx so that the previous character in info
+ * (which might be a multi-byte character) is erased.
+ */
+static void
+erase_prev_char(struct word_info *info)
+{
+ /* erase the hyphen, which might be a multibyte character */
+ if ((unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) < 0x80) { /* single-byte */
+ TRACE_FIND_VERBOSE((stderr, "1 XXX: %d",
+ (unsigned char)(info->txt_buf[info->curr_buf_idx - 1])));
+ info->txt_buf[--(info->curr_buf_idx)] = '\0';
+ }
+ else { /* skip back over multi-byte sequence */
+ while ((unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) >= 0x80
+ && (unsigned char)(info->txt_buf[info->curr_buf_idx - 1]) < 0xC0) { /* 10xxxxxx bytes */
+ TRACE_FIND_VERBOSE((stderr, "2 XXX: %d",
+ (unsigned char)(info->txt_buf[info->curr_buf_idx - 1])));
+ info->txt_buf[--(info->curr_buf_idx)] = '\0';
+ }
+ /* first byte (TODO: sanity check?) */
+ info->txt_buf[--(info->curr_buf_idx)] = '\0';
+ }
+}
+
+
+static Boolean
+inside_text_match(int curr_pos, int from, int to)
+{
+ return from < curr_pos && curr_pos <= to;
+}
+
+static Boolean reinit_scan = False;
+
+void
+reinit_text_scan(void) {
+ reinit_scan = True;
+}
+
+static Boolean
+inside_bbox(int x, int y, int w, int h,
+ struct bbox *bboxes)
+{
+ int mid_x, mid_y;
+#if 0
+ XDrawRectangle(DISP, mane.win, globals.gc.high,
+ x / (double)currwin.shrinkfactor + 0.5,
+ y / (double)currwin.shrinkfactor + 0.5,
+ w / (double)currwin.shrinkfactor + 0.5,
+ h / (double)currwin.shrinkfactor + 0.5);
+#endif
+ /* already treat it as inside if there's an overlap of more than 50% */
+ mid_x = x + w / 2.0;
+ mid_y = y + h / 2.0;
+#if 0
+ fprintf(stderr, "------- check:\n%d, %d\n%d, %d, %d, %d\n",
+ mid_x, mid_y, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
+#endif
+ if (bboxes->ulx <= mid_x &&
+ bboxes->uly <= mid_y &&
+ bboxes->lrx >= mid_x &&
+ bboxes->lry >= mid_y) {
+#if 0
+ fprintf(stderr, "====== MATCH:\n%d, %d\n%d, %d, %d, %d\n",
+ mid_x, mid_y, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
+#endif
+ return True;
+ }
+ return False;
+}
+
+static Boolean
+inside_bbox_line(int y, int h,
+ struct bbox *bboxes)
+{
+ int mid_y = y + h / 2.0;
+ if (bboxes->uly <= mid_y &&
+ bboxes->lry >= mid_y) {
+#if 0
+ fprintf(stderr, "MATCH:\n%d, %d, %d, %d\n%d, %d, %d, %d\n",
+ x, y, w, h, bboxes->ulx, bboxes->uly, bboxes->lrx, bboxes->lry);
+#endif
+ return True;
+ }
+ return False;
+}
+
+static void
+do_char(wide_ubyte ch,
+ struct drawinf currinf,
+ struct scan_info *info,
+ long pxl_v1, long pxl_v2,
+ long x1, long x2,
+ struct glyph *g)
+{
+ struct word_info *w_info = (struct word_info *)info->data;
+ struct search_settings *settings = NULL;
+ const struct page_mapping *page_mapping = NULL;
+ uint32_t u_glyph = 0, new_glyph = 0;
+ float fsize = dvi_pt_conv(currinf.fontp->scale); /* font size in pt */
+ Boolean convert_to_lowercase = False;
+ /* if set to true, ignore whitespace before/after character (for CJK characters) */
+ Boolean ignore_whitespace = False;
+
+ /* default min space between words, in DVI units */
+ /* TODO: for T1 fonts, should we look at fontdimen2 / fontdimen4?
+ (e.g. tfminfo[fontmaps[currinf.fontp->t1id].tfmidx].fontdimen2)
+ */
+ long min_delta = (int)(1.5 * fsize + 0.5) << 16;
+
+ size_t buf_offset = w_info->buffer_offset;
+
+ size_t i;
+ /* for delayed insertion of newlines in text selection mode */
+ static Boolean had_newline = False;
+ /* for whitespace insertion in text selection mode */
+ static Boolean had_chars_in_line = False;
+ static long last_dvi_h1 = 0, last_pxl_v = 0;
+ static long last_dvi_h2 = 0;
+ static long last_x = 0;
+ static uint32_t last_u_glyph = 0;
+ static int last_page = -1;
+ static int page_bak = -1;
+ const char *expanded_lig = NULL;
+ const uint32_t UNKNOWN_GLYPH_CODE = 0x003F; /* question mark */
+ char retbuf[MAX_CHARS];
+ retbuf[0] = '\0';
+
+ if (w_info != NULL && w_info->settings != NULL) {
+ settings = w_info->settings;
+ if (!settings->case_sensitive)
+ convert_to_lowercase = True;
+ }
+
+ if (w_info->bbox_pass) {
+ ASSERT(w_info != NULL, "");
+ ASSERT(w_info->page_mapping != NULL, "");
+ page_mapping = w_info->page_mapping;
+ }
+
+ if (reinit_scan || last_page != current_page) { /* reinit */
+ last_dvi_h1 = last_pxl_v = last_dvi_h2 = last_x = 0;
+ last_page = current_page;
+ last_u_glyph = 0;
+ w_info->bboxes_idx = 0;
+ reset_bboxes(w_info);
+/* w_info->curr_buf_idx = 0; */
+ reinit_scan = False;
+ had_newline = False;
+ had_chars_in_line = False;
+ }
+
+/* TRACE_FIND((stderr, "\n--------- POSITIONS: %ld, %ld, %ld, %ld", x1, pxl_v2, x2, y2)); */
+
+ if ((u_glyph = get_unicode_char(ch, currinf, retbuf)) == 0) {
+ if (retbuf[0] == '\0') {
+ TRACE_FIND((stderr, "unknown glyph `%lu'\n", (unsigned long)ch));
+ u_glyph = UNKNOWN_GLYPH_CODE;
+ }
+ else /* several characters in retbuf, will be evaluated later */
+ u_glyph = 0;
+ }
+
+ TRACE_FIND_VERBOSE((stderr, "UNICODE: 0x%.4X; idx: %ld",
+ (unsigned int)u_glyph,
+ (unsigned long)w_info->curr_buf_idx));
+
+ /* resize buffer if needed */
+ while (w_info->curr_buf_idx + MAX_CHARS >= w_info->txt_buf_size) {
+ w_info->txt_buf_size += ALLOC_STEP;
+ w_info->txt_buf = xrealloc(w_info->txt_buf, w_info->txt_buf_size);
+ }
+
+ /* Copy text into buffer, applying heuristics for special glyphs.
+ A `\0' is always appended, so that we have a valid C string;
+ if we have more text, this '\0' will be overwritten in the next call. */
+
+ /* apply accent/linebreak heuristics */
+/* fprintf(stderr, "Checking: %ld > 0, %ld > 0\n", last_dvi_h1, last_pxl_v); */
+ if (last_dvi_h1 > 0 && last_pxl_v > 0) { /* had at least 1 character */
+ TRACE_FIND_VERBOSE((stderr, "++++ dvi_h: %ld, last_dvi_h1: %ld, w_info->curr_buf_idx: %ld",
+ DVI_H, last_dvi_h1, (unsigned long)w_info->curr_buf_idx));
+
+ /* spaces after/before ideographic characters are ignored */
+ if (is_ideograph(last_u_glyph) || is_ideograph(u_glyph))
+ ignore_whitespace = true;
+
+ /* first, check for linebreaks since accents are also triggered by negative hspace.
+ * Usually, a linebreak is signalled by vertical movement down. However, in multicolumn
+ * mode, it can also be a movement up, which we try to catch with the second condition. */
+ if (pxl_v2 > last_pxl_v + (int)(1.2 * fsize + 0.5)
+ || (page_bak == current_page && pxl_v2 + (int)(6 * fsize + 0.5) < last_pxl_v)) {
+ TRACE_FIND_VERBOSE((stderr, "linebreak (%ld > %ld + %d || %ld < %ld)!\n",
+ pxl_v2, last_pxl_v, (int)(1.2 * fsize + 0.5),
+ pxl_v2 + (int)(6 * fsize + 0.5), last_pxl_v));
+
+ /* remove hyphen followed by newline if ignore_hyphens option is set,
+ and we're scanning for string search: */
+ if ((w_info->search_scan_pass || w_info->bbox_pass)
+ && settings->ignore_hyphens && w_info->curr_buf_idx > 0
+ && is_hyphenchar(last_u_glyph)) {
+
+ erase_prev_char(w_info);
+ TRACE_FIND_VERBOSE((stderr, "%d > %d + %d? offset: %lu",
+ settings->searchinfo->from_pos,
+ (int)w_info->curr_buf_idx,
+ settings->hyphen_delta, (unsigned long)buf_offset));
+ if (!w_info->bbox_pass
+ && settings->searchinfo->from_pos
+ > (int)(w_info->curr_buf_idx + buf_offset + settings->hyphen_delta)) {
+ settings->hyphen_delta += 2;
+ }
+ TRACE_FIND((stderr, "erasing hyphen %lu at pos %lu with char %c; hyphen_delta is: %d",
+ (unsigned long)last_u_glyph, (unsigned long)w_info->curr_buf_idx, ch, settings->hyphen_delta));
+ /* If the position of this hyphen had been at the start of the bounding
+ box, this bounding box info is now invalid - delete it */
+ if (w_info->bbox_pass) {
+ int from, to;
+ map_index_positions(settings->searchinfo, page_mapping, &from, &to);
+ if ((int)w_info->curr_buf_idx == from) {
+ delete_last_bbox(w_info);
+ }
+ }
+ }
+ else { /* ignore_hyphens not set, insert newline */
+ /* Also save hyphen_delta, in case we need to update from_pos and to_pos
+ if user switched from ignore hyphens to don't ignore hyphens */
+ if (w_info->search_scan_pass && !w_info->bbox_pass
+ && is_hyphenchar(last_u_glyph)
+ && settings->searchinfo->from_pos + settings->hyphen_delta
+ >= (int)(w_info->curr_buf_idx + buf_offset)) {
+ settings->hyphen_delta += 2;
+ TRACE_FIND((stderr, "updating delta: %d at pos %d, curr_idx %d, offset: %lu",
+ settings->hyphen_delta, settings->searchinfo->from_pos,
+ (int)w_info->curr_buf_idx, (unsigned long)buf_offset));
+ }
+ if (w_info->text_selection_pass) {
+ if (inside_bbox(last_x, last_pxl_v, 5, 5, w_info->bboxes)
+ || (inside_bbox_line(last_pxl_v, 5, w_info->bboxes))) {
+ had_newline = True;
+ had_chars_in_line = False;
+ }
+ }
+ else if (w_info->search_scan_pass && settings->ignore_linebreaks && !ignore_whitespace)
+ w_info->txt_buf[w_info->curr_buf_idx++] = ' ';
+ else if (!ignore_whitespace)
+ w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
+ }
+ if (w_info->bbox_pass) {
+ int from, to;
+ map_index_positions(settings->searchinfo, page_mapping, &from, &to);
+ if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
+ finish_bbox(w_info);
+ }
+ }
+ }
+ else if (w_info->curr_buf_idx > 0 && last_u_glyph != 0 && last_x > 0
+ && (!w_info->text_selection_pass
+ || (w_info->text_selection_pass
+ && inside_bbox(last_x, pxl_v2, x1 - last_x, pxl_v1 - pxl_v2, w_info->bboxes)))
+ && x1 < last_x /* overlapping glyphs: check for diacritics */
+ && ((new_glyph = get_accented_glyph(last_u_glyph, u_glyph)) != 0)) {
+ erase_prev_char(w_info);
+ /* use new glyph for next writing operation: */
+ u_glyph = new_glyph;
+ }
+ else if (!ignore_whitespace && last_dvi_h2 > 0 && DVI_H > last_dvi_h2 + min_delta) {
+ TRACE_FIND_VERBOSE((stderr, "space (%ld > %ld + %ld)!", DVI_H, last_dvi_h2, min_delta));
+ if (!w_info->text_selection_pass
+ || (w_info->text_selection_pass
+ && had_chars_in_line
+ && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h, w_info->bboxes))) {
+ w_info->txt_buf[w_info->curr_buf_idx++] = ' ';
+ w_info->txt_buf[w_info->curr_buf_idx] = '\0';
+ if (w_info->bbox_pass) {
+ int from, to;
+ map_index_positions(settings->searchinfo, page_mapping, &from, &to);
+ if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
+ TRACE_FIND_VERBOSE((stderr, "bounding box for space: %ld, %ld, %ld, %ld",
+ last_x, last_pxl_v, x1 - last_x, pxl_v1 - pxl_v2));
+ create_bbox(w_info, last_x, pxl_v2, x1 - last_x, pxl_v1 - pxl_v2);
+ }
+ }
+ }
+ }
+ }
+
+ last_page = current_page;
+ if (retbuf[0] != '\0'
+ || (expanded_lig = expand_ligature(u_glyph)) != NULL
+ /* when in search pass, normalize more characters */
+ || ((w_info->bbox_pass || w_info->search_scan_pass)
+ && (expanded_lig = search_normalize_chars(u_glyph)) != NULL)) {
+ /* expanded ligature, which is always in 7-bit ASCII -> copy into buffer */
+ size_t len;
+ if (retbuf[0] != '\0')
+ expanded_lig = retbuf;
+ len = strlen(expanded_lig);
+ TRACE_FIND_VERBOSE((stderr, "I: %lu to %lu",
+ (unsigned long)w_info->curr_buf_idx,
+ (unsigned long)(w_info->curr_buf_idx + len)));
+
+ if (!w_info->text_selection_pass
+ || (w_info->text_selection_pass && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h,
+ w_info->bboxes))) {
+
+/* fprintf(stderr, "inserting1 %s\n", expanded_lig); */
+ if (had_newline) {
+ w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
+ had_newline = False;
+ }
+ memcpy(w_info->txt_buf + w_info->curr_buf_idx, expanded_lig, len);
+ had_chars_in_line = True;
+ for (i = 0; i < len; i++) {
+ w_info->curr_buf_idx++;
+/* fprintf(stderr, "setting index to: %d\n", w_info->curr_buf_idx); */
+ if (w_info->bbox_pass) {
+ int from, to;
+ map_index_positions(settings->searchinfo, page_mapping, &from, &to);
+ if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
+ create_bbox(w_info, x1, pxl_v2, x2 - x1, g->bitmap.h);
+ }
+ }
+ }
+ w_info->txt_buf[w_info->curr_buf_idx] = '\0';
+ }
+ }
+ else if (!w_info->text_selection_pass
+ || (w_info->text_selection_pass && inside_bbox(x1, pxl_v2, x2 - x1, g->bitmap.h, w_info->bboxes))) {
+ /* convert to utf8 */
+ char utf8_buf[MAX_CHARS]; /* ample ... */
+ size_t len;
+ /* convert to utf8, eventually lowercasing */
+ ucs4_to_utf8(u_glyph, utf8_buf, &len, convert_to_lowercase);
+/* fprintf(stderr, "inserting2 %lu\n", u_glyph); */
+ if (had_newline) {
+ w_info->txt_buf[w_info->curr_buf_idx++] = '\n';
+ had_newline = False;
+ }
+ memcpy(w_info->txt_buf + w_info->curr_buf_idx, utf8_buf, len);
+ had_chars_in_line = True;
+ for (i = 0; i < len; i++) {
+ w_info->curr_buf_idx++;
+/* fprintf(stderr, "setting index2 to: %d\n", w_info->curr_buf_idx); */
+ if (w_info->bbox_pass) {
+ int from, to;
+#if 0
+ int j;
+ fprintf(stderr, "current page_mapping:\n");
+ for (j = 0; j <= total_pages; j++) {
+ fprintf(stderr, "%d: %d\n", j, page_mapping[j]);
+ }
+#endif /* 0 */
+/* fprintf(stderr, "mapping!\n"); */
+ map_index_positions(settings->searchinfo, page_mapping, &from, &to);
+ if (inside_text_match((int)w_info->curr_buf_idx, from, to)) {
+ create_bbox(w_info, x1, pxl_v2, x2 - x1, g->bitmap.h);
+ }
+ }
+ }
+ w_info->txt_buf[w_info->curr_buf_idx] = '\0'; /* ensure termination */
+ }
+
+ last_dvi_h1 = DVI_H;
+ last_u_glyph = u_glyph;
+ last_pxl_v = pxl_v1;
+ last_dvi_h2 = DVI_H + currinf.fontp->glyph[ch].dvi_adv;
+ last_x = x2;
+}
+
+/* handle a character in the text scanning routine */
+long
+text_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch)
+{
+ if (currinf.set_char_p == set_no_char) {
+ if (currinf.virtual == NULL
+ || (currinf.fontp = currinf.virtual->first_font) == NULL)
+ return 0; /* error; we'll catch it later */
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ }
+
+ if (currinf.set_char_p == set_empty_char)
+ return 0; /* error; we'll catch it later */
+
+ if (currinf.set_char_p == load_n_set_char) {
+ if (globals.ev.flags & EV_GE_NEWDOC) /* if abort */
+ return 0;
+ if (!load_font(currinf.fontp, resource.t1lib)) { /* if not found */
+ if (globals.ev.flags & EV_GE_NEWDOC) /* if abort */
+ return 0;
+
+ /* FIXME: replace by GUI warning! */
+ fputs("geom_do_char: Character(s) will be left blank.\n", stderr);
+ currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
+ return 0;
+ }
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ }
+
+ if (currinf.set_char_p == set_char) {
+ struct glyph *g;
+ long x, y;
+
+ if (ch > maxchar)
+ return 0; /* catch the error later */
+ if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
+ if (g->addr == 0)
+ return 0; /* catch the error later */
+ if (g->addr == -1)
+ return 0; /* previously flagged missing char */
+ open_font_file(currinf.fontp);
+ fseek(currinf.fontp->file, g->addr, SEEK_SET);
+ (*currinf.fontp->read_char) (currinf.fontp, ch);
+ if (globals.debug & DBG_BITMAP)
+ print_char((ubyte) ch, g);
+ currinf.fontp->timestamp = ++current_timestamp;
+ }
+#ifdef TEXXET
+ if (geom_scan_frame == NULL) {
+ long dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= g->dvi_adv;
+#endif
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
+#ifdef TEXXET
+ DVI_H = dvi_h_sav;
+ }
+#endif
+ return DIR * g->dvi_adv;
+ }
+ else if (currinf.set_char_p == set_vf_char) {
+ struct macro *m;
+ struct drawinf oldinfo;
+ ubyte oldmaxchar;
+#ifdef TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar)
+ return 0; /* catch the error later */
+ if ((m = &currinf.fontp->macro[ch])->pos == NULL)
+ return 0; /* catch the error later */
+#ifdef TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= m->dvi_adv;
+ if (geom_scan_frame == NULL) {
+#endif
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ WW = XX = YY = ZZ = 0;
+ currinf.tn_table_len = VFTABLELEN;
+ currinf.tn_table = currinf.fontp->vf_table;
+ currinf.tn_head = currinf.fontp->vf_chain;
+ currinf.pos = m->pos;
+ currinf.end = m->end;
+ currinf.virtual = currinf.fontp;
+ geom_scan_part(text_do_char, fp, info, geom_current_frame, currinf.fontp->dimconv);
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+#ifdef TEXXET
+ DVI_H = dvi_h_sav;
+ }
+#endif
+ return DIR * m->dvi_adv;
+ }
+#ifdef T1LIB
+ else if (currinf.set_char_p == set_t1_char) {
+ struct glyph *g ;
+ long x, y;
+ t1FontLoadStatusT status;
+
+#ifdef TEXXET
+ g = get_t1_glyph(0, ch, &status, True);
+ if (status == FAILURE_BLANK)
+ return 0;
+ if (geom_scan_frame == NULL) {
+ long dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= g->dvi_adv;
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
+ DVI_H = dvi_h_sav;
+ }
+#else
+ g = get_t1_glyph(ch, &status, True);
+ if (status == FAILURE_BLANK)
+ return 0;
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ do_char(ch, currinf, info, PXL_V, y, x, x + g->bitmap.w - 1, g);
+#endif
+ return DIR * g->dvi_adv;
+ }
+#endif /* T1LIB */
+ else {
+ XDVI_FATAL((stderr, "currinf.set_char_p not a registered routine!"));
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+/*
+ * Handle a character in geometric scanning routine.
+ */
+
+static long
+geom_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch)
+{
+ struct geom_info *g_info = info->data;
+
+ if (currinf.set_char_p == set_no_char) {
+ if (currinf.virtual == NULL
+ || (currinf.fontp = currinf.virtual->first_font) == NULL)
+ return 0; /* error; we'll catch it later */
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ }
+
+ if (currinf.set_char_p == set_empty_char)
+ return 0; /* error; we'll catch it later */
+
+ if (currinf.set_char_p == load_n_set_char) {
+ if (globals.ev.flags & EV_GE_NEWDOC) /* if abort */
+ return 0;
+ if (!load_font(currinf.fontp, resource.t1lib)) { /* if not found */
+ if (globals.ev.flags & EV_GE_NEWDOC) /* if abort */
+ return 0;
+
+ /* FIXME: replace by GUI warning! */
+ fputs("geom_do_char: Character(s) will be left blank.\n", stderr);
+ currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
+ return 0;
+ }
+ maxchar = currinf.fontp->maxchar;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ }
+
+ if (currinf.set_char_p == set_char) {
+ struct glyph *g;
+ long x, y;
+
+ if (ch > maxchar)
+ return 0; /* catch the error later */
+ if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
+ if (g->addr == 0)
+ return 0; /* catch the error later */
+ if (g->addr == -1)
+ return 0; /* previously flagged missing char */
+ open_font_file(currinf.fontp);
+ fseek(currinf.fontp->file, g->addr, SEEK_SET);
+ (*currinf.fontp->read_char) (currinf.fontp, ch);
+ if (globals.debug & DBG_BITMAP)
+ print_char((ubyte) ch, g);
+ currinf.fontp->timestamp = ++current_timestamp;
+ }
+#ifdef TEXXET
+ if (geom_scan_frame == NULL) {
+ long dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= g->dvi_adv;
+#endif
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ g_info->geom_box(info, x, y,
+ x + g->bitmap.w - 1, y + g->bitmap.h - 1);
+
+#ifdef TEXXET
+ DVI_H = dvi_h_sav;
+ }
+#endif
+ return DIR * g->dvi_adv;
+ }
+ else if (currinf.set_char_p == set_vf_char) {
+ struct macro *m;
+ struct drawinf oldinfo;
+ ubyte oldmaxchar;
+#ifdef TEXXET
+ long dvi_h_sav;
+#endif
+
+ if (ch > maxchar)
+ return 0; /* catch the error later */
+ if ((m = &currinf.fontp->macro[ch])->pos == NULL)
+ return 0; /* catch the error later */
+#ifdef TEXXET
+ dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= m->dvi_adv;
+ if (geom_scan_frame == NULL) {
+#endif
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ WW = XX = YY = ZZ = 0;
+ currinf.tn_table_len = VFTABLELEN;
+ currinf.tn_table = currinf.fontp->vf_table;
+ currinf.tn_head = currinf.fontp->vf_chain;
+ currinf.pos = m->pos;
+ currinf.end = m->end;
+ currinf.virtual = currinf.fontp;
+ geom_scan_part(geom_do_char, fp, info, geom_current_frame, currinf.fontp->dimconv);
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+#ifdef TEXXET
+ DVI_H = dvi_h_sav;
+ }
+#endif
+ return DIR * m->dvi_adv;
+ }
+#ifdef T1LIB
+ else if (currinf.set_char_p == set_t1_char) {
+ struct glyph *g ;
+ long x, y;
+ t1FontLoadStatusT status;
+
+#ifdef TEXXET
+ g = get_t1_glyph(0, ch, &status, False);
+ if (status == FAILURE_BLANK)
+ return 0;
+ if (geom_scan_frame == NULL) {
+ long dvi_h_sav = DVI_H;
+ if (currinf.dir < 0)
+ DVI_H -= g->dvi_adv;
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ g_info->geom_box(info, x, y,
+ x + g->bitmap.w - 1, y + g->bitmap.h - 1);
+ DVI_H = dvi_h_sav;
+ }
+#else
+ g = get_t1_glyph(ch, &status, False);
+ if (status == FAILURE_BLANK)
+ return 0;
+ x = G_PXL_H - g->x;
+ y = PXL_V - g->y;
+ g_info->geom_box(info, x, y,
+ x + g->bitmap.w - 1, y + g->bitmap.h - 1);
+#endif
+ return DIR * g->dvi_adv;
+ }
+#endif /* T1LIB */
+ else {
+ XDVI_FATAL((stderr, "currinf.set_char_p not a registered routine!"));
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+/*
+ * Do a rule in the geometry-scanning routine.
+ */
+
+static void
+geom_do_rule(struct scan_info *info, long h, long w)
+{
+ long x, y;
+#ifdef TEXXET
+ long dvi_h_save = DVI_H;
+#endif
+ struct geom_info *g_info = info->data;
+
+#ifdef TEXXET
+ if (currinf.dir < 0)
+ DVI_H -= w - 1;
+#endif
+ x = G_PXL_H;
+ y = PXL_V;
+ g_info->geom_box(info, x, y - xpixel_round(h) + 1,
+ x + xpixel_round(w) - 1, y);
+#ifdef TEXXET
+ DVI_H = dvi_h_save;
+#endif
+}
+
+/*
+ * Geometric dvi scanner work routine. This does most of the work
+ * (a) reading from a page, and (b) executing vf macros.
+ */
+
+void
+geom_scan_part(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
+ FILE *fp, struct scan_info *info, struct frame *minframe, double current_dimconv)
+{
+ ubyte ch;
+#ifdef TEXXET
+ struct drawinf oldinfo;
+ ubyte oldmaxchar = 0;
+ off_t file_pos = 0;
+ int refl_count = 0;
+#endif
+
+ currinf.fontp = NULL;
+ currinf.set_char_p = set_no_char;
+#ifdef TEXXET
+ currinf.dir = 1;
+ geom_scan_frame = NULL; /* indicates we're not scanning */
+#endif
+ for (;;) {
+ ch = xone(fp);
+ if (ch <= (ubyte)(SETCHAR0 + 127))
+ DVI_H += char_proc(fp, info, ch);
+ else if (FNTNUM0 <= ch && ch <= (ubyte) (FNTNUM0 + 63)) {
+ change_font((unsigned long)(ch - FNTNUM0));
+ }
+ else {
+ long a, b;
+
+ switch (ch) {
+ case SET1:
+ case PUT1:
+ a = char_proc(fp, info, xone(fp));
+ if (ch != PUT1)
+ DVI_H += a;
+ break;
+
+ case SET2:
+ case PUT2:
+ if (!resource.omega)
+ dvi_fmt_error("%s:%d: draw_part: op-code %d only works with the \"-omega\" option",
+ __FILE__, __LINE__, ch);
+ else {
+#ifdef TEXXET
+ char_proc(fp, info, xnum(fp, 2));
+#else
+ a = char_proc(fp, info, xnum(fp, 2));
+ if (ch != PUT2)
+ DVI_H += a;
+#endif
+ }
+ break;
+
+ case SETRULE:
+ /* Be careful, dvicopy outputs rules with
+ height = 0x80000000. We don't want any
+ SIGFPE here. */
+ a = xsfour(fp);
+ b = xspell_conv(xsfour(fp));
+ if (a >= 0 && b >= 0
+#ifdef TEXXET
+ && geom_scan_frame == NULL
+#endif
+ ) {
+ /* is this a geom scan? */
+ if (info->geom_special != NULL)
+ geom_do_rule(info, xspell_conv(a), b);
+ }
+ DVI_H += DIR * b;
+ break;
+
+ case PUTRULE:
+ a = xspell_conv(xsfour(fp));
+ b = xspell_conv(xsfour(fp));
+ if (a >= 0 && b >= 0
+#ifdef TEXXET
+ && geom_scan_frame == NULL
+#endif
+ ) {
+ /* is this a geom scan? */
+ if (info->geom_special != NULL)
+ geom_do_rule(info, a, b);
+ }
+ break;
+
+ case NOP:
+ break;
+
+ case BOP:
+ xskip(fp, (long)11 * 4);
+ DVI_H = G_OFFSET_X;
+ DVI_V = G_OFFSET_Y;
+ PXL_V = xpixel_conv(DVI_V);
+ WW = XX = YY = ZZ = 0;
+ /* create pagebreak in character scan */
+ if (info->geom_special == NULL) {
+ do_newpage(info);
+ }
+ break;
+
+ case PUSH:
+ if (geom_current_frame->next == NULL) {
+ struct frame *newp = xmalloc(sizeof *newp);
+
+ geom_current_frame->next = newp;
+ newp->prev = geom_current_frame;
+ newp->next = NULL;
+ }
+ geom_current_frame = geom_current_frame->next;
+ geom_current_frame->data = currinf.data;
+ break;
+
+ case POP:
+ if (geom_current_frame == minframe)
+ dvi_fmt_error("more POPs than PUSHes");
+ currinf.data = geom_current_frame->data;
+ geom_current_frame = geom_current_frame->prev;
+ break;
+
+#ifdef TEXXET
+ case SREFL:
+ if (geom_scan_frame == NULL) {
+ /* we're not scanning: save some info. */
+ oldinfo = currinf;
+ oldmaxchar = maxchar;
+ if (!currinf.virtual)
+ file_pos = xtell(fp, currinf.pos);
+ geom_scan_frame = geom_current_frame; /* start scanning */
+ refl_count = 0;
+ break;
+ }
+ /* we are scanning */
+ if (geom_current_frame == geom_scan_frame)
+ ++refl_count;
+ break;
+
+ case EREFL:
+ if (geom_scan_frame != NULL) { /* if we're scanning */
+ if (geom_current_frame == geom_scan_frame
+ && --refl_count < 0) {
+ /* we've hit the end of our scan */
+ geom_scan_frame = NULL;
+ /* first: push */
+ if (geom_current_frame->next == NULL) {
+ struct frame *newp = xmalloc(sizeof *newp);
+
+ geom_current_frame->next = newp;
+ newp->prev = geom_current_frame;
+ newp->next = NULL;
+ }
+ geom_current_frame = geom_current_frame->next;
+ geom_current_frame->data = currinf.data;
+ /* next: restore old file position, XX, etc. */
+ if (!currinf.virtual) {
+ off_t bgn_pos = xtell(fp, G_dvi_buf_ptr);
+
+ if (file_pos >= bgn_pos) {
+ oldinfo.pos = dvi_buffer + (file_pos - bgn_pos);
+ oldinfo.end = currinf.end;
+ }
+ else {
+ (void)lseek(fileno(fp), file_pos,
+ SEEK_SET);
+ oldinfo.pos = oldinfo.end;
+ }
+ }
+ currinf = oldinfo;
+ maxchar = oldmaxchar;
+ /* and then: recover position info. */
+ DVI_H = geom_current_frame->data.dvi_h;
+ DVI_V = geom_current_frame->data.dvi_v;
+ PXL_V = geom_current_frame->data.pxl_v;
+ /* and finally, reverse direction */
+ currinf.dir = -currinf.dir;
+ }
+ break;
+ }
+ /* we're not scanning, */
+ /* so just reverse direction and then pop */
+ currinf.dir = -currinf.dir;
+ currinf.data = geom_current_frame->data;
+ geom_current_frame = geom_current_frame->prev;
+ break;
+#endif /* TEXXET */
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ DVI_H += DIR * xspell_conv(xsnum(fp, ch - RIGHT1 + 1));
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ WW = xspell_conv(xsnum(fp, ch - W0));
+ case W0:
+ DVI_H += DIR * WW;
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ XX = xspell_conv(xsnum(fp, ch - X0));
+ case X0:
+ DVI_H += DIR * XX;
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ DVI_V += xspell_conv(xsnum(fp, ch - DOWN1 + 1));
+ PXL_V = xpixel_conv(DVI_V);
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ YY = xspell_conv(xsnum(fp, ch - Y0));
+ case Y0:
+ DVI_V += YY;
+ PXL_V = xpixel_conv(DVI_V);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ ZZ = xspell_conv(xsnum(fp, ch - Z0));
+ case Z0:
+ DVI_V += ZZ;
+ PXL_V = xpixel_conv(DVI_V);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ case FNT4:
+ change_font(xnum(fp, ch - FNT1 + 1));
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ a = xnum(fp, ch - XXX1 + 1);
+ if (a > 0) {
+ char *str = read_special(fp, a);
+
+ /* is this a geom scan? */
+ if (info->geom_special != NULL) {
+ /* process the bounding box */
+ geom_do_special(info, str, current_dimconv);
+ /* process the specials we're looking for */
+ info->geom_special(info, str, a);
+ }
+ }
+ break;
+
+ case FNTDEF1:
+ case FNTDEF2:
+ case FNTDEF3:
+ case FNTDEF4:
+ xskip(fp, (long)(12 + ch - FNTDEF1 + 1));
+ a = (long)xone(fp);
+ xskip(fp, a + (long)xone(fp));
+ break;
+
+#ifndef TEXXET
+ case SREFL:
+ case EREFL:
+#endif
+ case PRE:
+ case POST:
+ case POSTPOST:
+ case EOP:
+ default:
+ return;
+
+ } /* end switch */
+ } /* end else (ch not a SETCHAR or FNTNUM) */
+ } /* end for */
+}
+
+
+/*
+ * Main scanning routine.
+ */
+
+void
+geom_scan(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
+ FILE *fp, struct scan_info *info, int pageno)
+{
+ volatile off_t pos_save = 0;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+
+#if PS
+ if (info->geom_special != NULL && scanned_page < current_page) {
+ fprintf(stderr, "shouldn't happen: %d >= %d!\n", scanned_page, current_page);
+ return; /* should not happen */
+ }
+#endif
+
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+
+ (void) lseek(fileno(fp), pageinfo_get_offset(pageno), SEEK_SET);
+
+ currinf_save = currinf;
+ maxchar_save = maxchar;
+
+ memset((char *)&currinf.data, '\0', sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ if (!setjmp(info->done_env)) {
+ geom_scan_part(char_proc, fp, info, geom_current_frame = &geom_frame0, dimconv);
+ }
+
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void)lseek(fileno(fp), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
+ }
+}
+
+
+/*
+ * Routines for source special lookup
+ */
+
+struct src_spec_data {
+ long x, y; /* coordinates we're looking for */
+ unsigned long distance; /* best distance so far */
+ Boolean recent_in_best; /* most recent string == XXX->best */
+ struct src_parsed_special best; /* best special so far */
+ struct src_parsed_special recent; /* most recent special */
+};
+
+void
+src_parse(const char *str, int str_len, struct src_parsed_special *parsed)
+{
+ const char *p = str;
+
+ if (*p >= '0' && *p <= '9') {
+ parsed->line = atoi(p);
+ do {
+ ++p;
+ str_len--;
+ }
+ while (*p >= '0' && *p <= '9');
+ }
+
+ parsed->col = 0;
+ if (*p == ':') {
+ ++p;
+ str_len--;
+ parsed->col = atoi(p);
+ while (*p >= '0' && *p <= '9') {
+ ++p;
+ str_len--;
+ }
+ }
+
+ if (*p == ' ') {
+ ++p;
+ str_len--;
+ }
+
+ if (*p != '\0') {
+ size_t len = str_len + 1;
+
+ if (len > parsed->filename_len) {
+ if (parsed->filename_len != 0)
+ free(parsed->filename);
+ parsed->filename_len = (len & -8) + 64; /* rounding? */
+ parsed->filename = xmalloc(parsed->filename_len);
+ }
+ memcpy(parsed->filename, p, len);
+ }
+}
+
+static void
+src_spec_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
+{
+ struct geom_info *g_info = (struct geom_info *)info->data;
+ struct src_spec_data *data = g_info->geom_data;
+ unsigned long distance;
+
+ distance = 0;
+
+ if (data->x < ulx)
+ distance += (ulx - data->x) * (ulx - data->x);
+ else if (data->x > lrx)
+ distance += (data->x - lrx) * (data->x - lrx);
+
+ if (data->y < uly)
+ distance += (uly - data->y) * (uly - data->y);
+ else if (data->y > lry)
+ distance += (data->y - lry) * (data->y - lry);
+
+ if (distance < data->distance) {
+ data->distance = distance;
+
+ /* Copy it over */
+ if (!data->recent_in_best) {
+ data->best.line = data->recent.line;
+ data->best.col = data->recent.col;
+ if (data->recent.filename_len != 0) {
+ if (data->best.filename_len < data->recent.filename_len) {
+ if (data->best.filename_len != 0)
+ free(data->best.filename);
+ data->best.filename_len = data->recent.filename_len;
+ data->best.filename = xmalloc(data->best.filename_len);
+ }
+ memcpy(data->best.filename, data->recent.filename,
+ data->recent.filename_len);
+ }
+
+ data->recent_in_best = True;
+ }
+
+ /* Quit early if we've found our glyph. */
+ if (distance == 0 && data->best.filename_len != 0) {
+ longjmp(info->done_env, 1);
+ }
+ }
+}
+
+static void
+src_spec_special(struct scan_info *info, const char *str, int str_len)
+{
+ struct geom_info *g_info = (struct geom_info *)info->data;
+ struct src_spec_data *data = g_info->geom_data;
+
+ if (memcmp(str, "src:", 4) != 0)
+ return;
+
+ src_parse(str + 4, str_len - 4, &data->recent);
+
+ /*
+ * If this is the first special on the page, we may already have
+ * spotted the nearest box.
+ */
+
+ if (data->best.filename_len == 0) {
+ data->best.line = data->recent.line;
+ data->best.col = data->recent.col;
+ if (data->recent.filename_len != 0) {
+ if (data->best.filename_len < data->recent.filename_len) {
+ if (data->best.filename_len != 0)
+ free(data->best.filename);
+ data->best.filename_len = data->recent.filename_len;
+ data->best.filename = xmalloc(data->best.filename_len);
+ }
+ memcpy(data->best.filename, data->recent.filename,
+ data->recent.filename_len);
+
+ data->recent_in_best = True;
+ }
+
+ if (data->distance == 0) {
+ longjmp(info->done_env, 1);
+ }
+ }
+ else
+ data->recent_in_best = False;
+}
+
+/*
+ * Routines for reverse searches on other pages.
+ */
+
+static struct src_parsed_special found;
+/* static jmp_buf scan_env; */
+
+static Boolean
+scan_first_src_spcl(char *str, int str_len, void *data)
+{
+ UNUSED(data);
+ if (memcmp(str, "src:", 4) != 0)
+ return False;
+
+ src_parse(str + 4, str_len - 4, &found);
+
+ return True;
+}
+
+static Boolean
+scan_last_src_spcl(char *str, int str_len, void *data)
+{
+ UNUSED(data);
+ if (memcmp(str, "src:", 4) != 0)
+ return False;
+
+ src_parse(str + 4, str_len - 4, &found);
+
+ return True;
+}
+
+
+/* Replace (pseudo-)format arguments in NULL-terminated argv list as follows:
+ * %f -> filename, %l -> linenumber, %c -> column number.
+ * If %f or %l are not specified, they are appended as %f and +%l.
+ * If colno == 0, no %c argument is provided.
+ */
+static char **
+src_format_arguments(char **argv, const char *filename, int lineno, int colno)
+{
+ size_t i;
+ Boolean found_filename = False;
+ Boolean found_lineno = False;
+ /* index of argv elem that contained a deleted column number specifier */
+ int colno_deleted = -1;
+
+ for (i = 0; argv[i] != NULL; i++) {
+ char *ptr, *curr = argv[i];
+ while ((ptr = strchr(curr, '%')) != NULL) {
+ char *p1;
+ if ((p1 = strchr("flc", ptr[1])) != NULL) { /* we have a formatting char */
+ char digit_arg[LENGTH_OF_INT];
+ const char *new_elem = NULL;
+ /* remember offsets and lengths */
+ size_t l_init = ptr - argv[i];
+ size_t l_rest = strlen(ptr + 2) + 1;
+ size_t l_mid;
+
+ if (*p1 == 'f') {
+ found_filename = True;
+ new_elem = filename;
+ }
+ else if (*p1 == 'l') {
+ found_lineno = True;
+ sprintf(digit_arg, "%d", lineno);
+ new_elem = digit_arg;
+ }
+ else if (*p1 == 'c') {
+ if (colno == 0) { /* if we have no column information, don't provide this argument */
+ memmove(ptr, ptr + 2, l_rest);
+ curr = ptr;
+ colno_deleted = i;
+ continue;
+ }
+ sprintf(digit_arg, "%d", colno);
+ new_elem = digit_arg;
+ }
+
+ l_mid = strlen(new_elem);
+
+ argv[i] = xrealloc(argv[i], strlen(argv[i]) + l_mid + 1);
+ curr = argv[i] + l_init; /* need to reinitialize it because of realloc */
+ memmove(curr + l_mid, curr + 2, l_rest);
+ memcpy(curr, new_elem, l_mid);
+ curr += l_mid;
+ }
+ else if (ptr[1] == '%') { /* escaped %, skip both */
+ curr = ptr + 2;
+ }
+ else {
+ curr = ptr + 1;
+ }
+ }
+ }
+
+ /* append line number and file name arguments if they were not specified */
+ if (!found_lineno) {
+ i++;
+ argv = xrealloc(argv, (i + 1) * sizeof *argv);
+ argv[i - 1] = xmalloc(LENGTH_OF_INT + 2);
+ sprintf(argv[i - 1], "+%d", lineno);
+ argv[i] = NULL;
+ }
+
+ if (!found_filename) {
+ i++;
+ argv = xrealloc(argv, (i + 1) * sizeof *argv);
+ argv[i - 1] = xstrdup(filename);
+ argv[i] = NULL;
+ }
+
+ /* if we deleted %c, remove from argv if it's empty now */
+ if (colno_deleted > -1 && strlen(argv[colno_deleted]) == 0) {
+ for (i = colno_deleted; argv[i] != NULL; i++) {
+ argv[i] = argv[i + 1];
+
+ }
+ }
+ return argv;
+}
+
+
+static void
+src_spawn_editor(const struct src_parsed_special *parsed)
+{
+ char *expanded_filename;
+ char **argv;
+ const char *p;
+ char *q;
+ int i;
+
+ struct stat buf;
+
+ /* first, determine the editor if necessary */
+ if (resource.editor == NULL || *resource.editor == '\0') {
+ p = getenv("XEDITOR");
+ if (p != NULL)
+ resource.editor = xstrdup(p);
+ else {
+
+ p = getenv("VISUAL");
+ if (p == NULL) {
+ p = getenv("EDITOR");
+ if (p == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ /* help text */
+ "Use the \"-editor\" command-line opion, the X resource "
+ "\"xdvi.editor\" or one of the following environment variables "
+ "to select the editor for source specials: "
+ "\"XEDITOR\", \"VISUAL\" or \"EDITOR\".\n"
+ "See the xdvi man page for more information on source specials "
+ "and the editor options.",
+ /* message */
+ "No custom editor set - using vi as default.");
+ p = "vi";
+ }
+ }
+ q = xmalloc(strlen(p) + 10);
+ memcpy(q, "xterm -e ", 9);
+ strcpy(q + 9, p);
+ resource.editor = q;
+ }
+ }
+
+ /* now try to open the file; find_file allocates space for expanded_filename */
+ if ((expanded_filename = find_file(parsed->filename, &buf, kpse_tex_format)) == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL,
+ "File \"%s\" not found, couldn't jump to special\n\"%s:%d\"\n",
+ parsed->filename, parsed->filename, parsed->line);
+ }
+ else {
+ TRACE_SRC((stderr, "source file \"%s\" expanded to \"%s\"\n", parsed->filename, expanded_filename));
+ if (buf.st_mtime > globals.dvi_file.time) {
+ statusline_print(STATUS_FOREVER,
+ "Warning: TeX file is newer than dvi file - "
+ "source special information might be wrong.");
+ }
+
+ /* this allocates argv */
+ argv = src_format_arguments(get_separated_list(resource.editor, " \t", True),
+ expanded_filename, parsed->line, parsed->col);
+
+ fork_process(argv[0], False, NULL, NULL, NULL, argv);
+
+ free(expanded_filename);
+ for (i = 0; argv[i] != NULL; i++)
+ free(argv[i]);
+ free(argv);
+ }
+}
+
+off_t
+save_file_status(FILE *fp, struct drawinf *currinf_save, ubyte *maxchar_save)
+{
+ off_t pos_save = 0;
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(fp), 0L, SEEK_CUR)
+ - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+
+ *currinf_save = currinf;
+ *maxchar_save = maxchar;
+ return pos_save;
+}
+
+void
+restore_file_status(FILE *fp, struct drawinf currinf_save, ubyte maxchar_save, off_t pos_save)
+{
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void)lseek(fileno(fp), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
+ }
+}
+
+
+
+/*
+ * The main routine for source specials (reverse search).
+ */
+void
+source_reverse_search(int x, int y, wide_bool call_editor)
+{
+ struct scan_info info;
+ struct geom_info g_info;
+ struct src_spec_data data;
+ struct src_parsed_special *foundp;
+
+ info.geom_special = src_spec_special;
+
+ g_info.geom_box = src_spec_box;
+ g_info.geom_data = &data;
+
+ info.data = &g_info;
+
+ data.x = x;
+ data.y = y;
+ data.distance = 0xffffffff;
+ data.recent_in_best = True;
+ data.best.filename_len = data.recent.filename_len = 0;
+ foundp = &data.best;
+
+ geom_scan(geom_do_char, globals.dvi_file.bak_fp, &info, current_page);
+
+ if (data.best.filename_len == 0) {
+ /*
+ * nothing found on current page;
+ * scan next and previous pages with increasing offset
+ */
+ volatile int upper, lower;
+ volatile off_t pos_save;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+
+ /* Save file position */
+ pos_save = save_file_status(globals.dvi_file.bak_fp, &currinf_save, &maxchar_save);
+
+ upper = lower = current_page;
+ found.filename_len = 0; /* mark it as empty */
+ for (;;) {
+ if (++upper < total_pages) {
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(upper), SEEK_SET);
+ memset((char *)&currinf.data, '\0', sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ if (spcl_scan(scan_first_src_spcl, NULL, True, globals.dvi_file.bak_fp)) {
+ lower = upper;
+ break;
+ }
+ }
+ else if (lower < 0)
+ break;
+
+ if (--lower >= 0) {
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(lower), SEEK_SET);
+
+ memset((char *)&currinf.data, '\0', sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ (void)spcl_scan(scan_last_src_spcl, NULL, False, globals.dvi_file.bak_fp);
+ if (found.filename_len != 0)
+ break;
+ }
+ }
+
+ if (found.filename_len != 0)
+ statusline_print(STATUS_MEDIUM,
+ "No source specials on this page - nearest on page %d",
+ lower + globals.pageno_correct);
+ else {
+ /* nothing found at all; complain */
+ XBell(DISP, 0);
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ /* helptext */
+ reverse_search_helptext,
+ /* popup */
+ "No source specials in this DVI file - couldn't do reverse search.");
+ }
+
+ /* Restore file status. */
+ restore_file_status(globals.dvi_file.bak_fp, currinf_save, maxchar_save, pos_save);
+
+ foundp = &found;
+ }
+
+ if (data.recent.filename_len != 0)
+ free(data.recent.filename);
+
+ if (foundp->filename_len != 0) {
+ if (call_editor) {
+ src_spawn_editor(foundp);
+ }
+ else {
+ statusline_print(STATUS_MEDIUM, "nearest special at (%d,%d): \"%s:%d\"",
+ x / currwin.shrinkfactor, y / currwin.shrinkfactor, foundp->filename, foundp->line);
+ }
+ free(foundp->filename);
+ }
+}
+
+
+/*
+ * Debug routines for source special display (highlight the first box
+ * after each source special, or highlight each box).
+ */
+
+struct src_spec_show_data {
+ Boolean do_this_one; /* flag set after source special */
+ Boolean do_them_all; /* flag to reset the above to */
+};
+
+static void
+src_spec_show_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
+{
+ struct geom_info *g_info = (struct geom_info *)info->data;
+ struct src_spec_show_data *data = g_info->geom_data;
+
+ if (data->do_this_one) {
+ long x = ulx / mane.shrinkfactor;
+ long y = uly / mane.shrinkfactor;
+
+ XDrawRectangle(DISP, mane.win, globals.gc.high,
+ x - mane_base_x, y - mane_base_y,
+ lrx / mane.shrinkfactor - x,
+ lry / mane.shrinkfactor - y);
+ data->do_this_one = data->do_them_all;
+ }
+}
+
+static void
+src_spec_show_special(struct scan_info *info, const char *str, int str_len)
+{
+ /* if (memcmp(str, "src:", 4) != 0) */
+ /* return; */
+ struct geom_info *g_info = (struct geom_info *)info->data;
+ UNUSED(str_len);
+ XDVI_INFO((stdout, "special: %s", str));
+ ((struct src_spec_show_data *)g_info->geom_data)->do_this_one = True;
+}
+
+void
+source_special_show(wide_bool do_them_all)
+{
+ struct scan_info info;
+ struct geom_info g_info;
+ struct src_spec_show_data src_data;
+
+ info.geom_special = src_spec_show_special;
+
+ g_info.geom_box = src_spec_show_box;
+ g_info.geom_data = &src_data;
+
+ info.data = &g_info;
+
+ src_data.do_this_one = src_data.do_them_all = do_them_all;
+
+ geom_scan(geom_do_char, globals.dvi_file.bak_fp, &info, current_page);
+}
+
+
+/*
+ * Routines for forward search (look up a source line).
+ *
+ * The general procedure is:
+ * (1) Use spcl_scan() to find the page containing the line (or at
+ * least the closest line). This could be optimized further.
+ * (2) Use geom_scan_part() to find the exact location of the source
+ * special, and the box to highlight.
+ */
+
+/* These variables are referenced by src_scan_special(). */
+
+static int src_this_line;
+static Boolean src_this_file_equal;
+static int src_line;
+static int src_col;
+static const char *src_file;
+static int src_page;
+/* static jmp_buf src_env; */
+static Boolean found_src;
+static unsigned long best_distance;
+static unsigned long best_col_dist;
+static int best_line;
+static int best_page;
+static off_t best_offset;
+static off_t max_offset;
+
+/* Some of the above, plus these below, are used by geom_scan_part(). */
+
+static Boolean src_fwd_active;
+
+#define BBOX_INFO_MAXIDX 8 /* maximum number of bounding boxes */
+
+/* list of bounding boxes */
+struct bbox_info {
+ long min_x, max_x, min_y, max_y;
+ long spcl_min_x, spcl_max_x, spcl_min_y, spcl_max_y;
+} g_bbox_info[BBOX_INFO_MAXIDX];
+
+/* current index in g_bbox_info[] */
+static size_t bbox_info_idx = 0;
+
+static Boolean
+src_scan_special(char *str, int str_len, void *data)
+{
+ char *p;
+ int col = 0;
+ unsigned long distance;
+ unsigned long col_dist;
+
+ UNUSED(data);
+ if (memcmp(str, "src:", 4) != 0)
+ return False;
+
+ found_src = True;
+
+ p = str + 4;
+ str_len -= 4;
+
+ if (*p >= '0' && *p <= '9') {
+ src_this_line = atoi(p);
+ do {
+ ++p;
+ str_len--;
+ }
+ while (*p >= '0' && *p <= '9');
+ }
+
+ if (*p == ':') {
+ ++p;
+ str_len--;
+ col = atoi(p);
+ while (*p >= '0' && *p <= '9') {
+ ++p;
+ str_len--;
+ }
+ }
+
+ if (*p == ' ') {
+ ++p;
+ str_len--;
+ }
+
+ /* src specials might omit the file name when it had already
+ been specified on the page; so skip the test when the
+ special ends right here:
+ */
+ if (*p != '\0') {
+ ASSERT(globals.dvi_file.dirname != NULL, "DVI name should be set here");
+ src_this_file_equal = src_compare(p, str_len, src_file, globals.dvi_file.dirname, globals.dvi_file.dirlen);
+ }
+
+ if (!src_this_file_equal)
+ return False;
+
+ distance = (src_line > src_this_line
+ ? src_line - src_this_line
+ : 2 * (src_this_line - src_line)); /* favor earlier lines */
+
+ if (distance < best_distance) { /* found a better line */
+ best_distance = distance;
+ best_line = src_this_line;
+ best_page = src_page;
+ max_offset = best_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
+ }
+ else if (distance == best_distance) { /* still on a good line, remember diff */
+ max_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
+ }
+
+ if (distance == 0 && best_distance == 0) { /* found a better col */
+ col_dist = (src_col > col ? src_col - col : 2 * (col - src_col));
+
+ if (col_dist < best_col_dist) {
+ best_col_dist = col_dist;
+ best_page = src_page;
+ max_offset = best_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
+ }
+ else if (col_dist == best_col_dist) {
+ max_offset = xtell(globals.dvi_file.bak_fp, currinf.pos);
+ }
+ }
+ return True;
+}
+
+static Boolean
+htex_scan_special(char *str, int str_len, void *data)
+{
+ UNUSED(data);
+
+ if (g_anchor_pos == NULL)
+ return False;
+
+ /* first, hypertex specials */
+ if (memicmp(str, "html:", strlen("html:")) == 0) {
+ size_t offset = strlen("html:");
+ str += offset;
+ str_len -= offset;
+
+ while (*str == ' ' || *str == '\t') {
+ str++;
+ str_len--;
+ }
+
+ if (memicmp(str, "<a name", strlen("<a name")) != 0)
+ return False;
+
+ offset = strlen("<a name");
+ str += offset;
+ str_len -= offset;
+ str_len--; /* for the closing > */
+
+ /* skip over spaces, = and open quotes */
+ while (*str == ' ' || *str == '=') {
+ str++;
+ str_len--;
+ }
+ if (*str == '"') {
+ str++;
+ str_len -= 2; /* don't compare closing quote */
+ }
+
+ /* fprintf(stderr, "comparing: |%s|%s|%d\n", str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)); */
+ if (memcmp(str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)) == 0)
+ return True;
+ else
+ return False;
+ }
+ /* then, hdvips specials */
+ else if (memicmp(str, "ps:", 3) == 0 && g_anchor_pos != NULL) {
+ str += 3;
+ if (memicmp(str, "sdict begin ", strlen("sdict begin ")) == 0) {
+ char *ptr = NULL, *pptr = NULL;
+ str += strlen("sdict begin ");
+ if ((ptr = strstr(str, "/View")) != NULL
+ && (ptr = strchr(ptr, '(')) != NULL
+ && (pptr = strchr(ptr + 1, ')')) != NULL) {
+ if (memcmp(ptr + 1, g_anchor_pos, pptr - ptr - 1) == 0
+ && g_anchor_pos[pptr - ptr - 1] == '\0') {
+ return True;
+ }
+ }
+ }
+ return False;
+ }
+ else {
+ return False;
+ }
+}
+
+static void
+htex_scan_special_noreturn(struct scan_info *info, const char *str, int str_len)
+{
+ struct geom_info *g_info = (struct geom_info *)info->data;
+
+ /* first, hypertex specials */
+ if (memcmp(str, "html:", strlen("html:")) == 0) {
+ size_t offset = strlen("html:");
+ str += offset;
+ str_len -= offset;
+
+ while (*str == ' ' || *str == '\t') {
+ str++;
+ str_len--;
+ }
+
+ if (memicmp(str, "<a name", strlen("<a name")) != 0)
+ return;
+
+ offset = strlen("<a name");
+ str += offset;
+ str_len -= offset;
+ str_len--; /* for the closing > */
+
+ /* skip over spaces, = and open quotes */
+ while (*str == ' ' || *str == '=') {
+ str++;
+ str_len--;
+ }
+ if (*str == '"') {
+ str++;
+ str_len -= 2; /* don't compare closing quote */
+ }
+
+ if (g_anchor_pos != NULL
+ && memcmp(str, g_anchor_pos, MAX((size_t)str_len, g_anchor_len)) == 0) {
+ *((int *)g_info->geom_data) = pixel_conv(DVI_V);
+ longjmp(info->done_env, 1);
+ }
+ }
+ /* then, hdvips specials */
+ else if (memicmp(str, "ps:", 3) == 0 && g_anchor_pos != NULL) {
+ str += 3;
+ if (memicmp(str, "sdict begin ", strlen("sdict begin ")) == 0) {
+ char *ptr = NULL, *pptr = NULL;
+ str += strlen("sdict begin ");
+ if ((ptr = strstr(str, "/View")) != NULL
+ && (ptr = strchr(ptr, '(')) != NULL
+ && (pptr = strchr(ptr + 1, ')')) != NULL) {
+ if (memcmp(ptr + 1, g_anchor_pos, pptr - ptr - 1) == 0
+ && g_anchor_pos[pptr - ptr - 1] == '\0') {
+ *((int *)g_info->geom_data) = pixel_conv(DVI_V);
+ longjmp(info->done_env, 1);
+ }
+ }
+ }
+ }
+}
+
+static void
+src_spec_fwd_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
+{
+ /* Heuristic value to detect column breaks: A negative vertical
+ offset to the next glyph larger than BBOX_OFF will create a new
+ bounding box. The amount is in unshrunken pixels, i.e. 120
+ \approx 1 Line of 12pt Text. */
+ static const int BBOX_OFF = 360;
+
+ UNUSED(info);
+ if (src_fwd_active) {
+ /* probably a column break, create new box */
+ if (lry < g_bbox_info[bbox_info_idx].max_y - BBOX_OFF
+ && lrx > g_bbox_info[bbox_info_idx].max_x + 50) {
+ if (bbox_info_idx < BBOX_INFO_MAXIDX - 1) {
+ bbox_info_idx++;
+
+ g_bbox_info[bbox_info_idx].min_y = g_bbox_info[bbox_info_idx].min_x = LONG_MAX;
+ g_bbox_info[bbox_info_idx].max_x = g_bbox_info[bbox_info_idx].max_y = 0;
+ }
+ }
+ if (ulx < g_bbox_info[bbox_info_idx].min_x) {
+ g_bbox_info[bbox_info_idx].min_x = ulx;
+ }
+ if (uly < g_bbox_info[bbox_info_idx].min_y) {
+ g_bbox_info[bbox_info_idx].min_y = uly;
+ }
+ if (lrx > g_bbox_info[bbox_info_idx].max_x)
+ g_bbox_info[bbox_info_idx].max_x = lrx;
+ if (lry > g_bbox_info[bbox_info_idx].max_y) {
+ g_bbox_info[bbox_info_idx].max_y = lry;
+ }
+ }
+}
+
+/* dummy procedure for hyperlinks; we don't need geometry info for these. */
+static void
+htex_dummy_box(struct scan_info *info, long ulx, long uly, long lrx, long lry)
+{
+ UNUSED(info);
+ UNUSED(ulx);
+ UNUSED(uly);
+ UNUSED(lrx);
+ UNUSED(lry);
+ return;
+}
+
+static void
+src_spec_fwd_special(struct scan_info *info, const char *str, int str_len)
+{
+ long pos;
+ UNUSED(str_len);
+
+ if (memcmp(str, "src:", 4) != 0) /* if no source special */
+ return;
+
+ pos = xtell(globals.dvi_file.bak_fp, currinf.pos);
+ if (pos >= best_offset)
+ src_fwd_active = True;
+
+ if (src_fwd_active) {
+ if (pos > max_offset)
+ longjmp(info->done_env, 1);
+
+ if (G_PXL_H < g_bbox_info[bbox_info_idx].spcl_min_x)
+ g_bbox_info[bbox_info_idx].spcl_min_x = G_PXL_H;
+ if (G_PXL_H > g_bbox_info[bbox_info_idx].spcl_max_x)
+ g_bbox_info[bbox_info_idx].spcl_max_x = G_PXL_H;
+ if (PXL_V < g_bbox_info[bbox_info_idx].spcl_min_y)
+ g_bbox_info[bbox_info_idx].spcl_min_y = PXL_V;
+ if (PXL_V > g_bbox_info[bbox_info_idx].spcl_max_y)
+ g_bbox_info[bbox_info_idx].spcl_max_y = PXL_V;
+
+ }
+}
+
+/*
+ * Routine to actually draw the box.
+ */
+
+static void
+source_fwd_draw_box(void)
+{
+ if (globals.src.fwd_box_page != current_page) {
+ globals.src.fwd_box_page = -1; /* different page---clear it */
+ }
+ else {
+ size_t i;
+ static const int padding = 15;
+
+ /* fix oversplitting by heuristics, by merging box n with box n+1 if they overlap */
+ for (i = 0; i < bbox_info_idx; i++) {
+ if (g_bbox_info[i].min_x == LONG_MAX)
+ continue;
+ if ((g_bbox_info[i+1].min_x < g_bbox_info[i].max_x
+ && g_bbox_info[i+1].min_y < g_bbox_info[i].max_y) ||
+ (g_bbox_info[i].min_x < g_bbox_info[i+1].max_x
+ && g_bbox_info[i].min_y < g_bbox_info[i+1].max_y)) { /* overlap */
+ g_bbox_info[i].min_x = MIN(g_bbox_info[i].min_x, g_bbox_info[i+1].min_x);
+ g_bbox_info[i].min_y = MIN(g_bbox_info[i].min_y, g_bbox_info[i+1].min_y);
+ g_bbox_info[i].max_x = MAX(g_bbox_info[i].max_x, g_bbox_info[i+1].max_x);
+ g_bbox_info[i].max_y = MAX(g_bbox_info[i].max_y, g_bbox_info[i+1].max_y);
+ bbox_info_idx--;
+ }
+ }
+
+ for (i = 0; i <= bbox_info_idx; i++) {
+ int min_x, min_y, max_x, max_y;
+
+ volatile XPoint ul, ur, ll, lr;
+
+ if (g_bbox_info[i].min_x == LONG_MAX) {
+ /* If no glyphs or rules, use hot point of special instead. */
+ g_bbox_info[i].min_x = g_bbox_info[i].spcl_min_x;
+ g_bbox_info[i].min_y = g_bbox_info[i].spcl_min_y;
+ g_bbox_info[i].max_x = g_bbox_info[i].spcl_max_x;
+ g_bbox_info[i].max_y = g_bbox_info[i].spcl_max_y;
+ }
+
+ min_x = (g_bbox_info[i].min_x - padding) / mane.shrinkfactor - mane_base_x;
+ min_y = (g_bbox_info[i].min_y - padding) / mane.shrinkfactor - mane_base_y;
+ max_x = (g_bbox_info[i].max_x + padding) / mane.shrinkfactor - mane_base_x;
+ max_y = (g_bbox_info[i].max_y + padding) / mane.shrinkfactor - mane_base_y;
+
+ ul.x = min_x;
+ ul.y = min_y;
+
+ ur.x = max_x;
+ ur.y = min_y;
+
+ ll.x = min_x;
+ ll.y = max_y;
+
+ lr.x = max_x;
+ lr.y = max_y;
+
+ if (i == 0 && bbox_info_idx == 0) { /* only 1 bounding box */
+ XDrawRectangle(DISP, mane.win, globals.gc.high,
+ min_x, min_y, max_x - min_x, max_y - min_y);
+ }
+ else if (i == 0) { /* draw first bbox with open bottom */
+ XPoint points[4];
+ points[0] = ll;
+ points[1] = ul;
+ points[2] = ur;
+ points[3] = lr;
+ XDrawLines(DISP, mane.win, globals.gc.high, points, 4, CoordModeOrigin);
+ }
+ else if (i > 0 && i < bbox_info_idx) { /* draw middle box with open top and open bottom */
+ XPoint points[2];
+ points[0] = ul;
+ points[1] = ll;
+ XDrawLines(DISP, mane.win, globals.gc.high, points, 2, CoordModeOrigin);
+ points[0] = ur;
+ points[1] = lr;
+ XDrawLines(DISP, mane.win, globals.gc.high, points, 2, CoordModeOrigin);
+ }
+ else { /* draw last box with open top */
+ XPoint points[4];
+ points[0] = ul;
+ points[1] = ll;
+ points[2] = lr;
+ points[3] = ur;
+ XDrawLines(DISP, mane.win, globals.gc.high, points, 4, CoordModeOrigin);
+ }
+ }
+ }
+}
+
+#if 0
+#include<asm/msr.h>
+unsigned long time_start=0, time_end=0;
+#endif
+
+void
+source_forward_search(const char *str)
+{
+ volatile off_t pos_save = 0;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+ struct scan_info info;
+ struct geom_info g_info;
+
+ TRACE_CLIENT((stderr, "Entering source_forward_search(%s)", str));
+
+ max_offset = 0;
+ src_file = str;
+ while (*src_file == '0')
+ ++src_file;
+ if (*src_file < '1' || *src_file > '9') {
+ XDVI_WARNING((stderr, "Ignoring malformed source special \"%s\"", str));
+ return;
+ }
+ src_line = atoi(src_file);
+ while (*src_file >= '0' && *src_file <= '9')
+ ++src_file;
+
+ src_col = 0;
+ if (*src_file == ':') {
+ ++src_file;
+ src_col = atoi(src_file);
+ while (*src_file >= '0' && *src_file <= '9')
+ ++src_file;
+ }
+
+ if (*src_file == ' ')
+ ++src_file;
+
+ TRACE_CLIENT((stderr, "File = \"%s\", line = %d, col = %d", src_file, src_line, src_col));
+
+ /* Save status of dvi_file reading (in case we hit an error and resume
+ drawing). */
+
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(globals.dvi_file.bak_fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(0), SEEK_SET);
+
+ currinf_save = currinf;
+ maxchar_save = maxchar;
+
+ memset((char *)&currinf.data, '\0', sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ /* Start search over pages */
+#if 0
+ rdtscl(time_start);
+#endif
+
+ found_src = False;
+ best_distance = best_col_dist = ULONG_MAX;
+ src_this_line = 0; /* initialize things that are kept as defaults */
+ src_this_file_equal = False;
+
+ /* These two lines do the actual scanning (first pass). */
+ for (src_page = 0; src_page < total_pages; ++src_page)
+ (void)spcl_scan(src_scan_special, NULL, False, globals.dvi_file.bak_fp);
+
+ if (best_distance == ULONG_MAX) {
+ if (!found_src) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ /* helptext */
+ reverse_search_helptext,
+ /* popup */
+ "No source specials in this DVI file - couldn't do reverse search.");
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ /* helptext */
+ "To enable reverse search, the TeX file has to be compiled with source specials. "
+ "See the xdvi man page (section SOURCE SPECIALS) for details.",
+ /* popup */
+ "No references to source file \"%s\" in DVI file.",
+ src_file);
+ }
+
+ /* Restore file position. */
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
+ }
+
+ return;
+ }
+ TRACE_CLIENT((stderr, "Match: line %d on page %d, offset %lu",
+ best_line, best_page + globals.pageno_correct, (unsigned long)best_offset));
+
+ /*
+ * In this case we don't need to restore maxchar and currinf, since
+ * we won't resume drawing -- we'll jump to a new page instead.
+ */
+
+ /* Move to that page. */
+ goto_page(best_page, resource.keep_flag ? NULL : home, False);
+ page_history_insert(best_page);
+ globals.ev.flags |= EV_NEWPAGE; /* so that existing mark gets erased */
+ /* Now search that particular page. */
+
+ info.geom_special = src_spec_fwd_special;
+
+ g_info.geom_box = src_spec_fwd_box;
+ g_info.geom_data = NULL;
+
+ src_fwd_active = False;
+ bbox_info_idx = 0;
+
+ g_bbox_info[bbox_info_idx].min_x =
+ g_bbox_info[bbox_info_idx].min_y =
+ g_bbox_info[bbox_info_idx].spcl_min_x =
+ g_bbox_info[bbox_info_idx].spcl_min_y = LONG_MAX;
+ g_bbox_info[bbox_info_idx].max_x =
+ g_bbox_info[bbox_info_idx].max_y =
+ g_bbox_info[bbox_info_idx].spcl_max_x =
+ g_bbox_info[bbox_info_idx].spcl_max_y = 0;
+ globals.src.fwd_box_page = -1; /* in case of error, suppress box */
+
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(best_page), SEEK_SET);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ info.data = &g_info;
+
+ if (!setjmp(info.done_env))
+ geom_scan_part(geom_do_char, globals.dvi_file.bak_fp, &info, geom_current_frame = &geom_frame0, dimconv);
+
+ if (!src_fwd_active) {
+ XDVI_ERROR((stderr, "%s:%d: shouldn't happen: geom_scan_part() failed to re-find the special.", __FILE__, __LINE__));
+ }
+ else {
+ long x_min = g_bbox_info[bbox_info_idx].min_x;
+ long y_min = g_bbox_info[bbox_info_idx].min_y;
+ long x_max = g_bbox_info[bbox_info_idx].max_x;
+ long y_max = g_bbox_info[bbox_info_idx].max_y;
+ do_autoscroll = True;
+ globals.src.fwd_box_page = current_page;
+ if (x_min == LONG_MAX || x_max == LONG_MAX) {
+ /* If no glyphs or rules, use hot point of special instead. */
+ x_min = g_bbox_info[bbox_info_idx].spcl_min_x;
+ y_min = g_bbox_info[bbox_info_idx].spcl_min_y;
+ x_max = g_bbox_info[bbox_info_idx].spcl_max_x;
+ y_max = g_bbox_info[bbox_info_idx].spcl_max_y;
+ }
+ scroll_page_if_needed((int)(x_min / currwin.shrinkfactor) + 2, (int)(x_max / currwin.shrinkfactor) - 2,
+ (int)(y_min / currwin.shrinkfactor) + 10, (int)(y_max / currwin.shrinkfactor) - 10);
+ }
+#if 0
+ rdtscl(time_end);
+ printf("time search: %lu\n", time_end - time_start);
+#endif
+}
+
+
+void
+anchor_search(const char *str)
+{
+ off_t pos_save = 0;
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+ volatile int test_page = 0;
+ Boolean found_anchor = False;
+ int y_pos = -1;
+ struct scan_info info;
+ struct geom_info g_info;
+
+ ASSERT(str != NULL, "Argument to anchor_search() musn't be NULL");
+ TRACE_HTEX((stderr, "Entering anchor_search(%s)", str));
+
+ /* Save status of dvi_file reading (in case we hit an error and resume drawing). */
+ if (dvi_pointer_frame != NULL)
+ pos_save = lseek(fileno(globals.dvi_file.bak_fp), 0L, SEEK_CUR) - (dvi_pointer_frame->end - dvi_pointer_frame->pos);
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(0), SEEK_SET);
+
+ currinf_save = currinf;
+ maxchar_save = maxchar;
+
+ memset((char *)&currinf.data, '\0', sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ /* Start search over pages */
+ for (test_page = 0; test_page < total_pages; test_page++) {
+ if (spcl_scan(htex_scan_special, NULL, True, globals.dvi_file.bak_fp)) {
+ found_anchor = True;
+ break;
+ }
+ }
+
+ if (!found_anchor) {
+ /* Restore file position. */
+ maxchar = maxchar_save;
+ currinf = currinf_save;
+
+ if (dvi_pointer_frame != NULL) {
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pos_save, SEEK_SET);
+ dvi_pointer_frame->pos = dvi_pointer_frame->end = dvi_buffer;
+ }
+ XBell(DISP, 0);
+ statusline_print(STATUS_MEDIUM, "Error: Anchor \"%s\" not found.", str);
+ return;
+ }
+
+ /*
+ * In this case we don't need to restore maxchar and currinf, since
+ * we won't resume drawing -- we'll jump to a new page instead.
+ */
+
+ /* Move to that page. */
+ (void)lseek(fileno(globals.dvi_file.bak_fp), pageinfo_get_offset(test_page), SEEK_SET);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+ currinf.pos = currinf.end = dvi_buffer;
+ currinf.virtual = NULL;
+
+ info.geom_special = htex_scan_special_noreturn;
+
+ g_info.geom_box = htex_dummy_box;
+ g_info.geom_data = &y_pos;
+
+ info.data = &g_info;
+
+ if (!setjmp(info.done_env))
+ geom_scan_part(geom_do_char, globals.dvi_file.bak_fp, &info, geom_current_frame = &geom_frame0, dimconv);
+
+ if (y_pos == -1) { /* not found */
+ XDVI_ERROR((stderr, "%s:%d: shouldn't happen: geom_scan_part() failed to re-find the link.", __FILE__, __LINE__));
+ }
+ else {
+ goto_page(test_page, resource.keep_flag ? NULL : home, False);
+ page_history_insert(test_page);
+ do_autoscroll = True;
+ htex_set_anchormarker(y_pos);
+ }
+ /* reset info */
+ free(g_anchor_pos);
+ g_anchor_pos = NULL;
+ g_anchor_len = 0;
+}
+
+
+
+#ifdef T1LIB
+
+/* ********************** FONT AND ENCODING LOADING ******************** */
+
+static char **
+load_vector(const char *enc)
+{
+ char *filename;
+
+ TRACE_T1((stderr, "loading vector: |%s|", enc));
+ /*
+ * With TDS 1.0/kpathsea 3.5.2(?), encoding files are in texmf/fonts/enc and accessed
+ * via kpse_enc_format; see e.g.:
+ * http://tug.org/mailman/htdig/tex-live/2004-January/004734.html
+ *
+ * The lookups under kpse_program_text_format and kpse_tex_ps_header_format
+ * are kept for backwards compatibility.
+ */
+ do {
+ filename = kpse_find_file(enc, kpse_enc_format, 0);
+ if (filename != NULL)
+ break;
+ filename = kpse_find_file(enc, kpse_program_text_format, 0);
+ if (filename != NULL)
+ break;
+ /* If that fails we try the standard place: postscript headers */
+ filename = kpse_find_file(enc, kpse_tex_ps_header_format, 1);
+ } while (0);
+
+ if (filename != NULL) {
+ return T1_LoadEncoding(filename);
+ }
+ return NULL;
+}
+
+
+
+static int
+add_tfm(const char *texname)
+{
+ /* Load font metrics if not already loaded. Return index into
+ fontmetrics array. If it fails, fallback metrics must be
+ loaded instead; if that fails as well, exit. */
+
+ size_t i;
+ int idx;
+ static size_t wlidx = 0;
+ static size_t wlidx_max = 0;
+ static const size_t wlidx_step = 1024;
+
+#ifdef USE_HASH
+ if (tfminfo_hash.size == 0)
+ tfminfo_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
+
+ if (find_str_int_hash(&tfminfo_hash, texname, &i)) {
+ return i;
+ }
+#else
+ for (i = 0; i <= wlidx; i++)
+ if (strcmp(tfminfo[i].texname, texname) == 0)
+ return i;
+#endif /* USE_HASH */
+
+ while (wlidx >= wlidx_max) {
+ wlidx_max += wlidx_step;
+ tfminfo = xrealloc(tfminfo, wlidx_max * sizeof *tfminfo);
+ }
+
+ tfminfo[wlidx].texname = texname;
+#ifdef USE_HASH
+ put_str_int_hash(&tfminfo_hash, tfminfo[wlidx].texname, wlidx);
+#endif /* USE_HASH */
+
+ if (!tfmload(texname, &tfminfo[wlidx].designsize, tfminfo[wlidx].widths,
+ &(tfminfo[wlidx].fontdimen2))) {
+ XDVI_FATAL((stderr, "Cannot find font metrics file %s.tfm, "
+ "and fallback metrics cmr10.tfm is missing as well - exiting.\n",
+ texname));
+ }
+
+ idx = wlidx++;
+
+ if (fallbacktfm == 1) {
+ fallbacktfm = 2;
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ /* helptext */
+ "A font metrics file is missing and cmr10.tfm is used instead. Either "
+ "you don't have the file, or your TeX system cannot find it. Try to "
+ "invoke \"kpsewhich\" with the filename mentioned in the error "
+ "message and the \"-debug 2\" option to find out where Xdvik is "
+ "searching for your files.\n"
+ "To enable automatic creation of .tfm files for "
+ "Metafont fonts, "
+ /* FIXME: how about Type1 fonts?? */
+ "set the environment variable MKTEXTFM "
+ "to 1 and re-start xdvi. See the file texmf.cnf for the default settings "
+ "of MKTEXTFM and related variables.",
+ /* message */
+ "Could not find font metrics file %s.tfm; using cmr10.tfm instead. "
+ "Expect ugly output.",
+ texname);
+ }
+
+ return idx;
+}
+
+static int
+add_t1font(const char *fontname, const char *filename)
+{
+ /* Add t1 font to list if it's not already there; return the
+ (newly created, or already existing) t1lib font id. The
+ filename argument is optional, but is assumed to be a full path
+ if it is given.
+ */
+
+ int id, idx;
+ size_t i;
+ char *path = NULL;
+
+ static size_t t1lidx = 0;
+ static size_t t1lidx_max = 0;
+ static const size_t t1lidx_step = 1024;
+
+
+#ifdef USE_HASH
+ /* Already set up by that name? */
+ if (t1fonts_hash.size == 0)
+ t1fonts_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
+
+ if (find_str_int_hash(&t1fonts_hash, fontname, &i)) {
+ return i;
+ }
+#else
+ for (i = 0; i <= t1lidx; i++) {
+ if (strcmp(t1fonts[i].shortname, fontname) == 0 ||
+ strcmp(t1fonts[i].file, fontname) == 0) {
+ TRACE_T1((stderr, "Type1 font %s already loaded from %s", fontname, filename));
+ return i;
+ }
+ }
+#endif /* USE_HASH */
+
+ /* Insert and set up new t1 font */
+ while (t1lidx >= t1lidx_max) {
+ t1lidx_max += t1lidx_step;
+ t1fonts = xrealloc(t1fonts, t1lidx_max * sizeof *t1fonts);
+
+ TRACE_T1((stderr, "Enlarged t1 table from %lu to %lu entries",
+ (unsigned long)t1lidx, (unsigned long)t1lidx_max));
+ }
+
+ if (filename == NULL) {
+ /* We don't know the full path name yet, find it */
+ path = kpse_find_file(fontname, kpse_type1_format, 0);
+ if (path == NULL)
+ return -1; /* xdvi will use substitution font */
+ }
+ else {
+ path = xstrdup(filename);
+ }
+
+ t1fonts[t1lidx].file = xstrdup(path);
+ t1fonts[t1lidx].t1id = id = T1_AddFont(path);
+ t1fonts[t1lidx].shortname = xstrdup(fontname);
+ t1fonts[t1lidx].loaded = 0;
+
+ TRACE_T1((stderr, "Loaded font %lu/%s (%d) from %s", (unsigned long)t1lidx, fontname, id, path));
+
+#ifdef USE_HASH
+ /* also save the info in the hashtable (note: no duplication of the string here!) */
+ put_str_int_hash(&t1fonts_hash, t1fonts[t1lidx].shortname, t1lidx);
+#endif /* USE_HASH */
+
+ idx = t1lidx++;
+
+ free(path);
+
+#if USE_AFM
+ /* BZZT! AFM files are useless to us, their metric information is
+ too inacurate for TeX use. Never define USE_AFM */
+ /* Set the afm filename. Always before loading. If no afm file
+ found t1lib will use fallback code. In fact the fallback code
+ has been deactivated entierly, it's dog slow. */
+ path = kpse_find_file(fontname, kpse_afm_format, 0);
+ if (path != NULL) {
+ TRACE_T1((stderr, "found afm file: %s", path));
+ T1_SetAfmFileName(id, path);
+ free(path);
+ }
+#endif
+
+ return idx;
+}
+
+static int
+find_texfont(const char *texname)
+{
+ /* Find fontmap index of texfont */
+ size_t i;
+
+#ifdef USE_HASH
+ if (fontmaps_hash.size == 0)
+ fontmaps_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
+
+ if (find_str_int_hash(&fontmaps_hash, texname, &i)) {
+ return i;
+ }
+#else
+ for (i = 0; i < g_maplidx; i++) {
+ if (strcmp(fontmaps[i].texname, texname) == 0) {
+ TRACE_T1((stderr, "Type1 font already loaded at index %d: %s\n", i, texname));
+ return i;
+ }
+ }
+#endif /* USE_HASH */
+ return -1;
+}
+
+
+static int
+setup_encoded_T1_font(const char *mapfile,
+ int lineno,
+ const char *texname,
+ const char *alias,
+ const char *filename,
+ int enc,
+ int ext,
+ int sl)
+{
+ /* xdvi T1 Font loading is done in two steps:
+
+ 1. At xdvi startup two things happen:
+
+ a. The fontmaps are read.
+
+ b. the dvi file is (partialy) scanned, and fonts are set up.
+ In the case of t1 fonts we only set up the data structures,
+ they are not actually loaded until they are used.
+
+ 2. At the time a T1 font is used it is loaded, encoded, extended
+ and slanted as prescribed.
+
+ This procedure takes care of step 1a. It locates the font and
+ sets up the data-structures so it may be assumed, by xdvi, to be
+ loaded. Return the fontmaps array index.
+
+ The 'texname' param should be the texname of the font, such as
+ ptmr8r or cmr10.
+
+ The 'alias' param should be the file name of the font if it is
+ different from the texname. This is often the case with fonts
+ defined in fontmaps.
+
+ If, for some reason, the full filename of the font has already
+ been looked up before we get here it is passed in the filename
+ param so we don't have to look it up again.
+
+ Implied encodings are not handled here.
+
+ REMEMBER: THIS PROC IS CALLED FOR EACH FONT IN THE FONTMAPS, WE
+ CANNOT DO ANY EXPENSIVE OPERATIONS HERE!!!
+
+ */
+
+ int test_idx;
+ size_t curr_idx;
+ static size_t maplidx_max = 0;
+ static const size_t maplidx_step = 1024;
+
+ /* fprintf(stderr, "setup font: |%s|, %s\n", texname, mapfile); */
+
+ /* Already setup by that name? */
+ test_idx = find_texfont(texname);
+ ASSERT(test_idx == -1 || (test_idx > -1 && test_idx < (int)g_maplidx), "Result of find_texfont() out of range");
+
+ if (mapfile != NULL && test_idx != -1) {
+ /* font is already set up, and we're scanning the map file: replace existing font with new one */
+ curr_idx = test_idx;
+ XDVI_INFO((stdout, "%s: Entry for font \"%s\" on line %d overrides previous entry.",
+ mapfile, texname, lineno));
+
+ free(fontmaps[curr_idx].filename);
+ free(fontmaps[curr_idx].pathname);
+ }
+ else if (test_idx != -1) {
+ /* font is already set up, but we're not scanning the map file - return font index */
+ TRACE_T1_VERBOSE((stderr, "font |%s| already set up at index %d", texname, test_idx));
+ return test_idx;
+ }
+ else { /* Not set up yet, do it. */
+ curr_idx = g_maplidx++; /* increment global index count */
+ while (curr_idx >= maplidx_max) {
+ maplidx_max += maplidx_step;
+ fontmaps = xrealloc(fontmaps, maplidx_max * sizeof *fontmaps);
+
+ TRACE_T1((stderr, "Enlarged the fontmap from %lu to %lu entries",
+ (unsigned long)curr_idx, (unsigned long)maplidx_max));
+ }
+ fontmaps[curr_idx].texname = xstrdup(texname);
+ }
+
+ if (alias == NULL)
+ alias = texname;
+
+#ifdef USE_HASH
+ if (test_idx == -1) {
+ if (fontmaps_hash.size == 0)
+ fontmaps_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
+ put_str_int_hash(&fontmaps_hash, fontmaps[curr_idx].texname, curr_idx);
+ }
+#endif /* USE_HASH */
+
+ fontmaps[curr_idx].enc = enc;
+ fontmaps[curr_idx].extension = ext;
+ fontmaps[curr_idx].slant = sl;
+
+ fontmaps[curr_idx].filename = xstrdup(alias);
+ fontmaps[curr_idx].t1libid = -1;
+ TRACE_T1((stderr,
+ "fontmaps[%lu]: \"%s\", enc=%d, ext=%d, sl=%d, alias \"%s\"",
+ (unsigned long)curr_idx, texname, enc, ext, sl, alias));
+
+ if (filename != NULL) {
+ fontmaps[curr_idx].pathname = xstrdup(filename);
+ }
+ else {
+ fontmaps[curr_idx].pathname = NULL;
+ }
+ fontmaps[curr_idx].tfmidx = -1;
+ fontmaps[curr_idx].warned_about = False;
+ fontmaps[curr_idx].force_pk = False;
+
+ return curr_idx;
+}
+
+
+static t1FontLoadStatusT
+try_pk_fallback(int idx, struct font *fontp)
+{
+ Boolean success;
+
+ success = load_font(fontp, False); /* loading non-t1 version of font */
+ fontmaps[idx].force_pk = True;
+ TRACE_T1((stderr,
+ "setting force_pk for %d to true; success for PK fallback: %d\n",
+ idx, success));
+
+ if (!success) {
+ /* this is probably serious enough for a GUI warning */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ /* helptext */
+ "Xdvi tries all of the following possibilities in turn, and all of them have failed:\n\n"
+ " (1) If the resource t1lib is set, try a Postscript Type1 version of a font.\n\n"
+ " (2) Otherwise, or if the Type1 version hasn't been found, try to "
+ "locate, or generate via mktexpk, a TeX Pixel (PK) version of the font.\n\n"
+ " (3) Use the fallback font defined via the \"altfont\" resource (cmr10 by default), "
+ "both as Type1 and as PK version, at various resolutions.\n\n"
+ "It seems that your font setup is defective.\n",
+ /* errmsg */
+ "Error loading font %s: Neither a Type1 version nor "
+ "a pixel version could be found. The character(s) "
+ "will be left blank.",
+ fontmaps[idx].texname);
+ currinf.set_char_p = currinf.fontp->set_char_p = set_empty_char;
+ return FAILURE_BLANK;
+ }
+ /* free unneeded resources. We mustn't free
+ fontmaps[idx].texname,
+ else find_T1_font will try to load the font all over again.
+ */
+ free(fontmaps[idx].filename);
+ free(fontmaps[idx].pathname);
+ currinf.set_char_p = currinf.fontp->set_char_p = set_char;
+ return FAILURE_PK;
+}
+
+static t1FontLoadStatusT
+load_font_now(int idx, struct font *fontp)
+{
+ /* At this point xdvi needs to draw a glyph from this font. But
+ first it must be loaded/copied and modified if needed. */
+
+ int t1idx; /* The fontmap entry number */
+ int t1id; /* The id of the unmodified font */
+ int cid; /* The id of the copied font */
+ int enc, sl, ext;
+
+/* statusline_print(STATUS_SHORT, "Loading T1 font %s", fontmaps[idx].filename); */
+ TRACE_T1((stderr, "adding %s %s",
+ fontmaps[idx].filename, fontmaps[idx].pathname));
+
+ t1idx = add_t1font(fontmaps[idx].filename, fontmaps[idx].pathname);
+
+ t1id = fontmaps[idx].t1libid = t1fonts[t1idx].t1id;
+
+ errno = 0;
+ if (!t1fonts[t1idx].loaded && T1_LoadFont(t1id) == -1) {
+ /* this error is somehow better kept at stderr instead of
+ a popup (too annoying) or the statusline (might disappear
+ too fast) ... */
+ XDVI_ERROR((stderr, "Could not load Type1 font %s from %s: %s %s (T1_errno = %d); "
+ "will try pixel version instead.\nPlease see the T1lib documentation for details about this.\n",
+ fontmaps[idx].texname, fontmaps[idx].pathname,
+ T1_StrError(T1_errno),
+ errno != 0 ? strerror(errno) : "",
+ T1_errno));
+ return try_pk_fallback(idx, fontp);
+ }
+
+ fontmaps[idx].tfmidx = add_tfm(fontmaps[idx].texname);
+
+ t1fonts[t1idx].loaded = 1;
+
+ /* If there is nothing further to do, just return */
+ enc = fontmaps[idx].enc;
+ ext = fontmaps[idx].extension;
+ sl = fontmaps[idx].slant;
+ TRACE_T1((stderr, "lookup at idx[%d] yields: %d, %d, %d", idx, enc, ext, sl));
+
+ if (enc == -1 && ext == 0 && sl == 0)
+ return SUCCESS;
+
+ /* The fontmap entry speaks of a modified font. Copy it first. */
+ cid = T1_CopyFont(t1id);
+
+ fontmaps[idx].t1libid = cid;
+
+ if (enc != -1) {
+ TRACE_T1_VERBOSE((stderr, "trying to load vector from encodings index %d", enc));
+ /* Demand load vector */
+ if (encodings[enc].vector == NULL)
+ encodings[enc].vector = load_vector(encodings[enc].file);
+
+ if (encodings[enc].vector == NULL) {
+ /* this error is somehow better kept at stderr instead of
+ a popup (too annoying) or the statusline (might disappear
+ too fast) ... */
+ XDVI_ERROR((stderr, "Could not load load encoding file %s for vector %s (font %s): %s (T1_errno = %d); "
+ "will try pixel version instead.\n"
+ "Please see the T1lib documentation for details about this.\n",
+ encodings[enc].file, encodings[enc].enc, fontmaps[idx].texname,
+ T1_StrError(T1_errno), T1_errno));
+ return try_pk_fallback(idx, fontp);
+ }
+ else {
+ if (T1_ReencodeFont(cid, encodings[enc].vector) != 0) {
+ XDVI_ERROR((stderr, "Re-encoding of %s failed: %s (T1_errno = %d); "
+ "will try pixel version instead.\n"
+ "Please see the T1lib documentation for details about this.\n",
+ fontmaps[idx].texname,
+ T1_StrError(T1_errno), T1_errno));
+ return try_pk_fallback(idx, fontp);
+ }
+ }
+ }
+
+ if (ext)
+ T1_ExtendFont(cid, ext / 1000.0);
+
+ if (sl)
+ T1_SlantFont(cid, sl / 10000.0);
+
+ return SUCCESS;
+}
+
+
+int
+find_T1_font(const char *texname)
+{
+ /* Step 1b in the scenario above. xdvi knows that this font is
+ needed. Check if it is available, but do not load it yet.
+ Return the fontmap index at which the font was found */
+
+ int idx; /* Iterator, t1 font id */
+ char *filename;
+ int fl, el; /* Fontname length, encoding name length */
+ int encoded = -1;
+ char *mname; /* Modified font name */
+ size_t i;
+
+ encoded = 0;
+
+ /* First: Check the maps */
+ idx = find_texfont(texname);
+
+ if (idx != -1) {
+ if (fontmaps[idx].force_pk) {
+ return idx;
+ }
+ if (fontmaps[idx].pathname == NULL) {
+ filename = kpse_find_file(fontmaps[idx].filename, kpse_type1_format, 0);
+ /* It should have been on disk according to the map, but never
+ fear, xdvi will try to find it other ways. */
+ if (filename == NULL) {
+ if (!fontmaps[idx].warned_about) {
+ fontmaps[idx].warned_about = True;
+ XDVI_WARNING((stderr, "Font map calls for %s, but it was not found (will try PK version instead).",
+ fontmaps[idx].filename));
+ }
+ return -1;
+ }
+ fontmaps[idx].pathname = filename;
+ }
+ TRACE_T1((stderr, "find_T1_font map: %s, entered as #%d",texname,idx));
+ return idx;
+ }
+
+#if 0
+ /* Second: the bare name */
+ filename = kpse_find_file(texname, kpse_type1_format, 0);
+
+ if (filename != NULL) {
+ idx = setup_encoded_T1_font(NULL, 0, texname, NULL, filename, -1, 0, 0);
+ TRACE_T1((stderr, "find_T1_font bare enc: %s, entered as #%d", texname, idx));
+ return idx;
+ }
+#endif
+
+ /* Third: Implied encoding? */
+ fl = strlen(texname);
+
+ for (i = 0; i < enclidx; i++) {
+ if (encodings[i].enc == NULL)
+ continue;
+
+ el = strlen(encodings[i].enc);
+
+ /* Note: the encodings map is short, so the strcmp doesn't hurt here */
+ if (strcmp(texname + (fl - el), encodings[i].enc) == 0) {
+ /* Found a matching encoding */
+ TRACE_T1((stderr, "Encoding match: %s - %s", texname,
+ encodings[i].enc));
+
+ mname = malloc(fl + 2);
+ strcpy(mname, texname);
+ mname[fl - el] = '\0';
+ /* If we had 'ptmr8r' the we now look for 'ptmr' */
+ filename = kpse_find_file(mname, kpse_type1_format, 0);
+ if (filename == NULL) {
+ /* No? Look for ptmr8a. 8a postfix is oft used on raw fonts */
+ strcat(mname, "8a");
+ filename = kpse_find_file(mname, kpse_type1_format, 0);
+ }
+ if (filename != NULL) {
+ idx = setup_encoded_T1_font(NULL, 0, texname, mname, filename, i, 0, 0);
+ TRACE_T1((stderr, "find_T1_font implied enc: %s, is #%d", texname, idx));
+ return idx;
+ }
+
+ free(mname);
+ /* Now we have tried everything. Time to give up. */
+ return -1;
+
+ } /* If (strcmp...) */
+ } /* for */
+ return -1;
+}
+
+/* ************************* CONFIG FILE READING ************************ */
+
+
+static int
+new_encoding(const char *enc, const char *file)
+{
+ /* (Possibly) new encoding entered from .cfg file, or from dvips
+ map. When entered from dvips map the enc is null/anonymous */
+
+ size_t i;
+ static size_t enclidx_max = 0;
+ static const size_t enclidx_step = 16;
+
+ /* Shirley! You're jesting! */
+ if (file == NULL)
+ return -1;
+
+ if (enc == NULL) {
+ /* Enter by file name. First check if the file has been entered
+ already. */
+ for (i = 0; i < enclidx; i++) {
+ if (strcmp(encodings[i].file, file) == 0) {
+ return i;
+ }
+ }
+ }
+ else {
+ /* Enter by encoding name. Check if already loaded first. */
+ for (i = 0; i < enclidx; i++) {
+ if (encodings[i].enc != NULL && strcmp(encodings[i].enc, enc) == 0)
+ return i;
+ }
+ }
+
+ /* Bonafide new encoding */
+
+ while (enclidx >= enclidx_max) {
+ enclidx_max += enclidx_step;
+ encodings = xrealloc(encodings, enclidx_max * sizeof *encodings);
+
+ TRACE_T1((stderr, "Enlarged encoding map from %lu to %lu entries",
+ (unsigned long)enclidx, (unsigned long)enclidx_max));
+ }
+
+ TRACE_T1((stderr, "New encoding #%lu: '%s' -> '%s'", (unsigned long)enclidx, enc ? enc : "<NULL>", file));
+
+ /* The encoding name is optional */
+ encodings[enclidx].enc = NULL;
+ if (enc != NULL)
+ encodings[enclidx].enc = xstrdup(enc);
+
+ /* The file name is required */
+ encodings[enclidx].file = xstrdup(file);
+ encodings[enclidx].vector = NULL; /* Demand load later */
+
+ return enclidx++;
+}
+
+
+void
+add_T1_mapentry(int lineno,
+ const char *mapfile,
+ const char *name,
+ const char *file,
+ const char *vec,
+ char *spec)
+{
+ /* This is called from read_map_file, once for each fontmap line `lineno'. We
+ will dutifully enter the information into our fontmap table */
+
+ static char delim[] = "\t ";
+ char *last, *current;
+ float number;
+ int extend = 0;
+ int slant = 0;
+
+ TRACE_T1_VERBOSE((stderr, "%s:%d: %s -> %s Enc: %s Spec: %s",
+ mapfile, lineno,
+ name, file,
+ vec == NULL ? "<none>" : vec,
+ spec == NULL ? "<none>" : spec));
+
+ if (spec != NULL) {
+ /* Try to analyze the postscript string. We recognize two things:
+ "n ExtendFont" and "m SlantFont". n can be a decimal number in
+ which case it's an extension factor, or a integer, in which
+ case it's a charspace unit? In any case 850 = .85 */
+
+ last = strtok(spec, delim);
+ current = strtok(NULL, delim);
+ while (current != NULL) {
+ if (strcmp(current, "ExtendFont") == 0) {
+ sscanf(last, "%f", &number);
+ if (number < 10.0)
+ extend = number * 1000.0;
+ else
+ extend = number;
+ }
+ else if (strcmp(current, "SlantFont") == 0) {
+ sscanf(last, "%f", &number);
+ slant = number * 10000.0;
+ }
+ last = current;
+ current = strtok(NULL, delim);
+ }
+ }
+
+ setup_encoded_T1_font(mapfile, lineno,
+ name, file, NULL, new_encoding(NULL, vec), extend,
+ slant);
+}
+
+static void
+read_cfg_file(const char *file)
+{
+ char *filename;
+ FILE *fp;
+ int len;
+ char *keyword;
+ char *ptr;
+ char *buffer;
+ char *enc;
+ char *name;
+ int i;
+ static const char delim[] = "\t \n\r";
+ Boolean found_no_map_files = True;
+
+ if (file == NULL)
+ file = "xdvi.cfg";
+
+ filename = kpse_find_file(file, kpse_program_text_format, 1);
+ if (filename == NULL) {
+ statusline_print(STATUS_MEDIUM, "Warning: Unable to find \"%s\"!", file);
+ return;
+ }
+
+ if ((fp = XFOPEN(filename, "r")) == NULL) {
+ XDVI_ERROR((stderr, "Cannot open config file `%s' for reading: %s", filename, strerror(errno)));
+ return;
+ }
+
+ TRACE_T1((stderr, "Reading cfg file %s", filename));
+
+ buffer = xmalloc(BUFFER_SIZE);
+
+ while (fgets(buffer, BUFFER_SIZE, fp) != NULL) {
+ len = strlen(buffer);
+ if (buffer[len - 1] != '\n') {
+ int c;
+ /* this really shouldn't happen ... */
+ XDVI_WARNING((stderr, "Skipping overlong line (> %d characters) in config file `%s':\n%s ...",
+ BUFFER_SIZE, filename, buffer));
+ /* read until end of this line */
+ while((c = fgetc(fp)) != '\n' && c != EOF) { ; }
+ continue;
+ }
+
+ keyword = buffer;
+
+ /* Skip leading whitespace */
+ while (keyword[0] != '\0' && (keyword[0] == ' ' || keyword[0] == '\t'))
+ keyword++;
+
+ /* % in first column is a correct comment */
+ if (keyword[0] == '%' || keyword[0] == '\0' || keyword[0] == '\n')
+ continue;
+
+ keyword = strtok(keyword, delim);
+
+ if (strcmp(keyword, "dvipsmap") == 0) {
+ if ((ptr = strtok(NULL, delim)) == NULL) {
+ XDVI_WARNING((stderr, "Syntax error in entry \"%s\"", buffer));
+ continue;
+ }
+ TRACE_T1((stderr, "DVIPSMAP: '%s'", ptr));
+
+ if (read_map_file(ptr)) {
+ found_no_map_files = False;
+ }
+ else {
+ TRACE_T1((stderr, "Read map file: '%s'", ptr));
+ }
+ }
+ else if (strcmp(keyword, "encmap") == 0) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Your xdvi.cfg file is for a previous version of xdvik. Please replace "
+ "it by the xdvi.cfg file in the current xdvik distribution.",
+ "Keyword \"encmap\" in xdvi.cfg is no longer supported, "
+ "please update the config file %s.",
+ filename);
+ }
+ else if (strcmp(keyword, "enc") == 0) {
+ enc = strtok(NULL, delim);
+ name = strtok(NULL, delim);
+ if ((ptr = strtok(NULL, delim)) == NULL) {
+ XDVI_WARNING((stderr, "Syntax error in entry \"%s\" (skipping line)", buffer));
+ continue;
+ }
+ i = new_encoding(enc, ptr);
+ TRACE_T1((stderr, "Encoding[%d]: '%s' = '%s' -> '%s'", i, enc, name, ptr));
+ } else {
+ /* again, nag them with a popup so that they'll do something about this ... */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Please check the syntax of your config file. "
+ "Valid keywords are: \"enc\" and \"dvipsmap\".",
+ "Skipping unknown keyword \"%s\" in config file %s.",
+ keyword, filename);
+ }
+ }
+
+ if (found_no_map_files) {
+ /* nag 'em with a popup so that they'll do something about this ... */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Direct Type 1 font rendering via T1lib gives you many benefits, such as:\n"
+ " - quicker startup time, since no bitmap fonts need to be generated;\n"
+ " - saving disk space for storing the bitmap fonts.\n"
+ "To fix this error, check that the file `ps2pk.map' is located somewhere "
+ "in your XDVIINPUTS path. Have a look at the xdvi wrapper shell script "
+ "(type \"which xdvi\" to locate that shell script) for the current setting "
+ "of XDVIINPUTS.",
+ "Could not load any of the map files listed in xdvi.cfg - disabling T1lib.");
+ resource.t1lib = False;
+ }
+ fclose(fp);
+
+ free(buffer);
+ free(filename);
+}
+
+
+/* **************************** GLYPH DRAWING *************************** */
+
+
+/* Set character# ch */
+
+static struct glyph *
+get_t1_glyph(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch, t1FontLoadStatusT *flag,
+ Boolean is_geom_scan)
+{
+
+ /*
+ A problem is that there are some gaps in math modes tall braces '{',
+ (see for example the amstex users guide). These gaps are seen less if a
+ small size factor is applied, 1.03 seems nice. This does not seem like
+ the Right Thing though. Also gaps do not show up in the fullsize
+ window.
+
+ All in all the factor has been dropped. Despite the beauty flaw.
+ */
+
+ float size = dvi_pt_conv(currinf.fontp->scale);
+
+ int id = currinf.fontp->t1id;
+ int t1libid = fontmaps[id].t1libid;
+
+ GLYPH *G; /* t1lib glyph */
+ struct glyph *g; /* xdvi glyph */
+
+#ifdef TEXXET
+ UNUSED(cmd);
+#endif
+ *flag = SUCCESS;
+
+#if COLOR
+ if (!is_geom_scan && fg_active != fg_current)
+ do_color_change();
+#endif
+
+ /* return immediately if we need to use the fallback PK */
+ if (fontmaps[id].force_pk)
+ return NULL;
+
+ TRACE_T1((stderr, "scale: %ld, ppi %d, sf: %d, size: %f",
+ currinf.fontp->scale, resource.pixels_per_inch,
+ currwin.shrinkfactor, size));
+
+ if (t1libid == -1) {
+ TRACE_T1((stderr, "trying to load font %d", id));
+ *flag = load_font_now(id, currinf.fontp);
+ if (*flag < 0) {
+ TRACE_T1((stderr, "load_font_now failed for T1 font %d", id));
+ return NULL;
+ }
+ t1libid = fontmaps[id].t1libid;
+ }
+
+ TRACE_T1((stderr, "Setting 0x%x `%c' of %d, at %ld(%.2fpt), shrinkage is %d",
+ ch,
+ isprint(ch) ? ch : '?',
+ t1libid, currinf.fontp->scale,
+ size, currwin.shrinkfactor));
+
+ /* Check if the glyph already has been rendered */
+ if ((g = &currinf.fontp->glyph[ch])->bitmap.bits == NULL) {
+ int bitmapbytes;
+ int h;
+ unsigned char *f;
+ unsigned char *t;
+ /* Not rendered: Generate xdvi glyph from t1font */
+
+ g->addr = 1; /* Dummy, should not provoke errors other places in xdvi */
+
+ /* Use the width from the tfm file */
+ g->dvi_adv = tfminfo[fontmaps[id].tfmidx].widths[ch] * currinf.fontp->dimconv;
+ TRACE_T1((stderr, "0x%x, dvi_adv = %ld; dimconv: %f",
+ ch,
+ tfminfo[fontmaps[id].tfmidx].widths[ch],
+ currinf.fontp->dimconv));
+
+ /* Render the glyph. Size here should be postscript bigpoints */
+ G = T1_SetChar(t1libid, ch, size, NULL);
+ if (G == NULL) {
+ /* This can happen e.g. if font is too small; example with plain TeX:
+ \magnification=50 Hello, world!\end
+ */
+ statusline_print(STATUS_FOREVER,
+ "Error rendering character 0x%x `%c' - replacing by whitespace",
+ ch,
+ isprint(ch) ? ch : '?');
+ XDVI_ERROR((stderr, "T1lib failed for character 0x%x `%c': %s. Replacing by whitespace.",
+ ch, isprint(ch) ? ch : '?',
+ T1_StrError(T1_errno)));
+ g->bitmap.w = 1;
+ g->bitmap.h = 1;
+ g->bitmap.bytes_wide = T1PAD(g->bitmap.w, archpad) / 8;
+ alloc_bitmap(&g->bitmap);
+ memset(g->bitmap.bits, 0, g->bitmap.h * g->bitmap.bytes_wide);
+ g->x = 0;
+ g->y = 0;
+#if COLOR
+ g->fg = fg_current;
+#endif
+ return g;
+ }
+
+ if (G->bits == NULL) {
+ if (ch != ' ') {
+ /* -- janl:
+ Blank glyph != .notdef (e.g., it could be a space char).
+ Drop message until I find out how .notdef can be detected.
+ -- SU 2003/02/24:
+ I changed this, since dropped characters is an important
+ thing to warn users about. We try to catch the space char
+ case by checking for space above (rather lame, since it won't
+ catch all fonts, but ...)
+ The only case in which TeX actually uses a space character seems
+ to be the output of `tex testfont', or in some CJK fonts
+ (e.g. gbksong25).
+ */
+ char index[128];
+ char *fontname = xstrdup(currinf.fontp->fontname);
+ size_t dummy = 0;
+
+ SNPRINTF(index, sizeof index, "%d", ch);
+ fontname = xstrcat(fontname, index);
+ if (font_warn_hash.size == 0) {
+ /* TODO: print to statusline */
+ /* popup_message(MSG_WARN, */
+ /* NULL, */
+ /* "Unexpected blank character (.notdef) in font %s, " */
+ /* "replacing with whitespace (see output to stderr for details). " */
+ /* "This might indicate that the font %s is missing " */
+ /* "from the font map, or that it has been specified " */
+ /* "with a wrong encoding.", */
+ /* currinf.fontp->fontname, currinf.fontp->fontname); */
+ font_warn_hash = hash_create(T1FONTS_INITIAL_HASHTABLE_SIZE);
+ }
+
+ if (!find_str_int_hash(&font_warn_hash, fontname, &dummy)) {
+ if (!resource.hush_chars)
+ XDVI_WARNING((stderr, "Character %d is mapped to .notdef in font %s (page %d), "
+ "replacing by whitespace.",
+ ch, currinf.fontp->fontname, current_page + 1));
+ put_str_int_hash(&font_warn_hash, fontname, dummy);
+ }
+ else {
+ free(fontname);
+ }
+ }
+ /* *flag = FAILURE_BLANK; */
+ /* g->addr = -1; */
+ /* return NULL; */
+
+ /* FIXME: g->dvi_adv is only used when invoking set_char(), not with
+ set_empty_char(), and the former apparently needs a valid bitmap.
+ Check how this is done without t1lib.
+ */
+ TRACE_T1((stderr, "replacing .notdef char 0x%02x by space.\n", ch));
+ g->bitmap.w = 1;
+ g->bitmap.h = 1;
+ g->bitmap.bytes_wide = T1PAD(g->bitmap.w, archpad) / 8;
+ alloc_bitmap(&g->bitmap);
+ memset(g->bitmap.bits, 0, g->bitmap.h * g->bitmap.bytes_wide);
+ g->x = 0;
+ g->y = 0;
+#if COLOR
+ g->fg = fg_current;
+#endif
+ return g;
+ }
+
+ g->bitmap.w = abs(G->metrics.rightSideBearing - G->metrics.leftSideBearing);
+ g->bitmap.h = abs(G->metrics.descent - G->metrics.ascent);
+ g->bitmap.bytes_wide = T1PAD(g->bitmap.w, archpad) / 8;
+ alloc_bitmap(&g->bitmap);
+
+ bitmapbytes = g->bitmap.bytes_wide * g->bitmap.h;
+
+ if (padMismatch) {
+ /* Fix alignment mismatch */
+ int from_bytes = T1PAD(g->bitmap.w, 8) / 8;
+
+ f = (unsigned char *)G->bits;
+ t = (unsigned char *)g->bitmap.bits;
+
+ memset(t, 0, bitmapbytes); /* OR ELSE! you get garbage */
+
+ for (h = 0 ; h < g->bitmap.h; h++) {
+ memcpy(t, f, from_bytes);
+ f += from_bytes;
+ t += g->bitmap.bytes_wide;
+ }
+
+
+ } else {
+ /* t1lib and arch alignment matches */
+ memcpy(g->bitmap.bits, G->bits, bitmapbytes);
+ }
+
+#ifdef WORDS_BIGENDIAN
+ /* xdvi expects the bits to be reversed according to
+ endianness. t1lib expects no such thing. This loop reverses
+ the bit order in all the bytes. -janl 18/5/2001 */
+ t = (unsigned char *)g->bitmap.bits;
+
+ for (h = 0; h < bitmapbytes; h++) {
+ *t = rbits[*t];
+ t++;
+ }
+#endif
+
+ g->x = -G->metrics.leftSideBearing; /* Opposed x-axis */
+ g->y = G->metrics.ascent;
+#if COLOR
+ g->fg = fg_current;
+#endif
+ }
+ return g;
+}
+
+setcharRetvalT
+set_t1_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch)
+{
+ t1FontLoadStatusT flag;
+
+ /*
+ get_t1_glyph() will itself set currinf.fontp->set_char_p
+ to set_empty_char() or set_char() if it failed to load the
+ T1 version, but for the *current* call of set_t1_char,
+ we still need to know whether (1) or (2) holds:
+ (1) Type1 font hasn't been found but PK is working,
+ use set_char() to set the PK version
+ (2) neither Type1 nor PK have been found (this is the
+ FAILURE_BLANK case), use set_empty_char().
+ So we need the flag to pass this additional information.
+ */
+#ifdef TEXXET
+ (void)get_t1_glyph(cmd, ch, &flag, False);
+ if (flag == FAILURE_BLANK)
+ set_empty_char(cmd, ch);
+ else
+ set_char(cmd, ch);
+ return;
+#else
+ (void)get_t1_glyph(ch, &flag, False);
+ if (flag == FAILURE_BLANK)
+ return set_empty_char(ch);
+ else
+ return set_char(ch);
+#endif
+}
+
+void read_T1_char(struct font *fontp, wide_ubyte ch)
+{
+ UNUSED(fontp);
+ UNUSED(ch);
+ /* Should never be called */
+ XDVI_ABORT((stderr, "%s:%d: asked to load %c", __FILE__, __LINE__, ch));
+}
+
+void init_t1(void)
+{
+ int i;
+ void *success;
+ /* Attempt to set needed padding.
+
+ FIXME: This is not really the required alignment/padding. On
+ ix86 the requirement for int * is 8 bits, on sparc on the other
+ hand it's 32 bits. Even so, some operations will be faster if
+ the bitmaps lines are alligned "better". But on the other hand
+ this requires a more complex glyph copying operation...
+
+ - janl 16/5/2001
+ */
+ archpad = BMBYTES * 8;
+ i = T1_SetBitmapPad(archpad);
+ if (i == -1) {
+ /* Failed, revert to 8 bits and compilicated bitmap copying */
+ padMismatch = True;
+ T1_SetBitmapPad(8);
+ } else {
+ padMismatch = False;
+ }
+
+ /* Initialize t1lib, use LOGFILE to get logging, NO_LOGFILE otherwise */
+ /* Under NO circumstances remove T1_NO_AFM, it slows us down a LOT */
+
+ if (globals.debug & DBG_T1) {
+ XDVI_INFO((stdout, "Additional t1lib messages may be found in \"t1lib.log\"."));
+ success = T1_InitLib(LOGFILE | T1_NO_AFM | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE);
+ }
+ else
+ success = T1_InitLib(NO_LOGFILE | T1_NO_AFM | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE);
+ if (success == NULL) {
+ XDVI_FATAL((stderr, "Initialization of t1lib failed!"));
+ }
+ T1_SetLogLevel(T1LOG_DEBUG);
+
+ if (resource.subpixel_order == SUBPIXEL_NONE)
+ T1_SetDeviceResolutions(BDPI, BDPI);
+ else
+ T1_SetDeviceResolutions(3 * BDPI, BDPI);
+
+ read_cfg_file(NULL);
+}
+
+#endif /* T1LIB */
+
+
+#if GREY
+
+extern double pow();
+
+static void
+mask_shifts(Pixel mask, int *pshift1, int *pshift2)
+{
+ int k, l;
+
+ for (k = 0; (mask & 1) == 0; ++k)
+ mask >>= 1;
+ for (l = 0; (mask & 1) == 1; ++l)
+ mask >>= 1;
+ *pshift1 = sizeof(short) * 8 - l;
+ *pshift2 = k;
+}
+
+/*
+ * Try to allocate 4 color planes for 16 colors (for GXor drawing).
+ * Not called if the visual type is TrueColor.
+ * When color specials are active, this is called exactly once.
+ * It is used for the first foreground/background pair displayed in
+ * the document. For other documents, we act as if this call had failed.
+ */
+
+
+void
+init_plane_masks(void)
+{
+ Pixel pixel;
+
+ if (globals.gc.do_copy || plane_masks[0] != 0)
+ return;
+
+ if (XAllocColorCells(DISP, G_colormap, False, plane_masks, 4, &pixel, 1)) {
+ /* Make sure fore_Pixel and back_Pixel are a part of the palette */
+ resource.back_Pixel = pixel;
+ resource.fore_Pixel = pixel | plane_masks[0] | plane_masks[1]
+ | plane_masks[2] | plane_masks[3];
+ if (mane.win != (Window) 0)
+ XSetWindowBackground(DISP, mane.win, resource.back_Pixel);
+ }
+ else {
+ globals.gc.do_copy = True;
+ warn_overstrike();
+ }
+}
+
+#endif /* GREY */
+
+#if COLOR
+
+/*
+ * Insert into list of colors to be freed upon opening new document.
+ */
+
+static void
+color_list_insert(Pixel pixel)
+{
+ if (color_list_len >= color_list_max) {
+ if (color_list_max == 0)
+ color_list = xmalloc((color_list_max += 16) * sizeof *color_list);
+ else
+ color_list = xrealloc(color_list,
+ (color_list_max += 16) * sizeof *color_list);
+ }
+ color_list[color_list_len++] = pixel;
+}
+
+
+/*
+ * Warn about colors not being correct.
+ */
+
+static void
+color_warn(void)
+{
+ if (!color_warned) {
+ color_warned = True;
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ /* helptext */
+ "Either this document is using too many "
+ "colors, or some other application is. "
+ "In the latter case, try to close that "
+ "application and re-read the DVI file.",
+ /* msg */
+ "Cannot allocate colormap entry, "
+ "displayed colors will not be exact.");
+ }
+}
+
+
+/*
+ * Allocate a color and add it to our list of pixels to be returned
+ * upon opening a new document.
+ */
+
+#define SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
+
+static int shift1_r, shift1_g, shift1_b;
+static int shift2_r, shift2_g, shift2_b;
+static Boolean shifts_good = False;
+
+Pixel
+alloc_color(const struct rgb *colorp, Pixel fallback_pixel)
+{
+ XColor xcol;
+
+ if (G_visual->class == TrueColor) {
+ if (!shifts_good) {
+ mask_shifts(G_visual->red_mask, &shift1_r, &shift2_r);
+ mask_shifts(G_visual->green_mask, &shift1_g, &shift2_g);
+ mask_shifts(G_visual->blue_mask, &shift1_b, &shift2_b);
+ shifts_good = True;
+ }
+ return SHIFTIFY(colorp->r, shift1_r, shift2_r)
+ | SHIFTIFY(colorp->g, shift1_g, shift2_g)
+ | SHIFTIFY(colorp->b, shift1_b, shift2_b);
+ }
+ else {
+ xcol.red = colorp->r;
+ xcol.green = colorp->g;
+ xcol.blue = colorp->b;
+ xcol.flags = DoRed | DoGreen | DoBlue;
+ if (XAllocColor(DISP, G_colormap, &xcol)) {
+ color_list_insert(xcol.pixel);
+ if (globals.debug & DBG_DVI)
+ printf("alloc_color%6d%6d%6d --> %ld\n",
+ xcol.red, xcol.green, xcol.blue, xcol.pixel);
+ return xcol.pixel;
+ }
+ else {
+ if (globals.debug & DBG_DVI)
+ printf("alloc_color%6d%6d%6d --> failed\n",
+ xcol.red, xcol.green, xcol.blue);
+ color_warn();
+ return fallback_pixel;
+ }
+ }
+}
+
+#undef SHIFTIFY
+
+
+/*
+ * Switch colors of GCs, etc. Called when we're about to use a GC.
+ */
+
+void
+do_color_change(void)
+{
+ static int shrink_allocated_for = 0;
+ Pixel set_bits;
+ Pixel clr_bits;
+
+ ASSERT(fg_current != NULL, "Current foreground mustn't be NULL");
+ ASSERT(bg_current != NULL, "Current background mustn't be NULL");
+#if GREY
+ if (resource.use_grey) {
+ if (G_visual->class == TrueColor) {
+ if (!fg_current->pixel_good) {
+ fg_current->pixel = alloc_color(&fg_current->color,
+ color_data[0].pixel);
+ fg_current->pixel_good = True;
+ }
+
+ set_bits = fg_current->pixel & ~bg_current->pixel;
+ clr_bits = bg_current->pixel & ~fg_current->pixel;
+
+ if (set_bits & G_visual->red_mask)
+ set_bits |= G_visual->red_mask;
+ if (clr_bits & G_visual->red_mask)
+ clr_bits |= G_visual->red_mask;
+ if (set_bits & G_visual->green_mask)
+ set_bits |= G_visual->green_mask;
+ if (clr_bits & G_visual->green_mask)
+ clr_bits |= G_visual->green_mask;
+ if (set_bits & G_visual->blue_mask)
+ set_bits |= G_visual->blue_mask;
+ if (clr_bits & G_visual->blue_mask)
+ clr_bits |= G_visual->blue_mask;
+
+ /*
+ * Make the GCs
+ */
+
+ globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->pixel, bg_current->pixel);
+ globals.gc.fore2 = NULL;
+
+ if (resource.copy
+ || (set_bits && clr_bits && !resource.thorough)) {
+ if (!resource.copy) {
+ warn_overstrike();
+ }
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->pixel, bg_current->pixel);
+ }
+ else {
+ if (set_bits) {
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, fg_current->pixel & set_bits, 0);
+ if (clr_bits) {
+ globals.gc.fore2 = globals.gc.fore2_bak = set_or_make_gc(globals.gc.fore2_bak, GXandInverted,
+ ~fg_current->pixel & clr_bits, 0);
+ }
+ }
+ else {
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXandInverted,
+ ~fg_current->pixel & clr_bits, 0);
+ }
+ }
+
+ if (globals.debug & DBG_DVI)
+ printf("do_color_change: fg = %lx, bg = %lx, with%s globals.gc.fore2\n",
+ fg_current->pixel, bg_current->pixel,
+ globals.gc.fore2 == NULL ? "out" : "");
+
+ if (mane.shrinkfactor > 1) {
+ unsigned int i;
+ unsigned int sf_squared;
+
+ sf_squared = mane.shrinkfactor * mane.shrinkfactor;
+
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL) {
+ free((char *) pixeltbl);
+ if (pixeltbl_gc2 != NULL) {
+ free((char *) pixeltbl_gc2);
+ pixeltbl_gc2 = NULL;
+ }
+ }
+ pixeltbl = xmalloc((sf_squared + 1) * sizeof *pixeltbl);
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+ if (globals.gc.fore2 != NULL && pixeltbl_gc2 == NULL) {
+ /* Can't use sf_squared (or mane.shrinkfactor) here */
+ pixeltbl_gc2 = xmalloc((shrink_allocated_for * shrink_allocated_for + 1) * sizeof *pixeltbl_gc2);
+ }
+
+ /*
+ * Initialize the pixel lookup table according to the gamma values.
+ */
+#define SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
+
+ for (i = 0; i <= sf_squared; ++i) {
+ double frac = resource.gamma > 0
+ ? pow((double)i / sf_squared, 1 / resource.gamma)
+ : 1 - pow((double) (sf_squared - i) / sf_squared, -resource.gamma);
+ unsigned int red, green, blue;
+ Pixel pixel;
+ /* fprintf(stderr, "frac: %f\n", frac); */
+/* fprintf(stderr, "fg_current: %d, bg_current: %d\n", fg_current->color.r, bg_current->color.r); */
+ red = frac
+ * ((double) fg_current->color.r - bg_current->color.r)
+ + bg_current->color.r;
+ green = frac
+ * ((double) fg_current->color.g - bg_current->color.g)
+ + bg_current->color.g;
+ blue = frac
+ * ((double) fg_current->color.b - bg_current->color.b)
+ + bg_current->color.b;
+
+ pixel = SHIFTIFY(red, shift1_r, shift2_r)
+ | SHIFTIFY(green, shift1_g, shift2_g)
+ | SHIFTIFY(blue, shift1_b, shift2_b);
+
+ if (globals.gc.fore2 != NULL) { /* if thorough */
+ /* fprintf(stderr, "++++++ pixeltable at %d: %ld\n", i, pixel & ~bg_current->pixel); */
+ pixeltbl[i] = pixel & ~bg_current->pixel;
+ pixeltbl_gc2[i] = ~pixel & bg_current->pixel;
+ }
+ else if (resource.copy || (set_bits && clr_bits)) {
+ /* fprintf(stderr, "++++++ pixeltable2 at %d: %ld\n", i, pixel); */
+ pixeltbl[i] = pixel;
+ }
+ else {
+ /* fprintf(stderr, "++++++ pixeltable3 at %d: 0x%lx\n", i, ~pixel & clr_bits); */
+ /* fprintf(stderr, "++++++ pixeltable3 at %d: %ld\n", i, pixel & set_bits); */
+ pixeltbl[i] = set_bits ? pixel & set_bits : ~pixel & clr_bits;
+ }
+ }
+#undef SHIFTIFY
+ }
+
+ }
+ else { /* not TrueColor */
+ int i;
+ Boolean using_planes;
+
+ using_planes = (fg_current == bg_head->fg_head && !globals.gc.do_copy);
+ if (!fg_current->palette_good) {
+ XColor color;
+
+ /*
+ * Initialize the pixel lookup table according to the gamma values.
+ */
+ for (i = 0; i < 16; ++i) {
+ double frac;
+
+ frac = resource.gamma > 0
+ ? pow((double) i / 15, 1 / resource.gamma)
+ : 1 - pow((double) (15 - i) / 15, -resource.gamma);
+ color.red = frac
+ * ((double) fg_current->color.r - bg_current->color.r)
+ + bg_current->color.r;
+ color.green = frac
+ * ((double) fg_current->color.g - bg_current->color.g)
+ + bg_current->color.g;
+ color.blue = frac
+ * ((double) fg_current->color.b - bg_current->color.b)
+ + bg_current->color.b;
+
+ color.flags = DoRed | DoGreen | DoBlue;
+
+ if (using_planes) {
+ color.pixel = resource.back_Pixel; /* start of block */
+ if (i & 1) color.pixel |= plane_masks[0];
+ if (i & 2) color.pixel |= plane_masks[1];
+ if (i & 4) color.pixel |= plane_masks[2];
+ if (i & 8) color.pixel |= plane_masks[3];
+ XStoreColor(DISP, G_colormap, &color);
+ fg_current->palette[i] = color.pixel;
+ }
+ else {
+ if (XAllocColor(DISP, G_colormap, &color)) {
+ fg_current->palette[i] = color.pixel;
+ color_list_insert(color.pixel);
+ }
+ else {
+ color_warn();
+ fg_current->palette[i] =
+ (i * 100 >= resource.density * 15)
+ ? resource.fore_Pixel : bg_current->pixel;
+ }
+ }
+ }
+
+ if (using_planes && bg_current->pixel != resource.back_Pixel) {
+ bg_current->pixel = resource.back_Pixel;
+/* XSetWindowBackground(DISP, mane.win, bg_current->pixel); */
+#if MOTIF
+ fprintf(stderr, "setting window background!\n");
+ XSetWindowBackground(DISP, XtWindow(globals.widgets.main_window), bg_current->pixel);
+ XtVaSetValues(globals.widgets.main_window, XmNbackground, bg_current->pixel, NULL);
+#else
+ XSetWindowBackground(DISP, mane.win, bg_current->pixel);
+#endif
+ XClearWindow(DISP, mane.win);
+ }
+
+ fg_current->palette_good = True;
+ }
+
+ if (globals.debug & DBG_DVI)
+ printf("do_color_change: fg = %ld, bg = %ld, using_planes = %d\n",
+ fg_current->palette[15], bg_current->pixel, using_planes);
+
+ if (using_planes) {
+ globals.gc.rule = set_or_make_gc(globals.gc.rule, GXor, fg_current->palette[15],
+ bg_current->pixel);
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, fg_current->palette[15],
+ bg_current->pixel);
+ }
+ else {
+ globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->palette[15],
+ bg_current->pixel);
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->palette[15],
+ bg_current->pixel);
+ }
+
+ globals.gc.fore2 = NULL;
+
+ if (mane.shrinkfactor > 1) {
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL)
+ free((char *) pixeltbl);
+ pixeltbl = xmalloc((unsigned)(mane.shrinkfactor * mane.shrinkfactor + 1)
+ * sizeof *pixeltbl);
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+
+ for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) {
+ pixeltbl[i] = fg_current->palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
+ / (2 * mane.shrinkfactor * mane.shrinkfactor)];
+ }
+ }
+ }
+ } /* end if resource.use_grey */
+ else
+#endif /* GREY */
+ {
+ if (!fg_current->pixel_good) {
+ fg_current->pixel = alloc_color(&fg_current->color,
+ color_data[0].pixel);
+ fg_current->pixel_good = True;
+ }
+
+ if (globals.debug & DBG_DVI)
+ printf("do_color_change: fg = %lx, bg = %lx\n",
+ fg_current->pixel, bg_current->pixel);
+
+ globals.gc.rule = set_or_make_gc(globals.gc.rule, GXcopy, fg_current->pixel, bg_current->pixel);
+
+ set_bits = (Pixel) (fg_current->pixel & ~bg_current->pixel);
+ clr_bits = (Pixel) (bg_current->pixel & ~fg_current->pixel);
+ globals.gc.fore2 = NULL;
+
+ if (resource.copy
+ || (set_bits && clr_bits && !resource.thorough)) {
+ if (!resource.copy) {
+ /* I used to get a warning here which I didn't get for
+ xdvi-22.64/events.c, l.1330, but I can't reproduce
+ it any more ...
+ */
+ warn_overstrike();
+ }
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXcopy, fg_current->pixel, bg_current->pixel);
+ }
+ else {
+ if (set_bits) {
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXor, set_bits, 0);
+ if (clr_bits) {
+ globals.gc.fore2 = globals.gc.fore2_bak1 = set_or_make_gc(globals.gc.fore2_bak1, GXandInverted, clr_bits, 0);
+ }
+ }
+ else
+ globals.gc.fore = set_or_make_gc(globals.gc.fore, GXandInverted, clr_bits, 0);
+ }
+ }
+
+ fg_active = fg_current;
+}
+
+#elif GREY /* if COLOR */
+
+void
+init_pix(void)
+{
+ static int shrink_allocated_for = 0;
+ static float oldgamma = 0.0;
+ static Pixel palette[17];
+ int i;
+
+ if (G_visual->class == TrueColor) {
+ /* This mirrors the non-grey code in xdvi.c */
+ static int shift1_r, shift1_g, shift1_b;
+ static int shift2_r, shift2_g, shift2_b;
+ static Pixel set_bits;
+ static Pixel clr_bits;
+ unsigned int sf_squared;
+
+ if (oldgamma == 0.0) {
+ mask_shifts(G_visual->red_mask, &shift1_r, &shift2_r);
+ mask_shifts(G_visual->green_mask, &shift1_g, &shift2_g);
+ mask_shifts(G_visual->blue_mask, &shift1_b, &shift2_b);
+
+ set_bits = color_data[0].pixel & ~(color_data[1].pixel);
+ clr_bits = color_data[1].pixel & ~(color_data[0].pixel);
+
+ if (set_bits & G_visual->red_mask)
+ set_bits |= G_visual->red_mask;
+ if (clr_bits & G_visual->red_mask)
+ clr_bits |= G_visual->red_mask;
+ if (set_bits & G_visual->green_mask)
+ set_bits |= G_visual->green_mask;
+ if (clr_bits & G_visual->green_mask)
+ clr_bits |= G_visual->green_mask;
+ if (set_bits & G_visual->blue_mask)
+ set_bits |= G_visual->blue_mask;
+ if (clr_bits & G_visual->blue_mask)
+ clr_bits |= G_visual->blue_mask;
+
+ /*
+ * Make the GCs
+ */
+
+ globals.gc.fore = globals.gc.fore2 = globals.gc.rule = 0;
+ globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel);
+ if (globals.gc.do_copy || (set_bits && clr_bits)) {
+ globals.gc.rule = globals.gc.copy;
+ if (!resource.thorough)
+ globals.gc.do_copy = True;
+ }
+ if (globals.gc.do_copy) {
+ 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 & color_data[0].pixel, 0);
+ }
+ if (clr_bits || !set_bits) {
+/* fprintf(stderr, "using GXandInverted!\n"); */
+ *(globals.gc.fore ? &globals.gc.fore2 : &globals.gc.fore) =
+ set_or_make_gc(NULL, GXandInverted, clr_bits & ~(color_data[0].pixel), 0);
+ }
+ if (!globals.gc.rule)
+ globals.gc.rule = globals.gc.fore;
+ }
+
+ oldgamma = resource.gamma;
+ }
+
+ if (mane.shrinkfactor == 1)
+ return;
+ sf_squared = mane.shrinkfactor * mane.shrinkfactor;
+
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL) {
+ free((char *)pixeltbl);
+ if (pixeltbl_gc2 != NULL)
+ free((char *)pixeltbl_gc2);
+ }
+ pixeltbl = xmalloc((sf_squared + 1) * sizeof *pixeltbl);
+ shrink_allocated_for = mane.shrinkfactor;
+ if (globals.gc.fore2 != NULL) {
+ pixeltbl_gc2 = xmalloc((sf_squared + 1) * sizeof *pixeltbl_gc2);
+ }
+ }
+
+ /*
+ * Initialize the pixel lookup table according to the gamma values.
+ */
+#define SHIFTIFY(x, shift1, shift2) ((((Pixel)(x)) >> (shift1)) << (shift2))
+
+ for (i = 0; i <= sf_squared; ++i) {
+ double frac = resource.gamma > 0
+ ? pow((double)i / sf_squared, 1 / resource.gamma)
+ : 1 - pow((double)(sf_squared - i) / sf_squared, -resource.gamma);
+ unsigned int red, green, blue;
+ Pixel pixel;
+
+ red = frac * ((double)color_data[0].red - color_data[1].red)
+ + color_data[1].red;
+ green = frac
+ * ((double)color_data[0].green - color_data[1].green)
+ + color_data[1].green;
+ blue = frac * ((double)color_data[0].blue - color_data[1].blue)
+ + color_data[1].blue;
+
+ pixel = SHIFTIFY(red, shift1_r, shift2_r) |
+ SHIFTIFY(green, shift1_g, shift2_g) |
+ SHIFTIFY(blue, shift1_b, shift2_b);
+
+ if (globals.gc.do_copy) {
+ pixeltbl[i] = pixel;
+ }
+ else if (globals.gc.fore2 != NULL) { /* if thorough */
+ pixeltbl[i] = pixel & ~(color_data[1].pixel);
+ pixeltbl_gc2[i] = ~pixel & color_data[1].pixel;
+ }
+ else {
+ pixeltbl[i] = set_bits ? pixel & set_bits : ~pixel & clr_bits;
+ }
+ }
+
+#undef SHIFTIFY
+
+ return;
+ }
+
+ /* if not TrueColor ... */
+
+ if (resource.gamma != oldgamma) {
+ XColor color;
+
+ for (i = 0; i < 16; ++i) {
+ double frac = resource.gamma > 0
+ ? pow((double)i / 15, 1 / resource.gamma)
+ : 1 - pow((double)(15 - i) / 15, -resource.gamma);
+
+ color.red = frac
+ * ((double)color_data[0].red - color_data[1].red)
+ + color_data[1].red;
+ color.green = frac
+ * ((double)color_data[0].green - color_data[1].green)
+ + color_data[1].green;
+ color.blue = frac
+ * ((double)color_data[0].blue - color_data[1].blue)
+ + color_data[1].blue;
+
+ color.pixel = resource.back_Pixel;
+ color.flags = DoRed | DoGreen | DoBlue;
+
+ if (!globals.gc.do_copy) {
+ if (i & 1)
+ color.pixel |= plane_masks[0];
+ if (i & 2)
+ color.pixel |= plane_masks[1];
+ if (i & 4)
+ color.pixel |= plane_masks[2];
+ if (i & 8)
+ color.pixel |= plane_masks[3];
+ XStoreColor(DISP, G_colormap, &color);
+ palette[i] = color.pixel;
+ }
+ else {
+ if (XAllocColor(DISP, G_colormap, &color))
+ palette[i] = color.pixel;
+ else
+ palette[i] = (i * 100 >= resource.density * 15)
+ ? resource.fore_Pixel : resource.back_Pixel;
+ }
+ }
+
+ globals.gc.copy = set_or_make_gc(NULL, GXcopy, resource.fore_Pixel, resource.back_Pixel);
+ globals.gc.rule = globals.gc.do_copy
+ ? globals.gc.copy
+ : set_or_make_gc(NULL, GXor, resource.fore_Pixel, resource.back_Pixel);
+ globals.gc.fore = globals.gc.rule;
+ globals.gc.fore2 = NULL;
+ oldgamma = resource.gamma;
+ }
+
+ if (mane.shrinkfactor == 1)
+ return;
+
+ if (shrink_allocated_for < mane.shrinkfactor) {
+ if (pixeltbl != NULL)
+ free((char *)pixeltbl);
+ pixeltbl = xmalloc((unsigned)
+ (mane.shrinkfactor * mane.shrinkfactor + 1) * sizeof *pixeltbl);
+ shrink_allocated_for = mane.shrinkfactor;
+ }
+
+ for (i = 0; i <= mane.shrinkfactor * mane.shrinkfactor; ++i) {
+ pixeltbl[i] = palette[(i * 30 + mane.shrinkfactor * mane.shrinkfactor)
+ / (2 * mane.shrinkfactor * mane.shrinkfactor)];
+ }
+}
+
+#endif /* COLOR */
diff --git a/Build/source/texk/xdvik/dvi-draw.h b/Build/source/texk/xdvik/dvi-draw.h
new file mode 100644
index 00000000000..bacb8a721f6
--- /dev/null
+++ b/Build/source/texk/xdvik/dvi-draw.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 1990-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef DVI_DRAW_H_
+#define DVI_DRAW_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+
+extern void prescan(FILE *fp);
+
+
+/* forward declarations */
+struct font;
+struct tn;
+
+/* this information is saved when using virtual fonts */
+struct drawinf {
+ struct framedata data;
+ struct font *fontp;
+ set_char_proc set_char_p;
+ unsigned long tn_table_len;
+ struct font **tn_table;
+ struct tn *tn_head;
+ ubyte *pos, *end; /* pointers to a scan buffer defined in dvi-draw.c */
+ struct font *virtual;
+#ifdef TEXXET
+ int dir;
+#endif
+};
+
+struct src_parsed_special {
+ int line;
+ int col;
+ char *filename;
+ size_t filename_len;
+};
+extern void src_parse(const char *str, int str_len, struct src_parsed_special *parsed);
+
+/*
+ * pixel_conv is currently used only for converting absolute positions
+ * to pixel values; although normally it should be
+ *
+ * ((int) ((x) / currwin.shrinkfactor + (1 << 15) >> 16)),
+ *
+ * the rounding is achieved instead by moving the constant 1 << 15 to
+ * PAGE_OFFSET in dvi-draw.c.
+ */
+
+#define pixel_conv(x) ((int) ((x) / currwin.shrinkfactor >> 16))
+#define pixel_round(x) ((int) ROUNDUP(x, currwin.shrinkfactor << 16))
+
+/* entries below with the characters 'dvi' in them are actually stored in
+ scaled pixel units */
+
+#define DVI_H currinf.data.dvi_h
+#define PXL_H pixel_conv(currinf.data.dvi_h)
+#define DVI_V currinf.data.dvi_v
+#define PXL_V currinf.data.pxl_v
+#define WW currinf.data.w
+#define XX currinf.data.x
+#define YY currinf.data.y
+#define ZZ currinf.data.z
+
+extern void draw_page(void);
+extern void source_reverse_search(int, int, wide_bool);
+extern void source_special_show(wide_bool);
+extern void source_forward_search(const char *);
+
+extern void anchor_search(const char *str);
+
+#ifdef T1LIB
+extern void init_t1(void);
+extern void add_T1_mapentry(int lineno, const char *mapfile, const char *name, const char *file, const char *vec, char *psec);
+extern void read_T1_char(struct font *, wide_ubyte);
+extern int find_T1_font(const char *);
+extern setcharRetvalT set_t1_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch);
+#endif /* T1LIB */
+
+
+/*
+ this is needed by any program that wants to use spcl_scan,
+ since the buffer is supposed to be of that length.
+*/
+#ifndef DVI_BUFFER_LEN
+#define DVI_BUFFER_LEN 2048
+#endif
+
+extern long text_do_char(FILE *fp, struct scan_info *info, wide_ubyte ch);
+extern Boolean spcl_scan(Boolean(*spcl_proc) (char *str, int str_len, void *data), void *data, Boolean return_if_found, FILE *fp);
+
+extern void geom_scan_part(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
+ FILE *fp, struct scan_info *info, struct frame *min_frame, double current_dimconv);
+
+extern void geom_scan(long(*char_proc)(FILE *, struct scan_info *, wide_ubyte),
+ FILE *fp, struct scan_info *info, int pageno);
+
+extern off_t save_file_status(FILE *fp, struct drawinf *currinf_save, ubyte *maxchar_save);
+extern void reinit_text_scan(void);
+extern void restore_file_status(FILE *fp, struct drawinf currinf_save, ubyte maxchar_save, off_t pos_save);
+
+void htex_do_special(const char *str, size_t len);
+
+extern setcharRetvalT set_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch);
+extern setcharRetvalT load_n_set_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch);
+extern setcharRetvalT set_vf_char(
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch);
+
+#ifdef GREY
+void init_plane_masks(void);
+#endif
+
+#if COLOR
+struct rgb; /* forward declaration */
+
+Pixel alloc_color(const struct rgb *, Pixel);
+void do_color_change(void);
+#elif GREY
+void init_pix(void);
+#endif
+
+void dvi_fmt_error(const char *message, ...);
+
+#endif /* DVI_DRAW_H_ */
diff --git a/Build/source/texk/xdvik/dvi-init.c b/Build/source/texk/xdvik/dvi-init.c
new file mode 100644
index 00000000000..d62b170f620
--- /dev/null
+++ b/Build/source/texk/xdvik/dvi-init.c
@@ -0,0 +1,1620 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2004 Paul Vojta
+
+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
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "dvi-init.h"
+#include "dvi-draw.h"
+#include "util.h"
+#include "x_util.h"
+#include "mime.h"
+#include "pagesel.h"
+#include "special.h"
+#include "hypertex.h"
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+#include "kpathsea/magstep.h"
+#include "kpathsea/tex-glyph.h"
+#include "dvi.h"
+#include "string-utils.h"
+#include "browser.h"
+#include "sfSelFile.h"
+#include "xm_toolbar.h"
+#include "pagehist.h"
+
+#ifdef T1LIB
+#include "t1lib.h"
+#endif
+
+#include "message-window.h"
+#include "search-internal.h"
+#include "statusline.h"
+#include "events.h"
+#include "font-open.h"
+
+#define PK_PRE 247
+#define PK_ID 89
+#define PK_MAGIC ((PK_PRE << 8) | PK_ID)
+#define GF_PRE 247
+#define GF_ID 131
+#define GF_MAGIC ((GF_PRE << 8) | GF_ID)
+#define VF_PRE 247
+#define VF_ID_BYTE 202
+#define VF_MAGIC ((VF_PRE << 8) | VF_ID_BYTE)
+
+/* font stuff */
+struct font *tn_table[TNTABLELEN];
+struct font *font_head = NULL;
+struct tn *tn_head = NULL;
+wide_ubyte maxchar;
+unsigned short current_timestamp = 0;
+
+
+unsigned long magnification;
+double dimconv;
+double tpic_conv;
+
+/* Curently processed page number (starting at 0). */
+int current_page = 0;
+int total_pages = 0;
+
+/* postamble offset is saved in this global variable */
+long g_postamble_offset;
+
+
+static struct stat fstatbuf;
+
+static FILE *m_dvi_fp = NULL; /* original user's file */
+
+
+static Boolean open_dvi_file(const char *filename, Boolean open_new_instance);
+
+/*
+ * DVI preamble and postamble information.
+ */
+static unsigned long numerator, denominator;
+static unsigned int dvi_unshrunk_page_w, dvi_unshrunk_page_h;
+static unsigned int m_paper_unshrunk_w, m_paper_unshrunk_h;
+
+
+/*
+ * Offset in DVI file of last page, set in read_postamble().
+ */
+static long m_last_page_offset;
+
+static const char *dvi_err_list[] = {
+ /* NO_ERROR */ "No Error",
+ /* WRONG_DVI_VERSION */ "Wrong version of DVI output for this program",
+ /* DVI_CORRUPTED */ "DVI file corrupted",
+ /* NOT_A_DVI_FILE */ "Not a DVI file",
+ /* POSTAMBLE_NO_POST */ "Postamble doesn't begin with POST",
+ /* POSTAMBLE_NO_MATCH */ "Postamble doesn't match preamble",
+ /* POSTAMBLE_NON_FNTDEF */ "Non-fntdef command found in postamble",
+ /* NOT_ALL_PIXEL_FILES_FOUND */ "Not all pixel files were found",
+ /* NO_BOP_AT_PAGEDESC */ "Page description doesn't begin with BOP",
+ /* FILE_HAS_ZERO_SIZE */ "File has zero size",
+ /* FILE_DOESNT_EXIST */ "No such file",
+ /* FILE_IS_DIRECTORY */ "Is a directory",
+ /* UNKNOWN_ERROR */ "An unknown error occurred"
+};
+
+/*
+ * access method for above list
+ */
+const char *
+get_dvi_error(dviErrFlagT flag) {
+ ASSERT(flag < XtNumber(dvi_err_list), "Flag out of range");
+ return dvi_err_list[flag];
+}
+
+/*
+ * free_vf_chain frees the vf_chain structure.
+ */
+
+static void
+free_vf_chain(struct tn *tnp)
+{
+ while (tnp != NULL) {
+ struct tn *tnp1 = tnp->next;
+ free((char *)tnp);
+ tnp = tnp1;
+ }
+}
+
+/*
+ * delete glyph information in a font.
+ */
+
+static void
+delete_glyphs(struct font *fontp)
+{
+ struct glyph *g;
+
+ for (g = fontp->glyph; g <= fontp->glyph + fontp->maxchar; ++g) {
+ if (g->bitmap2.bits) {
+ free(g->bitmap2.bits);
+ g->bitmap2.bits = NULL;
+ }
+#ifdef GREY
+ if (g->pixmap2) {
+ XDestroyImage(g->image2);
+ g->pixmap2 = NULL;
+ if (g->pixmap2_gc2 != NULL) {
+ free(g->pixmap2_gc2);
+ g->pixmap2_gc2 = NULL;
+ }
+ }
+#if COLOR
+ g->fg = NULL;
+#endif
+#endif
+ }
+}
+
+/*
+ * Release all shrunken bitmaps for all fonts.
+ */
+
+void
+reset_fonts(void)
+{
+ struct font *f;
+
+ for (f = font_head; f != NULL; f = f->next) {
+ if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)) {
+ delete_glyphs(f);
+ }
+ }
+}
+
+/*
+ * free up fonts no longer in use.
+ */
+static void
+free_unused_fonts(void)
+{
+ struct font *fontp;
+ struct font **fontpp;
+
+ fontpp = &font_head;
+ while ((fontp = *fontpp) != NULL) {
+ if (fontp->flags & FONT_IN_USE)
+ fontpp = &fontp->next;
+ else {
+ if (globals.debug & DBG_PK)
+ printf("xdvi: Discarding font \"%s\" at %d dpi\n",
+ fontp->fontname, (int)(fontp->fsize + 0.5));
+ *fontpp = fontp->next; /* remove from list */
+ free(fontp->fontname);
+ if (fontp->flags & FONT_LOADED) {
+ if (fontp->file != NULL) {
+ fclose(fontp->file);
+ }
+ free(fontp->filename);
+ if (fontp->flags & FONT_VIRTUAL) {
+ struct macro *m;
+
+ for (m = fontp->macro;
+ m <= fontp->macro + fontp->maxchar; ++m)
+ if (m->free_me) free((char *)m->pos);
+ free((char *)fontp->macro);
+ free((char *)fontp->vf_table);
+ free_vf_chain(fontp->vf_chain);
+ }
+ else {
+ delete_glyphs(fontp);
+ free((char *)fontp->glyph);
+ }
+ free((char *)fontp);
+ }
+ }
+ }
+}
+
+#if COLOR
+
+/*
+ * Release all allocated pixels, and (in greyscale mode) invalidate
+ * all shrunken glyphs.
+ */
+
+void
+reset_colors(void)
+{
+ if (color_list_len != 0) {
+ XFreeColors(DISP, G_colormap, color_list, color_list_len, 0);
+ color_list_len = 0;
+ }
+ while (bg_head != NULL) {
+ struct bgrec *bgp;
+ struct fgrec *fgp;
+
+ for (fgp = bg_head->fg_head; fgp != NULL;) {
+ struct fgrec *fgp1 = fgp->next;
+ free(fgp);
+ fgp = fgp1;
+ }
+ bgp = bg_head->next;
+ free(bg_head);
+ bg_head = bgp;
+ }
+#if GREY
+ if (resource.use_grey) {
+ struct font *f;
+ struct glyph *g;
+
+ for (f = font_head; f != NULL; f = f->next)
+ if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL))
+ for (g = f->glyph; g <= f->glyph + f->maxchar; ++g)
+ g->fg = NULL;
+ }
+#endif /* GREY */
+ bg_current = NULL;
+ fg_active = NULL;
+ color_warned = False;
+}
+
+/*
+ * All of the above, plus discard all scanned information.
+ */
+
+void
+full_reset_colors(void)
+{
+ if (page_colors.stack != NULL) {
+ size_t i;
+ struct rgb *last_freed = &fg_initial;
+
+ /* fprintf(stderr, "i: %d; last freed: %p\n", page_colors.size, &fg_initial); */
+ for (i = 0; i < page_colors.size; ++i) {
+ if (page_colors.stack[i].colorstack != last_freed) {
+ last_freed = page_colors.stack[i].colorstack;
+ /* BUG ALERT: don't free &fg_initial, else segfault with changing
+ foreground in xm_colorsel.c! */
+ if (last_freed != NULL && last_freed != &fg_initial) {
+ /* fprintf(stderr, "freeing %d: %p\n", i, last_freed); */
+ free(last_freed);
+ }
+ }
+ }
+ free(page_colors.stack);
+ page_colors.stack = NULL;
+ }
+ reset_colors();
+}
+
+#endif /* COLOR */
+
+
+
+/*
+ * realloc_font allocates the font structure to contain (newsize + 1)
+ * characters.
+ */
+
+void
+realloc_font(struct font *fontp, wide_ubyte newsize)
+{
+ struct glyph *glyph;
+
+ glyph = fontp->glyph = xrealloc(fontp->glyph,
+ (unsigned int)(newsize + 1) * sizeof(struct glyph));
+ if (newsize > fontp->maxchar)
+ memset((char *)(glyph + fontp->maxchar + 1), 0,
+ (int)(newsize - fontp->maxchar) * sizeof(struct glyph));
+ maxchar = fontp->maxchar = newsize;
+}
+
+
+/*
+ * realloc_virtual_font does the same thing for virtual fonts.
+ */
+
+void
+realloc_virtual_font(struct font *fontp, wide_ubyte newsize)
+{
+ struct macro *macro;
+
+ macro = fontp->macro = xrealloc(fontp->macro,
+ (unsigned int)(newsize + 1) * sizeof(struct macro));
+ if (newsize > fontp->maxchar)
+ memset((char *)(macro + fontp->maxchar + 1), 0,
+ (int)(newsize - fontp->maxchar) * sizeof(struct macro));
+ maxchar = fontp->maxchar = newsize;
+}
+
+
+/*
+ * load_font locates the t1 font or raster file and reads the index of
+ * characters, plus whatever other preprocessing is done (depending on
+ * the format).
+ *
+ * Returns True if sucessful, False if not.
+ */
+
+Boolean
+load_font(struct font *fontp, Boolean use_t1lib)
+{
+ double fsize = fontp->fsize;
+ int dpi = fsize + 0.5;
+ char *font_found;
+ int size_found;
+ int magic;
+ Boolean hushcs = resource.hush_chk;
+
+ fontp->file = NULL;
+
+ /* BUG ALERT: This used to be:
+ *
+ * if (--globals.ev.ctr == 0) {
+ * read_events(EV_GE_IDLE);
+ * }
+ * force_statusline_update();
+ * XSync(DISP, False);
+ *
+ * The idea was to update the `loading fonts ...' popup. However,
+ * calling read_events() here may call dvi_file_changed() if the
+ * user clicks on the window, which calls file_exists_p(), and
+ * that changes m_dvi_fp while it's still being used to read the
+ * postamble (where load_font() is called from), which will cause
+ * xdvi to crash! (bug #968127).
+ *
+ * Sadly, without this update, the `loading fonts' popup doesn't
+ * appear before the main window comes up ...
+ */
+
+#ifdef T1LIB
+ fontp->file = font_open(fontp->fontname, &font_found,
+ fsize, &size_found,
+ &fontp->filename, &fontp->t1id);
+#else
+ fontp->file = font_open(fontp->fontname, &font_found,
+ fsize, &size_found,
+ &fontp->filename);
+#endif /* T1LIB */
+
+#ifdef T1LIB
+ if (fontp->t1id >= 0 && use_t1lib) {
+ /* It's a type1 font */
+ fontp->fsize = fsize; /* It comes in all sizes */
+ fontp->timestamp = ++current_timestamp;
+ fontp->maxchar = maxchar = 255;
+ fontp->set_char_p = set_t1_char;
+ /* read_T1_char is a dummy */
+ fontp->read_char = read_T1_char;
+ fontp->glyph = xmalloc (256 * sizeof (struct glyph));
+ memset((char *) fontp->glyph, 0, 256 * sizeof (struct glyph));
+ fontp->flags |= FONT_LOADED;
+ if (font_found != NULL) {
+ statusline_print(STATUS_MEDIUM,
+ "Error: Can't find font %s; using %s instead. Expect ugly output.",
+ fontp->fontname, font_found);
+ force_statusline_update();
+ free(fontp->fontname);
+ fontp->fontname = font_found; /* this has been allocated by font_open */
+ }
+ return True;
+ }
+#endif /* T1LIB */
+ /* when not using T1lib, fontp->file == NULL means total failure */
+ if (fontp->file == NULL) {
+ if (globals.ev.flags & EV_GE_NEWDOC)
+ return False;
+ fontp->flags |= FONT_LOADED; /* as loaded as it'll get */
+ XDVI_ERROR((stderr, "Can't find font %s.%dpk", fontp->fontname, dpi));
+ return False;
+ }
+ fontp->flags |= FONT_LOADED;
+
+ if (font_found != NULL && strcmp(fontp->fontname, font_found) != 0) {
+ /* some other font used - FIXME: is there a more efficient way than strcmp() for checking this? */
+ statusline_print(STATUS_MEDIUM,
+ "Can't find pixel font %s; using %s instead at %d dpi.",
+ fontp->fontname, font_found, dpi);
+ force_statusline_update();
+ free(fontp->fontname);
+ fontp->fontname = font_found; /* this has been allocated by font_open */
+ hushcs = True;
+ }
+ else if (!kpse_bitmap_tolerance((double)size_found, fsize)) { /* a different size used */
+ statusline_print(STATUS_MEDIUM,
+ "Can't find pixel font %s at %d dpi; using %d dpi instead.",
+ fontp->fontname, dpi, size_found);
+ force_statusline_update();
+ }
+
+ /* PK version of some font found */
+ fontp->fsize = size_found;
+ fontp->timestamp = ++current_timestamp;
+ fontp->maxchar = maxchar = 255;
+ fontp->set_char_p = set_char;
+ magic = get_bytes(fontp->file, 2);
+
+ switch(magic) {
+ case PK_MAGIC:
+ read_PK_index(fontp, (wide_bool)hushcs);
+ break;
+#ifdef USE_GF
+ case GF_MAGIC:
+ read_GF_index(fontp, (wide_bool)hushcs);
+ break;
+#endif
+ case VF_MAGIC:
+ if (resource.omega)
+ maxchar = read_VF_index(fontp, (wide_bool)hushcs);
+ else
+ (void)read_VF_index(fontp, (wide_bool)hushcs);
+ break;
+ default:
+ XDVI_FATAL((stderr, "Cannot recognize format for font file %s", fontp->filename));
+ break;
+ }
+
+ if (fontp->flags & FONT_VIRTUAL) {
+ if (!resource.omega) {
+ while (maxchar > 0 && fontp->macro[maxchar].pos == NULL) {
+ --maxchar;
+ }
+ if (maxchar < 255) {
+ realloc_virtual_font(fontp, (wide_ubyte)maxchar);
+ }
+ }
+ }
+ else {
+ while (maxchar > 0 && fontp->glyph[maxchar].addr == 0)
+ --maxchar;
+ if (maxchar < 255)
+ realloc_font(fontp, (wide_ubyte)maxchar);
+ }
+ return True;
+}
+
+
+/*
+ * MAGSTEPVALUE - If the given magnification is close to a \magstep
+ * or a \magstephalf, then return twice the number of \magsteps.
+ * Otherwise return NOMAGSTP.
+ */
+
+#define NOMAGSTP (-29999)
+#define NOBUILD 29999
+
+static int
+magstepvalue(float *mag)
+{
+ int m = 0;
+ double fmag = *mag;
+ double xmag = resource.pixels_per_inch;
+ float margin = fmag * 0.002;
+
+ if (fmag < resource.pixels_per_inch)
+ for (;;) {
+ if (xmag - fmag < margin && -(xmag - fmag) < margin) {
+ *mag = xmag;
+ return m;
+ }
+ if (xmag < fmag)
+ break;
+ xmag *= 0.9128709292;
+ --m;
+ }
+ else
+ for (;;) {
+ if (xmag - fmag < margin && -(xmag - fmag) < margin) {
+ *mag = xmag;
+ return m;
+ }
+ if (xmag > fmag)
+ break;
+ xmag *= 1.095445115;
+ ++m;
+ }
+ return NOMAGSTP;
+}
+
+/*
+ * reuse_font recursively sets the flags for font structures being reused.
+ */
+
+static void
+reuse_font(struct font *fontp)
+{
+ struct font **fp;
+ struct tn *tnp;
+
+ if (fontp->flags & FONT_IN_USE)
+ return;
+
+ fontp->flags |= FONT_IN_USE;
+ if (resource.list_fonts)
+ printf("xdvi: (reusing) %s at %d dpi\n", fontp->fontname,
+ (int)(fontp->fsize + 0.5));
+ if (fontp->flags & FONT_VIRTUAL) {
+ for (fp = fontp->vf_table; fp < fontp->vf_table + VFTABLELEN; ++fp)
+ if (*fp != NULL)
+ reuse_font(*fp);
+ for (tnp = fontp->vf_chain; tnp != NULL; tnp = tnp->next)
+ reuse_font(tnp->fontp);
+ }
+}
+
+
+/*
+ * define_font reads the rest of the fntdef command and then reads in
+ * the specified pixel file, adding it to the global linked-list holding
+ * all of the fonts used in the job.
+ */
+struct font *
+define_font(Boolean load_font_now, /* only scanning, or also loading the font? */
+ FILE *file, wide_ubyte cmnd,
+ struct font *vfparent, /* vf parent of this font, or NULL */
+ struct font **tntable, /* table for low TeXnumbers */
+ unsigned int tn_table_len, /* length of table for TeXnumbers */
+ struct tn **tn_headpp, /* addr of head of list of TeXnumbers */
+ Boolean *not_found_flag) /* signal that font hasn't been found */
+{
+ unsigned int TeXnumber;
+ struct font *fontp;
+ float fsize;
+ double scale_dimconv;
+ long checksum;
+ int scale, orig_scale;
+ int design;
+ int magstepval;
+ int len;
+ char *fontname;
+ int size;
+
+ TeXnumber = get_bytes(file, (int)cmnd - FNTDEF1 + 1);
+ checksum = get_bytes(file, 4);
+ scale = orig_scale = get_bytes(file, 4);
+ design = get_bytes(file, 4);
+ len = get_byte(file);
+ len += get_byte(file); /* sequence point in the middle */
+
+ if (!load_font_now)
+ return NULL;
+
+ fontname = xmalloc((unsigned)len + 1);
+ fread(fontname, sizeof(char), len, file);
+ fontname[len] = '\0';
+ if (globals.debug & DBG_PK)
+ printf("xdvi: Define font \"%s\" scale=%d design=%d number=%d\n",
+ fontname, scale, design, TeXnumber);
+ if (vfparent == NULL) {
+ fsize = 0.001 * scale / design * magnification * resource.pixels_per_inch;
+ scale_dimconv = dimconv;
+ }
+ else {
+ /*
+ * The scaled size is given in units of vfparent->scale * 2 ** -20
+ * SPELL units, so we convert it into SPELL units by multiplying by
+ * vfparent->dimconv.
+ * The design size is given in units of 2 ** -20 pt, so we convert
+ * into SPELL units by multiplying by
+ * (resource.pixels_per_inch * 2**16) / (72.27 * 2**20).
+ */
+ fsize = (72.27 * (1 << 4)) * vfparent->dimconv * scale / design;
+ scale_dimconv = vfparent->dimconv;
+ /* Inherit the scale from the virtual parent */
+ scale = vfparent->scale * ((orig_scale * scale_dimconv / (1 << 20)) / vfparent->dimconv);
+ }
+ magstepval = magstepvalue(&fsize);
+ size = fsize + 0.5;
+ /*
+ * reuse font if possible
+ */
+ for (fontp = font_head;; fontp = fontp->next) {
+ if (fontp == NULL) { /* if font doesn't exist yet */
+ if (resource.list_fonts)
+ printf("xdvi: %s at %d dpi\n", fontname, (int)(fsize + 0.5));
+ fontp = xmalloc((unsigned)sizeof(struct font));
+ fontp->fontname = fontname;
+ fontp->fsize = fsize;
+ fontp->magstepval = magstepval;
+ fontp->file = NULL; /* needed if it's a virtual font */
+ fontp->checksum = checksum;
+ fontp->flags = FONT_IN_USE;
+ fontp->dimconv = orig_scale * scale_dimconv / (1 << 20);
+ fontp->set_char_p = load_n_set_char;
+ fontp->scale = scale;
+ if (vfparent == NULL)
+ if (!load_font(fontp, resource.t1lib)) {
+ if (globals.ev.flags & EV_GE_NEWDOC) { /* if aborting */
+ free(fontname);
+ free(fontp);
+ return NULL;
+ }
+ *not_found_flag = True;
+ }
+ fontp->next = font_head;
+ font_head = fontp;
+ break;
+ }
+ if (strcmp(fontname, fontp->fontname) == 0
+ && size == (int)(fontp->fsize + 0.5)) {
+ /* if font already in use */
+ reuse_font(fontp);
+ free(fontname);
+ break;
+ }
+ }
+ if (TeXnumber < tn_table_len)
+ tntable[TeXnumber] = fontp;
+ else {
+ struct tn *tnp;
+ tnp = xmalloc((unsigned)sizeof(struct tn));
+ tnp->next = *tn_headpp;
+ *tn_headpp = tnp;
+ tnp->TeXnumber = TeXnumber;
+ tnp->fontp = fontp;
+ }
+ return fontp;
+}
+
+
+
+
+/*
+ * process_preamble reads the information in the preamble and stores
+ * it into global variables for later use.
+ */
+Boolean
+process_preamble(FILE *fp, dviErrFlagT *errflag)
+{
+ ubyte k;
+ static char job_id[300];
+
+ TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d", (void *)fp, *errflag));
+
+ if (get_byte(fp) != PRE) {
+ *errflag = NOT_A_DVI_FILE;
+ TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag));
+ return False;
+ }
+ if (get_byte(fp) != 2) {
+ *errflag = WRONG_DVI_VERSION;
+ TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag));
+ return False;
+ }
+ numerator = get_bytes(fp, 4);
+ denominator = get_bytes(fp, 4);
+ magnification = get_bytes(fp, 4);
+ dimconv = (((double)numerator * magnification)
+ / ((double)denominator * 1000.));
+ dimconv = dimconv * (((long)resource.pixels_per_inch) << 16) / 254000;
+ tpic_conv = resource.pixels_per_inch * magnification / 1000000.0;
+ k = get_byte(fp);
+ fread(job_id, sizeof(char), (int)k, fp);
+ job_id[k] = '\0';
+
+ TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning True", (void *)fp, *errflag));
+
+ return True;
+}
+
+/*
+ * find_postamble locates the beginning of the postamble
+ * and leaves the file ready to start reading at that location.
+ */
+#define TMPSIZ 516 /* 4 trailer bytes + 512 junk bytes allowed */
+Boolean
+find_postamble(FILE *fp, dviErrFlagT *errflag)
+{
+ long pos;
+ ubyte temp[TMPSIZ];
+ ubyte *p;
+ ubyte *p1;
+ ubyte byte;
+
+ TRACE_FILES((stderr, "find_postamble on fp: %p", (void *)fp));
+
+ fseek(fp, 0L, SEEK_END);
+ pos = ftell(fp) - TMPSIZ;
+ if (pos < 0)
+ pos = 0;
+ fseek(fp, pos, SEEK_SET);
+ p = temp + fread((char *)temp, sizeof(char), TMPSIZ, fp);
+ for (;;) {
+ p1 = p;
+ while (p1 > temp && *(--p1) != TRAILER);
+ p = p1;
+ while (p > temp && *(--p) == TRAILER);
+ if (p <= p1 - 4)
+ break; /* found 4 TRAILER bytes */
+ if (p <= temp) {
+ *errflag = DVI_CORRUPTED;
+ TRACE_FILES((stderr, "find_postamble: returning FALSE"));
+ return False;
+ }
+ }
+ pos += p - temp;
+ byte = *p;
+ while (byte == TRAILER) {
+ fseek(fp, --pos, SEEK_SET);
+ byte = get_byte(fp);
+ }
+ if (byte != 2) {
+ *errflag = WRONG_DVI_VERSION;
+ TRACE_FILES((stderr, "find_postamble: returning FALSE"));
+ return False;
+ }
+ fseek(fp, pos - 4, SEEK_SET);
+ fseek(fp, get_lbytes(fp, 4), SEEK_SET);
+ TRACE_FILES((stderr, "find_postamble: returning TRUE"));
+ return True;
+}
+
+
+
+Boolean
+set_paper_type(const char *arg)
+{
+ const char *arg1;
+ char temp[21];
+ const char **p;
+ char *q;
+ const char **paper_types = get_paper_types();
+ size_t paper_types_size = get_paper_types_size();
+
+ if (*arg == '+') {
+ ++arg;
+ ignore_papersize_specials = True;
+ }
+ if (strlen(arg) > sizeof(temp) - 1)
+ return False;
+ q = temp;
+ for (;;) { /* convert to lower case */
+ char c = *arg++;
+ if (c >= 'A' && c <= 'Z')
+ c ^= ('a' ^ 'A');
+ *q++ = c;
+ if (c == '\0')
+ break;
+ }
+ arg = temp;
+ /* perform substitutions */
+ for (p = paper_types; p < paper_types + paper_types_size; p += 2) {
+ if (strcmp(temp, *p) == 0) {
+ arg = p[1];
+ break;
+ }
+ }
+ arg1 = strchr(arg, 'x');
+ if (arg1 == NULL)
+ return False;
+ m_paper_unshrunk_w = atopix(arg, False);
+ m_paper_unshrunk_h = atopix(arg1 + 1, False);
+
+ return (m_paper_unshrunk_w != 0 && m_paper_unshrunk_h != 0);
+}
+
+/*
+ * read_postamble reads the information in the postamble from fp,
+ * storing it into global variables.
+ * It also takes care of reading in all of the pixel files for the fonts
+ * used in the job.
+ *
+ * FIXME: Would be better (speed up initialization when needing to generate fonts,
+ * and allow to open window on first page) if the font loading was done on-demand later!
+ */
+Boolean
+read_postamble(FILE *fp, dviErrFlagT *errflag, Boolean load_fonts)
+{
+ ubyte cmnd;
+ Boolean font_not_found = False;
+ struct font *fontp;
+
+ TRACE_FILES((stderr, "read_postamble: reading %p (%d)", (void *)fp, load_fonts));
+
+ /* clear existing font table */
+ memset((char *)tn_table, 0, (int)sizeof tn_table);
+ free_vf_chain(tn_head);
+ tn_head = NULL;
+ for (fontp = font_head; fontp != NULL; fontp = fontp->next)
+ fontp->flags &= ~FONT_IN_USE;
+
+
+ if (get_byte(fp) != POST) {
+ *errflag = POSTAMBLE_NO_POST;
+ TRACE_FILES((stderr, "read_postamble: returning FALSE"));
+ return False;
+ }
+ m_last_page_offset = get_bytes(fp, 4);
+ if (numerator != get_bytes(fp, 4)
+ || denominator != get_bytes(fp, 4)
+ || magnification != get_bytes(fp, 4)) {
+ *errflag = POSTAMBLE_NO_MATCH;
+ TRACE_FILES((stderr, "read_postamble: returning FALSE"));
+ return False;
+ }
+
+ /* read largest box height and width */
+ dvi_unshrunk_page_h = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.yoffset_int;
+ if (dvi_unshrunk_page_h < m_paper_unshrunk_h)
+ dvi_unshrunk_page_h = m_paper_unshrunk_h;
+ dvi_unshrunk_page_w = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.xoffset_int;
+ if (dvi_unshrunk_page_w < m_paper_unshrunk_w)
+ dvi_unshrunk_page_w = m_paper_unshrunk_w;
+ (void)get_bytes(fp, 2); /* max stack size */
+ total_pages = get_bytes(fp, 2);
+
+ /* read font definitions */
+ while ((cmnd = get_byte(fp)) >= FNTDEF1 && cmnd <= FNTDEF4) {
+ struct font *f = define_font(load_fonts, fp, cmnd, (struct font *)NULL, tn_table,
+ TNTABLELEN, &tn_head, &font_not_found);
+ if (load_fonts && f == NULL) {
+ TRACE_FILES((stderr, "read_postamble: returning FALSE"));
+ return False;
+ }
+ else if (!load_fonts) { /* return early */
+ TRACE_FILES((stderr, "read_postamble: returning TRUE"));
+ return True;
+ }
+ }
+ if (cmnd != POSTPOST) {
+ *errflag = POSTAMBLE_NON_FNTDEF;
+ TRACE_FILES((stderr, "read_postamble: returning FALSE"));
+ return False;
+ }
+ if (font_not_found) {
+ *errflag = NOT_ALL_PIXEL_FILES_FOUND;
+ TRACE_FILES((stderr, "read_postamble: returning FALSE"));
+ return False;
+ }
+ free_unused_fonts();
+
+ TRACE_FILES((stderr, "read_postamble: returning TRUE"));
+ return True;
+}
+
+
+static Boolean
+prepare_pages(dviErrFlagT *errflag)
+{
+ int i;
+ long offset;
+
+ TRACE_FILES((stderr, "calling pageinfo_deallocate"));
+ pageinfo_deallocate();
+
+ TRACE_FILES((stderr, "pageinfo_allocate for %d pages", total_pages + 1));
+ pageinfo_allocate(total_pages + 1);
+ pageinfo_set_page_width(total_pages, m_paper_unshrunk_w);
+ pageinfo_set_page_height(total_pages, m_paper_unshrunk_h);
+ pageinfo_set_window_width(total_pages, dvi_unshrunk_page_w);
+ pageinfo_set_window_height(total_pages, dvi_unshrunk_page_h);
+
+ pageinfo_set_offset(total_pages - 1, m_last_page_offset);
+ /*
+ * Follow back pointers through pages in the DVI file,
+ * storing the offsets in the pageinfo table.
+ */
+ for (offset = m_last_page_offset, i = total_pages; i > 0; i--) {
+ fseek(globals.dvi_file.bak_fp, offset, SEEK_SET);
+ if (get_byte(globals.dvi_file.bak_fp) != BOP) {
+ *errflag = NO_BOP_AT_PAGEDESC;
+ return False;
+ }
+ pageinfo_set_offset(i-1, offset);
+ /* from c_0, read count0, the TeX page number */
+ pageinfo_set_number(i-1, get_bytes(globals.dvi_file.bak_fp, 4));
+
+ /* skip c_1 to c_9 */
+ fseek(globals.dvi_file.bak_fp, 9*4L, SEEK_CUR);
+
+ /* next 4 byte contain offset to previous bop */
+ offset = get_bytes(globals.dvi_file.bak_fp, 4);
+ }
+ /* If not prescanning, initialize page sizes. */
+ if (!resource.prescan) {
+ for (i = 0; i < total_pages; ++i) {
+ pageinfo_set_page_width(i, m_paper_unshrunk_w);
+ pageinfo_set_page_height(i, m_paper_unshrunk_h);
+ pageinfo_set_window_width(i, dvi_unshrunk_page_w);
+ pageinfo_set_window_height(i, dvi_unshrunk_page_h);
+ }
+ }
+ return True;
+}
+
+void
+init_page(void)
+{
+ if (globals.dvi_file.bak_fp == NULL)
+ return;
+ globals.page.unshrunk_w = pageinfo_get_page_width(current_page);
+ globals.page.unshrunk_h = pageinfo_get_page_height(current_page);
+ globals.page.w = ROUNDUP(globals.page.unshrunk_w, mane.shrinkfactor) + 2;
+ globals.page.h = ROUNDUP(globals.page.unshrunk_h, mane.shrinkfactor) + 2;
+ TRACE_FILES((stderr, "init_page: setting globals.page.w = %d, globals.page.h = %d", globals.page.w, globals.page.h));
+}
+
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+static char *tmp_dvi_name = NULL; /* name of backup file for useTempFp */
+
+/* access function for backup file name */
+char *get_tmp_dvi_name() {
+ return tmp_dvi_name;
+}
+
+void
+remove_tmp_dvi_file(void)
+{
+ if (tmp_dvi_name != NULL)
+ unlink(tmp_dvi_name);
+}
+
+
+static FILE *
+make_backup_fp(FILE *source_fp, FILE *target_fp)
+{
+ static Boolean first_time = True;
+ static int tmp_fd = 0;
+
+#if !HAVE_FTRUNCATE
+ /* in this case, we can't use ftruncate() on the existing temp file -
+ just close the existing one, and set flag to open a new one */
+ if (tmp_dvi_name != NULL)
+ unlink(tmp_dvi_name);
+ if (target_fp != NULL)
+ fclose(target_fp);
+ /* make sure we use a new temp file, else we'd have a race condition
+ after closing it */
+ free(tmp_dvi_name);
+ tmp_dvi_name = NULL;
+ first_time = True;
+#endif
+
+ if (first_time) { /* doesn't exist yet, create it */
+ if ((tmp_fd = xdvi_temp_fd(&tmp_dvi_name)) == -1) {
+ XDVI_ERROR((stderr, "error creating temporary file - disabling `useTempFp'."));
+ return NULL;
+ }
+/* fprintf(stderr, "temporary file name: |%s|, %d\n", tmp_dvi_name, tmp_fd); */
+ TRACE_EVENTS((stderr, "Created temp file: |%s|\n", tmp_dvi_name));
+ if ((target_fp = try_fdopen(tmp_fd, "wb+")) == NULL) {
+ XDVI_ERROR((stderr, "error opening temporary file (%s) - disabling `useTempFp'.", strerror(errno)));
+ return NULL;
+ }
+ first_time = False;
+ }
+ else { /* if not first time, truncate the existing file,
+ and position both files at beginning */
+ ASSERT(target_fp != NULL, "");
+ ASSERT(source_fp != NULL, "");
+
+#if HAVE_FTRUNCATE
+ if (ftruncate(tmp_fd, 0) < 0) {
+ XDVI_ERROR((stderr, "Couldn't truncate file %s: %s - disabling `useTempFp'.",
+ tmp_dvi_name, strerror(errno)));
+ unlink(tmp_dvi_name);
+ fclose(target_fp);
+ return NULL;
+ }
+#endif
+ fseek(target_fp, 0L, SEEK_SET);
+ fseek(source_fp, 0L, SEEK_SET);
+ }
+
+ /* copy the file */
+ if (!copy_fp(source_fp, target_fp)) {
+ XDVI_ERROR((stderr,
+ "Error creating temporary file: %s\n"
+ "- disabling `useTempFp'.",
+ strerror(errno)));
+ fclose(target_fp);
+ target_fp = NULL;
+ }
+
+ /* rewind both files, else DVI parsing will fail! */
+ fflush(target_fp);
+ fseek(source_fp, 0L, SEEK_SET);
+ if (target_fp != NULL) {
+ fseek(target_fp, 0L, SEEK_SET);
+ }
+
+ return target_fp;
+}
+
+static Boolean
+file_exists_p(const char *path, dviErrFlagT *errflag)
+{
+ TRACE_FILES((stderr, "file_exists_p for |%s|", path));
+ *errflag = UNKNOWN_ERROR;
+ if ((m_dvi_fp = XFOPEN(path, OPEN_MODE)) == NULL) {
+/* fprintf(stderr, "after internal_open_dvi1: xfopen\n"); */
+ *errflag = FILE_DOESNT_EXIST;
+ return False;
+ }
+ TRACE_FILES((stderr, "m_dvi_fp for |%s| = %p", path, (void *)m_dvi_fp));
+/* fprintf(stderr, "after internal_open_dvi2: xfopen\n"); */
+
+ /* shouldn't happen */
+ if (fstat(fileno(m_dvi_fp), &fstatbuf) != 0 || S_ISDIR(fstatbuf.st_mode)) { /* if it's a directory */
+ *errflag = FILE_IS_DIRECTORY;
+ fclose(m_dvi_fp);
+ m_dvi_fp = NULL;
+ return False;
+ }
+ /* If file has zero size, something has gone wrong with downloading
+ it, and the user should already have been warned about that;
+ just return in this case.
+ TODO: can it still happen that we try to load such a file as .dvi
+ file? (Will exit with `draw_part: unknown op-code xyz' or some such).
+ In this case, it would be better to look at the preamble before
+ entering the drawing loop.
+ */
+ if (fstatbuf.st_size == 0) {
+ *errflag = FILE_HAS_ZERO_SIZE;
+ fclose(m_dvi_fp);
+ m_dvi_fp = NULL;
+ return False;
+ }
+ return True;
+}
+
+/*
+ * internal_init_dvi is the main subroutine for reading the startup
+ * information from the dvi file.
+ */
+
+static Boolean
+internal_init_dvi(dviErrFlagT *errflag, Boolean load_fonts)
+{
+ char *icon_name = NULL, *title_name = NULL;
+
+ have_src_specials = False;
+
+ TRACE_FILES((stderr, "internal_init_dvi, globals.dvi_file.bak_fp = %p", (void *)globals.dvi_file.bak_fp));
+
+ if (!process_preamble(globals.dvi_file.bak_fp, errflag)
+ || !find_postamble(globals.dvi_file.bak_fp, errflag)
+ || !read_postamble(globals.dvi_file.bak_fp, errflag, load_fonts)
+ || !prepare_pages(errflag))
+ return False;
+
+ if (current_page >= total_pages)
+ current_page = total_pages - 1;
+
+ globals.warn_spec_now = resource.warn_spec;
+ globals.src.fwd_box_page = -1;
+ search_reset_info();
+
+ if (globals.pausing.num_save != NULL) {
+ free(globals.pausing.num_save);
+ globals.pausing.num_save = NULL;
+ }
+ if (resource.pause && total_pages > 0) {
+ globals.pausing.num_save = xmalloc(total_pages * sizeof *globals.pausing.num_save);
+ memset(globals.pausing.num_save, 0, total_pages * sizeof *globals.pausing.num_save);
+ }
+
+ init_prescan();
+ /* this allocates icon_name and title_name */
+ get_icon_and_title(globals.dvi_name, &icon_name, &title_name);
+ set_icon_and_title(icon_name, title_name);
+ free(icon_name);
+ free(title_name);
+ icon_name = title_name = NULL;
+
+#if defined(MOTIF) && HAVE_XPM
+ tb_check_navigation_sensitivity(current_page);
+#endif
+ refresh_pagelist(total_pages, current_page);
+
+ return True;
+}
+
+/*
+ * internal_open_dvi does the real opening of the dvi file, and sets
+ * globals.dvi_file.time. It returns True on success, and sets m_dvi_fp and globals.dvi_file.bak_fp.
+ */
+
+Boolean
+internal_open_dvi(const char *path, dviErrFlagT *errflag, Boolean load_fonts)
+{
+/* FILE *tmp_fp = NULL; */
+/* static FILE *bak_fp = NULL; /\* re-use the temporary backup fp *\/ */
+/* fprintf(stderr, "------------ opening: |%s|\n", path); */
+
+ TRACE_FILES((stderr, "internal_open_dvi for |%s|", path));
+ close_old_filep();
+
+ if (!file_exists_p(path, errflag)) { /* this should set fstatbuf.st_mtime */
+ return False;
+ }
+
+ if (!resource.use_temp_fp || (globals.dvi_file.bak_fp = make_backup_fp(m_dvi_fp, globals.dvi_file.bak_fp)) == NULL) {
+ globals.dvi_file.bak_fp = m_dvi_fp;
+ }
+ globals.dvi_file.time = fstatbuf.st_mtime;
+
+ if (!internal_init_dvi(errflag, load_fonts)) {
+ return False;
+ }
+
+#if COLOR
+ full_reset_colors();
+#endif /* COLOR */
+ reset_papersize_special();
+
+ TRACE_FILES((stderr, "internal_open_dvi: SUCCESS!"));
+
+ return True;
+}
+
+/*
+ check whether `filename' is a DVI file, by checking if it exists, and if so,
+ opening it and trying to read a DVI preamble from it:
+*/
+static char *
+is_dvi_file(const char *filename)
+{
+ FILE *fp;
+ struct stat statbuf;
+ char *full_pathname;
+ dviErrFlagT unused_error;
+
+ TRACE_FILES((stderr, "is_dvi_file %s", filename));
+ TRACE_HTEX((stderr, "filename: |%s|", filename));
+
+ /* used to append `.dvi' if not already present, but that was a
+ bad idea - if we have both foo.2 and foo.2.dvi, user will want
+ to open `foo.2' (with some appropriate application) if the link
+ points to that filename. This means that we need to have
+ different semantics for filenames on the command-line and
+ filenames in hyperlinks; the latter *must* specify an
+ extension, the former may omit the extension and default to DVI
+ files.
+ */
+ /* if ((full_filename = filename_append_dvi(filename)) == NULL) { */
+ /* free(full_filename); */
+ /* return NULL; */
+ /* } */
+ /* TRACE_HTEX((stderr, "full_filename: |%s|\n", full_filename)); */
+
+ if ((full_pathname = find_file(filename, &statbuf, kpse_program_text_format)) == NULL) {
+ return NULL;
+ }
+ else {
+ char *tmp = canonicalize_path(full_pathname);
+ free(full_pathname);
+ full_pathname = tmp;
+ }
+
+ TRACE_HTEX((stderr, "is_dvi_file: full_pathname: |%s|", full_pathname));
+
+ if ((fp = XFOPEN(full_pathname, OPEN_MODE)) == NULL) {
+ free(full_pathname);
+ return NULL;
+ }
+
+ if (!process_preamble(fp, &unused_error)) {
+ free(full_pathname);
+ fclose(fp);
+ return NULL;
+ }
+
+ fclose(fp);
+ return full_pathname;
+}
+
+static void
+report_open_error(const char *msg, const char *filename, dviErrFlagT errflag)
+{
+ const char *errmsg;
+ switch(errflag) {
+ case FILE_HAS_ZERO_SIZE:
+ errmsg = "File has zero size";
+ break;
+ case FILE_DOESNT_EXIST:
+ errmsg = "No such file";
+ break;
+ case FILE_IS_DIRECTORY:
+ errmsg = "Is a directory";
+ break;
+ default:
+ errmsg = "An unknown error occurred";
+ break;
+ }
+ XDVI_ERROR((stderr, "%s: %s: %s", msg, filename, errmsg));
+}
+
+/*
+ Implements the algorithm for opening a DVI file from the command line.
+ This is similar to `open_dvi_file()' in non-k xdvi.
+
+ If the file does not already have `.dvi' extension, append `.dvi'
+ and set tried_dvi_ext to True. Try to open this file. If the file
+ doesn't exist, try the original file name. If this file doesn't
+ exist either, exit with an error message `No such file or directory'.
+ If tried_dvi_ext == True, also report that file.dvi didn't exist
+ either.
+
+ (A later function will check if the file really is a DVI file, and
+ will use tried_dvi_ext for the same purpose).
+*/
+char *
+find_dvi_file(const char *filename, Boolean *tried_dvi_ext, Boolean from_file_history)
+{
+ char *new_filename;
+ size_t len;
+ dviErrFlagT errflag;
+
+ ASSERT(filename != NULL, "Filename argument in find_dvi_file() musn't be NULL");
+ len = strlen(filename);
+
+ if (len < sizeof(".dvi") || strcmp(filename + len - sizeof(".dvi") + 1, ".dvi") != 0) {
+ /* doesn't already have .dvi extension */
+ TRACE_HTEX((stderr, "|%s| doesn't have .dvi extension, appending ...", filename));
+ new_filename = xstrdup(filename);
+ new_filename = xstrcat(new_filename, ".dvi");
+ *tried_dvi_ext = True;
+
+ if (file_exists_p(new_filename, &errflag)) { /* file exists */
+ char *expanded_filename = expand_filename(new_filename, USE_CWD_PATH);
+ free(new_filename);
+ return expanded_filename;
+ }
+ else { /* don't report an error; will try verbatim filename next */
+ free(new_filename);
+ }
+ }
+
+ /* try verbatim filename (might be strange things like `foo.wdvi') */
+ if (file_exists_p(filename, &errflag)) {
+ char *expanded_filename = expand_filename(filename, USE_CWD_PATH);
+ return expanded_filename;
+ }
+ else {
+ if (*tried_dvi_ext) {
+ if (!from_file_history) {
+ XDVI_FATAL((stderr, "%s: %s, and %s.dvi doesn't exist either.",
+ filename, get_dvi_error(errflag), filename));
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Could not open \"%s\": %s.\n", filename, get_dvi_error(errflag));
+ }
+ }
+ else {
+ if (!from_file_history) {
+ XDVI_FATAL((stderr, "%s: %s.", filename, get_dvi_error(errflag)));
+ }
+ /* else: file is from history; this is at startup, where we may
+ loop through the history until we find a usable file. Don't report
+ an error in this case. */
+ }
+ }
+ return NULL;
+}
+
+
+
+/*
+ * A wrapper for open_dvi_file that can also deal with remote files/URLs, and other
+ * file types. Returns the (newly malloc'ed) new dvi file name if it succeeds, NULL else.
+ */
+char *
+open_dvi_file_wrapper(const char *filename,
+ Boolean from_command_line,
+ Boolean open_new_instance,
+ Boolean *tried_dvi_ext,
+ Boolean from_file_history)
+{
+ char *real_filename = NULL;
+ char *new_dvi_name = NULL;
+ char canonical_path[MAXPATHLEN + 1];
+
+ if (from_command_line) {
+ TRACE_HTEX((stderr, "filename IS from commandline"));
+ /*
+ if filename is from command-line, we want to treat the file as a DVI file
+ always (and NOT launch the browser or other programs; that'd just confuse
+ people, who meant to launch *xdvi*). `find_dvi_file' tries to locate the
+ file and does all error handling; on success, it returns a fully expanded
+ filename.
+ */
+ real_filename = find_dvi_file(filename, tried_dvi_ext, from_file_history); /* this allocates real_filename */
+ if (real_filename == NULL)
+ return False;
+
+ TRACE_HTEX((stderr, "filename |%s| %p from commandline;\ndvi_name: |%s|,\nfilename: |%s|%p",
+ real_filename, real_filename, globals.dvi_name, filename, (void *)filename));
+ new_dvi_name = xstrdup(REALPATH(real_filename, canonical_path));
+ free(real_filename);
+ TRACE_FILES((stderr, "new_dvi_name: |%s|", new_dvi_name));
+ return new_dvi_name;
+ }
+ else {
+ /*
+ if it's not from the command line (e.g. result of clicking Mouse-1 on a link);
+ in this case we might fall back to using the browser.
+ Check whether it's a local file:
+ */
+ const char *filename_no_prefix;
+ char *expanded_filename;
+ TRACE_HTEX((stderr, "filename NOT from commandline"));
+ if ((filename_no_prefix = is_local_file(filename)) != NULL) {
+ /* if it's a local file, check whether it's a DVI file: */
+ if ((expanded_filename = is_dvi_file(filename_no_prefix)) != NULL) {
+ /* yes, open it */
+ if (open_dvi_file(expanded_filename, open_new_instance)) {
+ TRACE_FILES((stderr, "success: %p |%s|", expanded_filename, expanded_filename));
+ if (!open_new_instance) {
+ new_dvi_name = expand_filename_append_dvi(expanded_filename, USE_DVI_PATH, True);
+ TRACE_FILES((stderr, "new_dvi_name: %p |%s|", (void*)new_dvi_name, new_dvi_name));
+ }
+ }
+ free(expanded_filename);
+ return new_dvi_name;
+ }
+ else {
+ /*
+ local file, but not a DVI file;
+ try other viewers for this MIME type:
+ */
+ TRACE_HTEX((stderr, "%s is NOT a DVI file", filename_no_prefix));
+ launch_program(filename);
+ return NULL;
+ }
+ }
+ else {
+ /* not a local file, retrieve it with the browser: */
+ launch_browser(filename);
+ return NULL;
+ }
+ }
+}
+
+
+static Boolean
+open_dvi_file(const char *filename, Boolean open_new_instance)
+{
+ Boolean retval = True;
+
+ char *anchor_name = resource.anchor_pos;
+
+ TRACE_HTEX((stderr, "open_dvi_file: |%s| + |%s|",
+ filename, anchor_name == NULL ? "<no anchor>" : anchor_name));
+
+ if (open_new_instance) {
+ launch_xdvi(filename, anchor_name);
+ }
+ else {
+ dviErrFlagT errflag = NO_ERROR;
+ TRACE_HTEX((stderr, "internal_open_dvi: |%s|", filename));
+ if (!internal_open_dvi(filename, &errflag, True)) {
+/* || !internal_init_dvi(&errflag, True)) { */
+ report_open_error("Cannot open DVI file", filename, errflag);
+ retval = False;
+ }
+ }
+ return retval;
+}
+
+/**
+ ** form_dvi_property forms the property used to exhibit the dvi file name
+ ** used as a window property (used for source specials).
+ **/
+
+void
+form_dvi_property(void)
+{
+#if 0
+ size_t len;
+ unsigned long ino;
+ int i;
+#endif
+
+ if (m_dvi_fp == NULL)
+ return;
+
+ if (dvi_property != NULL)
+ free(dvi_property);
+
+ dvi_property_length = strlen(globals.dvi_name) + 1; /* also copy the terminating 0 */
+ dvi_property = xmalloc(dvi_property_length);
+
+ /* NOTE: we don't use dvi_inode like non-k xdvi, since dvi_name is
+ always fully expanded with xdvik. */
+ strcpy(dvi_property, globals.dvi_name);
+}
+
+
+/* access for m_dvi_fp */
+void
+close_old_filep(void)
+{
+ if (m_dvi_fp != NULL) {
+ fclose(m_dvi_fp);
+ m_dvi_fp = NULL;
+ if (!resource.use_temp_fp)
+ globals.dvi_file.bak_fp = NULL;
+ }
+}
+
+
+
+/**
+ ** Check for changes in dvi file.
+ ** Return True if file has changed, False else.
+ **/
+
+Boolean
+dvi_file_changed(void)
+{
+ TRACE_FILES((stderr, "dvi_file_changed: fp = %p?", (void *)m_dvi_fp));
+
+/* fprintf(stderr, "m_dvi_fp3: %p (%s)\n", m_dvi_fp, globals.dvi_name); */
+ if (m_dvi_fp == NULL) {
+ TRACE_FILES((stderr, "m_dvi_fp == NULL"));
+ if (stat(globals.dvi_name, &fstatbuf) == 0 && fstatbuf.st_mtime != globals.dvi_file.time) {
+ TRACE_FILES((stderr, "file changed"));
+ if (resource.use_temp_fp) {
+ dviErrFlagT errflag = NO_ERROR;
+
+ if (resource.watch_file == 0.0)
+ statusline_print(STATUS_MEDIUM, "File changed ...");
+ TRACE_FILES((stderr, "returning FALSE"));
+
+ if (file_exists_p(globals.dvi_name, &errflag)
+ && process_preamble(m_dvi_fp, &errflag)
+ && find_postamble(m_dvi_fp, &errflag)
+ && read_postamble(m_dvi_fp, &errflag, False)) {
+ TRACE_FILES((stderr, "File OK, reloading ..."));
+
+ globals.ev.flags |= EV_RELOAD;
+ return True;
+ }
+ else {
+ return False;
+ }
+ }
+ /* Bug alert: Don't set EV_RELOAD again here, else xdvi
+ can go into a stretch of time where it again and again
+ tries to reload a file even if the user doesn't click
+ on the canvas.
+ */
+ /*
+ else {
+ globals.ev.flags |= EV_RELOAD;
+ }
+ */
+ TRACE_FILES((stderr, "returning TRUE"));
+ return True;
+ }
+ else {
+ TRACE_FILES((stderr, "file not changed"));
+ }
+ }
+ /* BUG ALERT: Don't use fstat(fileno(m_dvi_fp) here; if file hase
+ disappeared, this won't report an error! */
+ else if (stat(globals.dvi_name, &fstatbuf) != 0 /* stat failed ... */
+ || fstatbuf.st_mtime != globals.dvi_file.time /* ... or different timestamp, reload: */) {
+ dviErrFlagT errflag = NO_ERROR;
+
+ TRACE_FILES((stderr, "Stat failed, or different timestamp ..."));
+ globals.dvi_file.time = 0; /* force reload next time also if stat failed */
+
+ if (resource.use_temp_fp) { /* in this case, reload only if file has been written completely */
+ if (resource.watch_file == 0.0) {
+ statusline_print(STATUS_MEDIUM, "File corrupted (click on window to reload) ...");
+ globals.cursor.flags |= CURSOR_CORRUPTED;
+ globals.ev.flags |= EV_CURSOR;
+ }
+ else {
+ statusline_print(STATUS_MEDIUM, "File corrupted (will try to reload) ...");
+ }
+ close_old_filep();
+ if (file_exists_p(globals.dvi_name, &errflag)
+ && process_preamble(m_dvi_fp, &errflag)
+ && find_postamble(m_dvi_fp, &errflag)
+ && read_postamble(m_dvi_fp, &errflag, False)) {
+ TRACE_FILES((stderr, "File OK, reloading ..."));
+
+ globals.ev.flags |= EV_RELOAD;
+ return True;
+ }
+ else {
+ TRACE_FILES((stderr, "NO successful load: %s", get_dvi_error(errflag)));
+/* fprintf(stderr, "=========== NO successful load: %s\n", get_dvi_error(errflag)); */
+ return False;
+ }
+ }
+ else {
+ TRACE_FILES((stderr, "Not using temp fp, reloading..."));
+ globals.ev.flags |= EV_RELOAD;
+ return True;
+ }
+ }
+ return False;
+}
+
+/**
+ ** Reload the dvi file (unconditionally). Return True on success, False else.
+ **/
+
+Boolean
+load_dvi_file(Boolean load_fonts, dviErrFlagT *errflag)
+{
+ unsigned int old_page_w, old_page_h;
+ static ino_t dvi_inode = 0;
+
+ TRACE_FILES((stderr, "load_dvi_file: going to read %p", (void *)m_dvi_fp));
+
+ if (resource.use_temp_fp && m_dvi_fp != NULL) {
+ /* in this case, reload only if file has been written completely */
+ *errflag = NO_ERROR;
+ fseek(m_dvi_fp, 0L, SEEK_SET);
+ if (!process_preamble(m_dvi_fp, errflag)
+ || !find_postamble(m_dvi_fp, errflag)
+ || !read_postamble(m_dvi_fp, errflag, True)) {
+ TRACE_FILES((stderr, "reading of %p failed: %s!",
+ (void *)m_dvi_fp,
+ get_dvi_error(*errflag)));
+ return False;
+ }
+ }
+
+ old_page_w = globals.page.w;
+ old_page_h = globals.page.h;
+
+ *errflag = NO_ERROR;
+ if (!internal_open_dvi(globals.dvi_name, errflag, load_fonts)) {
+/* || !internal_init_dvi(errflag, load_fonts)) { */
+ XClearWindow(DISP, mane.win);
+ XBell(DISP, 0);
+ statusline_print(STATUS_MEDIUM, "%s: %s%s", globals.dvi_name, get_dvi_error(*errflag),
+ resource.watch_file > 0.0 ? "; will try to reload ..." : " (click on window to reload)");
+ close_old_filep();
+
+ return False;
+ }
+ else { /* success */
+ if (fstatbuf.st_ino != dvi_inode) {
+ dvi_inode = fstatbuf.st_ino;
+ form_dvi_property();
+ set_dvi_property();
+ }
+ if (globals.page.w != old_page_w || globals.page.h != old_page_h)
+ reconfig();
+
+ htex_reinit();
+
+ globals.cursor.flags &= ~CURSOR_CORRUPTED;
+ return True;
+ }
+}
diff --git a/Build/source/texk/xdvik/dvi-init.h b/Build/source/texk/xdvik/dvi-init.h
new file mode 100644
index 00000000000..e5881e0f151
--- /dev/null
+++ b/Build/source/texk/xdvik/dvi-init.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1990-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef DVI_INIT_H_
+#define DVI_INIT_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+typedef enum {
+ NO_ERROR = 0,
+ WRONG_DVI_VERSION,
+ DVI_CORRUPTED,
+ NOT_A_DVI_FILE,
+ POSTAMBLE_NO_POST,
+ POSTAMBLE_NO_MATCH,
+ POSTAMBLE_NON_FNTDEF,
+ NOT_ALL_PIXEL_FILES_FOUND,
+ NO_BOP_AT_PAGEDESC,
+ FILE_HAS_ZERO_SIZE,
+ FILE_DOESNT_EXIST,
+ FILE_IS_DIRECTORY,
+ PS_CONVERSION_FAILED,
+ PDF_CONVERSION_FAILED,
+ UNKNOWN_ERROR
+} dviErrFlagT;
+
+extern const char *get_dvi_error(dviErrFlagT flag);
+
+extern Boolean internal_open_dvi(const char *path, dviErrFlagT *errmsg, Boolean load_fonts);
+extern char *open_dvi_file_wrapper(const char *filename,
+ Boolean from_command_line,
+ Boolean open_new_instance,
+ Boolean *tried_dvi_ext,
+ Boolean from_file_history);
+extern char *get_tmp_dvi_name(void);
+
+/* font stuff */
+
+/*
+ * Bitmap structure for raster ops.
+ */
+struct bitmap {
+ unsigned short w, h; /* width and height in pixels */
+ short bytes_wide; /* scan line width in bytes */
+ char *bits; /* pointer to the bits */
+};
+
+/*
+ * Per-character information.
+ * There is one of these for each character in a font (raster fonts only).
+ * All fields are filled in at font definition time,
+ * except for the bitmap, which is "faulted in"
+ * when the character is first referenced.
+ */
+struct glyph {
+ long addr; /* address of bitmap in font file */
+ long dvi_adv; /* DVI units to move reference point */
+ short x, y; /* x and y offset in pixels */
+ struct bitmap bitmap; /* bitmap for character */
+ short x2, y2; /* x and y offset in pixels for shrunken bitmap */
+#if GREY
+# if COLOR
+ struct fgrec *fg; /* fgrec for which these pixmaps are valid */
+# endif
+ /* `2' means `shrunken' here */
+ XImage *image2; /* shrunken pixmap for antialiased character */
+ char *pixmap2; /* image data pointer for image2 */
+ char *pixmap2_gc2; /* separate image data for drawing image to globals.gc.fore2 */
+#endif /* GREY */
+ struct bitmap bitmap2; /* shrunken bitmap for character */
+};
+
+/*
+ * Per character information for virtual fonts
+ */
+struct macro {
+ ubyte *pos; /* address of first byte of macro */
+ ubyte *end; /* address of last+1 byte */
+ long dvi_adv; /* DVI units to move reference point */
+ Boolean free_me; /* if free(pos) should be called when */
+ /* freeing space */
+};
+
+/*
+ * The layout of a font information block.
+ * There is one of these for every loaded font or magnification thereof.
+ * Duplicates are eliminated: this is necessary because of possible recursion
+ * in virtual fonts.
+ *
+ * Also note the strange units. The design size is in 1/2^20 point
+ * units (also called micro-points), and the individual character widths
+ * are in the TFM file in 1/2^20 ems units, i.e., relative to the design size.
+ *
+ * We then change the sizes to SPELL units (unshrunk pixel / 2^16).
+ */
+
+#define NOMAGSTP (-29999)
+
+#define FONT_IN_USE 1 /* used for housekeeping */
+#define FONT_LOADED 2 /* if font file has been read */
+#define FONT_VIRTUAL 4 /* if font is virtual */
+
+/* forward declarations */
+struct font;
+struct tn;
+
+typedef void (*read_char_proc) (struct font *, wide_ubyte);
+
+struct font {
+ struct font *next; /* link to next font info block */
+ char *fontname; /* name of font */
+ float fsize; /* size information (dots per inch) */
+ int magstepval; /* magstep number * two, or NOMAGSTP */
+ FILE *file; /* open font file or NULL */
+ char *filename; /* name of font file */
+ long checksum; /* checksum */
+ unsigned short timestamp; /* for LRU management of fonts */
+ ubyte flags; /* flags byte (see values below) */
+ wide_ubyte maxchar; /* largest character code */
+ double dimconv; /* size conversion factor */
+ set_char_proc set_char_p; /* proc used to set char */
+ /* these fields are used by (loaded) raster fonts */
+ read_char_proc read_char; /* function to read bitmap */
+ struct glyph *glyph;
+ /* these fields are used by (loaded) virtual fonts */
+ struct font **vf_table; /* list of fonts used by this vf */
+ struct tn *vf_chain; /* ditto, if TeXnumber >= VFTABLELEN */
+ struct font *first_font; /* first font defined */
+ struct macro *macro;
+ /* These were added for t1 use */
+ int t1id;
+ long scale;
+};
+
+struct tn {
+ struct tn *next; /* link to next TeXnumber info block */
+ unsigned long TeXnumber; /* font number (in DVI file) */
+ struct font *fontp; /* pointer to the rest of the info */
+};
+
+
+extern void reset_fonts(void);
+#if COLOR
+extern void reset_colors(void);
+extern void full_reset_colors(void);
+#endif
+extern void realloc_font(struct font *, wide_ubyte);
+extern void realloc_virtual_font(struct font *, wide_ubyte);
+extern Boolean load_font(struct font *, Boolean use_t1lib);
+extern struct font *define_font(Boolean load_font_now,
+ FILE *, wide_ubyte,
+ struct font *, struct font **, unsigned int,
+ struct tn **, Boolean *not_found_flag);
+extern void init_page(void);
+extern void form_dvi_property(void);
+extern Boolean dvi_file_changed(void);
+extern void remove_tmp_dvi_file(void);
+extern Boolean load_dvi_file(Boolean load_fonts, dviErrFlagT *errflag);
+extern void read_PK_index(struct font *, wide_bool);
+extern void read_GF_index(struct font *, wide_bool);
+extern unsigned long read_VF_index(struct font *, wide_bool);
+
+extern Boolean set_paper_type(const char *arg);
+
+extern Boolean find_postamble(FILE *fp, dviErrFlagT *errflag);
+extern Boolean read_postamble(FILE *fp, dviErrFlagT *errflag, Boolean load_fonts);
+extern void close_old_filep(void);
+extern Boolean process_preamble(FILE *fp, dviErrFlagT *errflag);
+
+extern FILE *file_exists(const char *path, dviErrFlagT *errflag);
+extern char *find_dvi_file(const char *filename, Boolean *tried_dvi_ext, Boolean from_file_history);
+#endif /* DVI_INIT_H_ */
diff --git a/Build/source/texk/xdvik/dvi.h b/Build/source/texk/xdvik/dvi.h
new file mode 100644
index 00000000000..392712138fa
--- /dev/null
+++ b/Build/source/texk/xdvik/dvi.h
@@ -0,0 +1,64 @@
+/*
+ * Mnemonics for bytes in dvi file.
+ */
+
+#define SETCHAR0 0
+#define SET1 128
+#define SET2 129
+#define SETRULE 132
+#define PUT1 133
+#define PUT2 134
+#define PUTRULE 137
+#define NOP 138
+#define BOP 139
+#define EOP 140
+#define PUSH 141
+#define POP 142
+#define RIGHT1 143
+#define RIGHT2 144
+#define RIGHT3 145
+#define RIGHT4 146
+#define W0 147
+#define W1 148
+#define W2 149
+#define W3 150
+#define W4 151
+#define X0 152
+#define X1 153
+#define X2 154
+#define X3 155
+#define X4 156
+#define DOWN1 157
+#define DOWN2 158
+#define DOWN3 159
+#define DOWN4 160
+#define Y0 161
+#define Y1 162
+#define Y2 163
+#define Y3 164
+#define Y4 165
+#define Z0 166
+#define Z1 167
+#define Z2 168
+#define Z3 169
+#define Z4 170
+#define FNTNUM0 171
+#define FNT1 235
+#define FNT2 236
+#define FNT3 237
+#define FNT4 238
+#define XXX1 239
+#define XXX2 240
+#define XXX3 241
+#define XXX4 242
+#define FNTDEF1 243
+#define FNTDEF2 244
+#define FNTDEF3 245
+#define FNTDEF4 246
+#define PRE 247
+#define POST 248
+#define POSTPOST 249
+#define SREFL 250
+#define EREFL 251
+
+#define TRAILER 223 /* Trailing bytes at end of file */
diff --git a/Build/source/texk/xdvik/dvisel.c b/Build/source/texk/xdvik/dvisel.c
new file mode 100644
index 00000000000..d6b6b7f6793
--- /dev/null
+++ b/Build/source/texk/xdvik/dvisel.c
@@ -0,0 +1,759 @@
+/*
+ * select pages from a DVI file.
+ *
+ * Copyright (c) 1999
+ * WATANABE Takeshi watanabe@komadori.planet.sci.kobe-u.ac.jp
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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 ANY AUTHO 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.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+#include "dvi.h"
+#include "pagesel.h"
+#include "dvisel.h"
+#include "util.h"
+#include "dvi-init.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "message-window.h"
+#include "statusline.h"
+#include "print-dialog.h"
+
+/* stack for HTEX / Color stack */
+typedef enum { IS_A_HREF, IS_A_COLOR } stackElemT;
+
+/*
+ * Length of BOP command, without p[4] (previous BOP pointer):
+ * bop c_0[4] ... c_9[4]
+ */
+static const int BOP_PART_LEN = 1 + 10 * 4;
+/*
+ * Like above but with p[4]:
+ */
+static const int BOP_LEN = 1 + 10 * 4 + 4;
+/*
+ * Lenght of postamble:
+ * post p[4] num[4] den[4] mag[4] l[4] u[4] s[2] t[2]
+ */
+static const int POSTAMBLE_LEN = 1 + 4 * 6 + 2 + 2;
+/*
+ * Postamble without p[4] (final bop offset) and t[2] (total page number):
+ * num[4] den[4] mag[4] l[4] u[4] s[2]
+ */
+static const int POSTAMBLE_PART_LEN = 4 * 5 + 2;
+
+static char *dvips_papersize_special = NULL;
+
+/*
+ * Struct to save specials that need to be copied verbatim into the output file
+ * (things like `draftcopy'; see dvips manual, `Literal headers')
+ */
+struct literal_headers {
+ size_t size;
+ char **headers;
+};
+static struct literal_headers literal_headers = { 0, NULL };
+
+static struct specials_stack color_stack = { 0, NULL};
+static struct specials_stack href_stack = { 0, NULL};
+
+/*
+ stacks saved from the previous page (i.e. active at the
+ beginning of the page)
+ */
+static struct specials_stack color_save_stack = { 0, NULL };
+static struct specials_stack href_save_stack = { 0, NULL };
+
+static void
+push_stack(struct specials_stack *stack, const char *content)
+{
+ stack->items = xrealloc(stack->items, (stack->stack_len + 1) * sizeof *(stack->items));
+ stack->items[stack->stack_len].content = xstrdup(content);
+ stack->stack_len++;
+}
+
+static Boolean
+stack_contains_item(struct specials_stack *stack, const char *str)
+{
+ size_t i;
+ for (i = 0; i < stack->stack_len; i++) {
+ if (strcmp(str, stack->items[i].content) == 0) {
+ return True;
+ }
+ }
+ return False;
+}
+
+static void
+pop_stack(struct specials_stack *stack)
+{
+ ASSERT(stack->stack_len >= 1, "Attempt to pop empty stack");
+ free(stack->items[stack->stack_len - 1].content);
+ stack->stack_len--;
+}
+
+static void
+empty_stack(struct specials_stack *stack)
+{
+ while(stack->stack_len > 0) {
+ pop_stack(stack);
+ }
+}
+
+/*
+ This is used instead of struct tn, and struct font* from dvi-init.h,
+ since it appears that we don't need all the information from there.
+*/
+static struct fontinfo {
+ long TeXnumber;
+ unsigned char info[14];
+ char *fontname;
+ struct fontinfo *next;
+ Boolean used;
+} *fontinfo_head;
+
+#define PutFour(num, fp) { \
+ putc(((num) >> 24) & 0xff, (fp)); \
+ putc(((num) >> 16) & 0xff, (fp)); \
+ putc(((num) >> 8) & 0xff, (fp)); \
+ putc( (num) & 0xff, (fp)); \
+}
+
+#define CopyNum(fin, fout, num) { \
+ int m = num; \
+ while (--m >= 0) putc(getc(fin), fout); \
+}
+
+static void
+FontWrite(FILE *fout, struct fontinfo *fontp, long *fout_pos)
+{
+ if (fontp->TeXnumber > 0xff) {
+ if (fontp->TeXnumber > 0xffff) {
+ if (fontp->TeXnumber > 0xffffff) {
+ putc(FNTDEF4, fout);
+ putc((fontp->TeXnumber >> 24) & 0xff, fout);
+ (*fout_pos)++;
+ }
+ else {
+ putc(FNTDEF3, fout);
+ }
+ putc((fontp->TeXnumber >> 16) & 0xff, fout);
+ (*fout_pos)++;
+ }
+ else {
+ putc(FNTDEF2, fout);
+ }
+ putc((fontp->TeXnumber >> 8) & 0xff, fout);
+ (*fout_pos)++;
+ }
+ else {
+ putc(FNTDEF1, fout);
+ }
+ putc(fontp->TeXnumber & 0xff, fout);
+ fwrite(fontp->info, sizeof(char), 14, fout);
+ fwrite(fontp->fontname, sizeof(char), fontp->info[12] + fontp->info[13], fout);
+ (*fout_pos) += 2 + 14 + fontp->info[12] + fontp->info[13];
+}
+
+/*
+ Invoked by spcl_scan; saves file names referenced by special commands
+ into the `warn_files' field of `info'.
+*/
+static Boolean
+scan_for_included_files(char *special, int str_len, void *my_info)
+{
+ struct select_pages_info *info = (struct select_pages_info *)my_info;
+ UNUSED(str_len);
+ if (info->warn_files.items == NULL) /* no info needed, e.g. when printing */
+ return True;
+
+ while (*special == ' ' || *special == '\t')
+ ++special;
+
+ if (memicmp(special, "psfile=", strlen("psfile=")) == 0) {
+ char *b_ptr = special + strlen("psfile=");
+ char *e_ptr;
+
+ while (*b_ptr == '"')
+ b_ptr++;
+
+ if ((e_ptr = strchr(b_ptr, '"')) != NULL) {
+ size_t len = e_ptr - b_ptr;
+ char *tmp = xmalloc(len + 1);
+ memcpy(tmp, b_ptr, len);
+ tmp[len] = '\0';
+ if (!stack_contains_item(&(info->warn_files), tmp)) {
+ push_stack(&(info->warn_files), tmp);
+ }
+ free(tmp);
+ }
+ }
+
+ return True; /* dummy */
+}
+
+/*
+ Invoked by spcl_scan; saves hyperref and color commands
+ into the global stacks `color_stack' and `hyperref_stack'.
+ FIXME: In reality char *special is treated as const, but the declaration
+ of spcl_scan doesn't allow for this.
+*/
+static Boolean
+stack_save(char *special, int str_len, void *data)
+{
+ char *ptr;
+ size_t len;
+
+ UNUSED(data);
+ UNUSED(str_len);
+
+ while (isspace((int)*special))
+ ++special;
+
+ ptr = special;
+
+ if (memicmp(special, "color ", len = strlen("color ")) == 0) {
+ special += len;
+ while (*special == ' ' || *special == '\t')
+ ++special;
+ if (memicmp(special, "push ", 5) == 0) {
+ push_stack(&color_stack, ptr);
+ }
+ else if (memicmp(special, "pop", 3) == 0) {
+ pop_stack(&color_stack);
+ }
+ }
+ else if (memicmp(special, "html:", len = strlen("html:")) == 0) {
+ /* fprintf(stderr, "++++ special: %s; fd: %ld\n", special + 5, ftell(globals.dvi_file.bak_fp)); */
+ special += len;
+ if (memicmp(special, "<a href=", 8) == 0
+ || memicmp(special, "<a name=", 8) == 0) {
+ push_stack(&href_stack, ptr);
+ }
+ else if (memicmp(special, "</a>", 4) == 0) {
+ pop_stack(&href_stack);
+ }
+ }
+ else if (memicmp(special, "papersize", len = strlen("papersize")) == 0) {
+ free(dvips_papersize_special);
+ dvips_papersize_special = xstrdup(special);
+ }
+ else if (*special == '!'
+ || memcmp(special, "header", strlen("header")) == 0) {
+ size_t idx = literal_headers.size++;
+ if (globals.debug & DBG_GUI)
+ fprintf(stderr, "(literal) header %lu: |%s|\n", (unsigned long)idx, special);
+ literal_headers.headers = xrealloc(literal_headers.headers,
+ literal_headers.size * sizeof *(literal_headers.headers));
+ literal_headers.headers[idx] = xstrdup(special);
+ }
+ return True; /* dummy */
+}
+
+/* write a special to the FILE *fp, updating offset as appropriate. */
+static void
+write_special(const char *str, FILE *fp, long *offset)
+{
+ unsigned int len = strlen(str);
+ if (len < 256) {
+ unsigned char c = len;
+ putc(XXX1, fp);
+ putc(c, fp);
+ *offset += 2;
+ }
+ else { /* how about xxx2, xxx3? It seems that TeX doesn't use them either? */
+ putc(XXX4, fp);
+ PutFour(len, fp);
+ *offset += 5;
+ }
+ fputs(str, fp);
+ *offset += len;
+}
+
+/*
+ * Dump the headers in the global list `literal_headers',
+ * and free up resources
+ */
+static void
+dump_literal_headers(FILE *fp, long *pos)
+{
+ size_t i;
+ for (i = 0; i < literal_headers.size; i++) {
+ write_special(literal_headers.headers[i], fp, pos);
+ free(literal_headers.headers[i]);
+ }
+ free(literal_headers.headers);
+ literal_headers.headers = NULL;
+ literal_headers.size = 0;
+}
+
+
+static void
+scan_page_for_specials(FILE *fp, int page, Boolean save_stack,
+ Boolean (*special_proc)(char *str, int str_len, void *data),
+ struct select_pages_info *info)
+{
+ off_t pos_save;
+ static ubyte my_scan_buffer[DVI_BUFFER_LEN];
+
+ struct drawinf currinf_save;
+ ubyte maxchar_save;
+ size_t i;
+ TRACE_GUI((stderr, "parsing page: %d", page));
+ if (save_stack) {
+ /*
+ first, copy the current stacks (which reflect the state on the
+ preceding page) to color_save_stack and href_save_stack:
+ */
+ empty_stack(&color_save_stack);
+ empty_stack(&href_save_stack);
+ for (i = 0; i < color_stack.stack_len; i++) {
+ TRACE_GUI((stderr, "saving stack: |%s|", color_stack.items[i].content));
+ push_stack(&color_save_stack, color_stack.items[i].content);
+ }
+ for (i = 0; i < href_stack.stack_len; i++) {
+ TRACE_GUI((stderr, "saving stack: |%s|", href_stack.items[i].content));
+ push_stack(&href_save_stack, href_stack.items[i].content);
+ }
+ }
+
+ /* (void)fseek(fp, pageinfo_get_offset(page), SEEK_SET); */
+ /*
+ The datastructures in dvi-draw are rather weird in requiring
+ us to provide a buffer, and point the global currinf.pos and end
+ pointers to that buffer, for spcl_scan to be able to scan the file.
+ First save the contents of the exising currinf, pointing to the main file:
+ */
+ pos_save = save_file_status(fp, &currinf_save, &maxchar_save);
+
+ lseek(fileno(fp), pageinfo_get_offset(page), SEEK_SET);
+ memset((char *)&currinf.data, 0, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+
+ /* then point currinf to our own buffer: */
+ G_dvi_buf_ptr = my_scan_buffer;
+ currinf.pos = currinf.end = G_dvi_buf_ptr;
+ lseek(fileno(fp), pageinfo_get_offset(page), SEEK_SET);
+ /*
+ finally we may invoke spcl_scan(). I hope we can do without
+ the
+ (!setjmp(some_env))
+ black magic since there shouldn't be any interruptions ...
+ */
+#if 1
+ spcl_scan(special_proc, info, False, fp);
+#else
+ /* this is an attempt at using setjmp(), but it's just too ugly ... */
+ for (;;) {
+ int page_bak;
+ if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE)
+ break;
+ page_bak = page;
+ if (!setjmp(globals.ev.canit)) {
+ fprintf(stderr, "current position: %lu; seeking to: %lu\n",
+ (unsigned long)pos_save,
+ (unsigned long)pageinfo_get_offset(page));
+ (void) fprintf(stderr, "seeking to offset %ld, page %d of file %d\n",
+ pageinfo_get_offset(page),
+ page, fileno(globals.dvi_file.bak_fp));
+ fseek(fp, pageinfo_get_offset(page), SEEK_SET);
+ spcl_scan(special_proc, info, False);
+ }
+ else { /* if interrupted */
+ fprintf(stderr, "========= interrupted!\n");
+ if (page >= page_bak)
+ page = page_bak;
+ break;
+ }
+ if (page >= current_page)
+ break;
+ page++;
+ }
+#endif
+ /* now we restore those pesky globals, hoping that nobody
+ has stamped upon them in the meantime. */
+ restore_file_status(fp, currinf_save, maxchar_save, pos_save);
+
+ /* reposition file pointer */
+ (void)fseek(fp, pageinfo_get_offset(page), SEEK_SET);
+}
+
+
+/* dump the `open' commands on the current stack to the FILE *fp */
+static void
+stack_dump_open_commands(FILE *fp, long *pos)
+{
+ size_t i;
+ TRACE_GUI((stderr, "length of stacks: %lu, %lu",
+ (unsigned long)color_save_stack.stack_len,
+ (unsigned long)href_save_stack.stack_len));
+ for (i = 0; i < color_save_stack.stack_len; i++) {
+ TRACE_GUI((stderr, "dumping: |%s|", color_save_stack.items[i].content));
+ write_special(color_save_stack.items[i].content, fp, pos);
+ }
+ for (i = 0; i < href_save_stack.stack_len; i++) {
+ TRACE_GUI((stderr, "dumping: |%s|", href_save_stack.items[i].content));
+ write_special(href_save_stack.items[i].content, fp, pos);
+ }
+ if (dvips_papersize_special != NULL)
+ write_special(dvips_papersize_special, fp, pos);
+ TRACE_GUI((stderr, "end of dumping open\n"));
+}
+
+/* dump `close' commands for all the `open' commands on the
+ current stack (not the saved one, but the one active at the end of the page)
+ to the FILE *fp (closing tags for hyperref anchors,
+ `pop' commands for color specials).
+*/
+static void
+stack_dump_close_commands(FILE *fp, long *pos)
+{
+ size_t i;
+
+ for (i = color_stack.stack_len; i > 0; i--) {
+ TRACE_GUI((stderr, "===== color pop"));
+ write_special("color pop", fp, pos);
+ }
+ for (i = href_stack.stack_len; i > 0; i--) {
+ TRACE_GUI((stderr, "===== html:</a>"));
+ write_special("html:</a>", fp, pos);
+ }
+}
+
+
+static void
+WriteDVI(FILE *fin, FILE *fout, long *fout_pos, int c)
+{
+ int i, n;
+ struct fontinfo *fontp;
+
+ if (c >= FNTNUM0 && c <= FNT4) {
+ if (c >= FNT1)
+ n = get_bytes(fin, c - FNT1 + 1);
+ else
+ n = c - FNTNUM0;
+ for (fontp = fontinfo_head; fontp; fontp = fontp->next)
+ if (n == fontp->TeXnumber)
+ break;
+ if (fontp && fontp->used == False) {
+ fontp->used = True;
+ FontWrite(fout, fontp, fout_pos);
+ }
+ putc(c, fout);
+ (*fout_pos)++;
+ switch (c) {
+ case FNT4:
+ putc((n >> 24) & 0xff, fout);
+ (*fout_pos)++;
+ case FNT3:
+ putc((n >> 16) & 0xff, fout);
+ (*fout_pos)++;
+ case FNT2:
+ putc((n >> 8) & 0xff, fout);
+ (*fout_pos)++;
+ case FNT1:
+ putc(n & 0xff, fout);
+ (*fout_pos)++;
+ default:
+ break;
+ }
+ }
+ else if (c >= FNTDEF1 && c <= FNTDEF4) {
+ n = get_bytes(fin, c - FNTDEF1 + 1);
+ for (fontp = fontinfo_head; fontp; fontp = fontp->next)
+ if (n == fontp->TeXnumber)
+ break;
+ if (fontp && fontp->used == False) {
+ fontp->used = True;
+ FontWrite(fout, fontp, fout_pos);
+ }
+ (void) get_bytes(fin, 12);
+ (void) get_bytes(fin, (int)(get_byte(fin) + get_byte(fin)));
+ }
+ else {
+ putc(c, fout);
+ (*fout_pos)++;
+ n = 0;
+ if (c <= XXX4) {
+ for (i = 0; i < c - XXX1 + 1; i++) {
+ int x = get_byte(fin);
+ putc(x, fout);
+ (*fout_pos)++;
+ n = (n << 8) | x;
+ }
+ }
+ switch (c) {
+ case SETRULE:
+ case PUTRULE:
+ n += 4;
+ /* fall through */
+
+ case RIGHT4:
+ case W4:
+ case X4:
+ case DOWN4:
+ case Y4:
+ case Z4:
+ n++;
+ /* fall through */
+
+ case RIGHT3:
+ case W3:
+ case X3:
+ case DOWN3:
+ case Y3:
+ case Z3:
+ n++;
+ /* fall through */
+
+ case SET2:
+ case PUT2:
+ if (!resource.omega) {
+ dvi_fmt_error("%s:%d: WriteDVI: op-code %d only works with the \"-omega\" option",
+ __FILE__, __LINE__, c);
+ }
+ case RIGHT2:
+ case W2:
+ case X2:
+ case DOWN2:
+ case Y2:
+ case Z2:
+ n++;
+ /* fall through */
+
+ case SET1:
+ case PUT1:
+ case RIGHT1:
+ case W1:
+ case X1:
+ case DOWN1:
+ case Y1:
+ case Z1:
+#ifdef PTEX
+ case TDIR:
+#endif
+ n++;
+ /* fall through */
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ CopyNum(fin, fout, n);
+ (*fout_pos) += n;
+ /* fall through */
+
+ default:
+ break;
+ }
+ }
+}
+
+/* public functions */
+
+
+/* callback functions for selecting pages */
+Boolean
+check_pagerange(struct select_pages_info *info, int page)
+{
+ return (page >= info->from && page <= info->to);
+}
+
+Boolean
+check_marked(struct select_pages_info *info, int page)
+{
+ UNUSED(info);
+ return pageinfo_is_marked(page);
+}
+
+void
+select_pages(struct select_pages_info *pinfo)
+{
+ int c, n, page, pagecnt;
+ long fout_pos = 0L;
+ unsigned long curr_page_offset = 0xffffffff; /* pattern to be overwritten later */
+ unsigned long post_cmd_offset = 0xffffffff; /* pattern to be overwritten later */
+ struct fontinfo *fontp;
+ FILE *in_fp = pinfo->finfo->dvi_in.fp;
+ FILE *out_fp = pinfo->finfo->dvi_tmp.fp;
+
+ Boolean headers_dumped = False;
+ free(dvips_papersize_special); /* re-initialize */
+ dvips_papersize_special = NULL;
+
+ ASSERT(in_fp != NULL, "input file mustn't be NULL in select_pages()!");
+ ASSERT(out_fp != NULL, "output file mustn't be NULL in select_pages()!");
+
+ pinfo->errflag = NO_ERROR; /* reset errflag, in case we're recovering from a previous error */
+
+ /* get font list from postamble; in_fp already has been positioned
+ at correct position (start of postamble) in caller. */
+ (void)fseek(in_fp, ftell(in_fp), SEEK_SET); /* paranoia */
+ (void)get_bytes(in_fp, POSTAMBLE_LEN);
+ fontinfo_head = NULL;
+ for (;;) {
+ if ((c = get_byte(in_fp)) < FNTDEF1 || c > FNTDEF4) /* maybe POSTPOST */
+ break;
+ fontp = (struct fontinfo *) xmalloc(sizeof(struct fontinfo));
+ fontp->TeXnumber = get_bytes(in_fp, c - FNTDEF1 + 1);
+ fread(fontp->info, sizeof(char), 14, in_fp);
+ n = fontp->info[12] + fontp->info[13];
+ fontp->fontname = xmalloc(n);
+ fread(fontp->fontname, sizeof(char), n, in_fp);
+ fontp->next = fontinfo_head;
+ fontinfo_head = fontp;
+ fontp->used = False;
+ }
+
+ /* preamble */
+ fseek(in_fp, 0L, SEEK_SET);
+ fout_pos = pageinfo_get_offset(0);
+ CopyNum(in_fp, out_fp, fout_pos);
+
+ /* each page */
+ pagecnt = 0;
+ for (page = 0; page < total_pages; page++) {
+ scan_page_for_specials(in_fp, page, True, stack_save, NULL);
+
+ /* should the current page be selected? */
+ if (pinfo->callback == NULL || pinfo->callback(pinfo, page)) {
+ scan_page_for_specials(in_fp, page, False, scan_for_included_files, pinfo);
+
+ /* read BOP except for p[4] */
+ CopyNum(in_fp, out_fp, BOP_PART_LEN);
+ /* read p[4] (previous bop pointer */
+ (void)get_bytes(in_fp, 4);
+ /* write actual value of p[4] */
+ PutFour(curr_page_offset, out_fp);
+ /* remember offset of current page, for postamble */
+ curr_page_offset = fout_pos;
+ /* update fout_pos to current position */
+ fout_pos += BOP_LEN;
+
+ if (!headers_dumped) {
+ headers_dumped = True;
+ dump_literal_headers(out_fp, &fout_pos);
+ }
+
+ /* if (!written_pre_cmds) { */
+ stack_dump_open_commands(out_fp, &fout_pos);
+/* written_pre_cmds = True; */
+/* } */
+
+ while ((c = getc(in_fp)) != EOF) {
+ if ((c & 0x80) == 0) { /* ordinary character */
+ putc(c, out_fp);
+ fout_pos++;
+ }
+ else if (c == EOP) { /* End Of Page */
+/* fprintf(stderr, "EOP at %ld\n", ftell(fin)); */
+
+/* if (page == to) { */ /* print close stack for last page */
+ stack_dump_close_commands(out_fp, &fout_pos);
+/* } */
+
+ putc(c, out_fp);
+ fout_pos++;
+ break;
+ }
+ else {
+/* fprintf(stderr, "WRITE_DVI before: %ld, in_fp before: %ld\n", fout_pos, ftell(in_fp)); */
+ WriteDVI(in_fp, out_fp, &fout_pos, c);
+/* fprintf(stderr, "WRITE_DVI after: %ld; in_fp after: %ld\n", fout_pos, ftell(in_fp)); */
+ }
+ /* HACK alert: force synchronization - why is this neccessary?
+ Seems to have something do with the fact that two FILE *'s on the same
+ file are open. POSIX.1,
+ `Interaction of File Descriptors and Standard I/O Streams' seems to
+ say the seek()s on one of them also affect the other, but I'm not sure
+ about this.
+ */
+ fseek(in_fp, 0L, SEEK_CUR);
+ }
+ pagecnt++;
+ }
+ }
+
+ /* postamble */
+ if (!find_postamble(in_fp, &(pinfo->errflag))) {
+ return;
+ }
+
+ /* read/write POST command */
+ putc(get_byte(in_fp), out_fp);
+ /* read over last page offset */
+ get_bytes(in_fp, 4);
+ /* write last page offset */
+ PutFour(curr_page_offset, out_fp);
+ /* remember start of POST */
+ post_cmd_offset = fout_pos;
+ /* copy part of postamble */
+ CopyNum(in_fp, out_fp, POSTAMBLE_PART_LEN);
+ /* read t[2], total number of pages */
+ get_bytes(in_fp, 2);
+ /* write t[2] (two calls) */
+ putc((pagecnt >> 8) & 0xff, out_fp);
+ putc(pagecnt & 0xff, out_fp);
+ /* update fout_pos to current pos */
+ fout_pos += POSTAMBLE_LEN;
+
+ /* output font list */
+ for (;;) {
+ if ((c = get_byte(in_fp)) < FNTDEF1 || c > FNTDEF4) /* maybe POSTPOST */
+ break;
+ n = get_bytes(in_fp, c - FNTDEF1 + 1);
+ for (fontp = fontinfo_head; fontp; fontp = fontp->next)
+ if (n == fontp->TeXnumber)
+ break;
+ if (fontp && fontp->used == True)
+ FontWrite(out_fp, fontp, &fout_pos);
+ (void) get_bytes(in_fp, 12);
+ (void) get_bytes(in_fp, (int)(get_byte(in_fp) + get_byte(in_fp)));
+ }
+
+ /* free list */
+ for (fontp = fontinfo_head; fontp;) {
+ struct fontinfo *nextp;
+ free(fontp->fontname);
+ nextp = fontp->next;
+ free(fontp);
+ fontp = nextp;
+ }
+
+ /* POSTPOST */
+ putc(c, out_fp);
+ get_bytes(in_fp, 4);
+ PutFour(post_cmd_offset, out_fp);
+ CopyNum(in_fp, out_fp, 1 + 4);
+ for (fout_pos += 1 + 4 + 1 + 4;
+ fout_pos & 3;
+ fout_pos++) {
+ putc(TRAILER, out_fp);
+ }
+
+/* fclose(in_fp); */
+ fflush(out_fp);
+}
+
diff --git a/Build/source/texk/xdvik/dvisel.h b/Build/source/texk/xdvik/dvisel.h
new file mode 100644
index 00000000000..6e395564466
--- /dev/null
+++ b/Build/source/texk/xdvik/dvisel.h
@@ -0,0 +1,42 @@
+/*
+ * select pages from a DVI file.
+ *
+ * The original version is:
+ * Copyright (c) 1999
+ * WATANABE Takeshi watanabe@komadori.planet.sci.kobe-u.ac.jp
+ *
+ * Heavily changed for xdvik:
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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 ANY AUTHO 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.
+ */
+
+#ifndef DVISEL_H_
+#define DVISEL_H_
+
+#include "dvi-init.h"
+#include "print-internal.h"
+
+/* callbacks */
+Boolean check_pagerange(struct select_pages_info *pinfo, int pageno);
+Boolean check_marked(struct select_pages_info *pinfo, int pageno);
+void select_pages(struct select_pages_info *pinfo);
+
+#endif /* DVISEL_H_ */
diff --git a/Build/source/texk/xdvik/encodings.c b/Build/source/texk/xdvik/encodings.c
new file mode 100644
index 00000000000..37cb883498c
--- /dev/null
+++ b/Build/source/texk/xdvik/encodings.c
@@ -0,0 +1,3989 @@
+/* The unicode2adobe structure and the adobe2unicode_table mapping is taken
+ from the catdvi (v0.12) `adobetbl.h' source file; it has the following copyright:
+
+ catdvi - get text from DVI files
+ Copyright (C) 1999 Antti-Juhani Kaijanaho <gaia@iki.fi>
+ Copyright (C) 2001 Bjoern Brill <brill@fs.math.uni-frankfurt.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Other parts are adapted from the GNU `iconv' library,
+ (search for `iconv'), which has the following copyright:
+
+ Copyright (C) 1999-2001 Free Software Foundation, Inc.
+
+ The GNU LIBICONV Library is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ The GNU LIBICONV Library is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ If not, write to the Free Software Foundation, Inc., 59 Temple Place -
+ Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+
+/* The rest of the file is Copyright (c) 2003-2004 the xdvik development team
+
+ 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.
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#if HAVE_ICONV_H
+# include <iconv.h>
+static iconv_t m_iconv_gb_ucs4 = (iconv_t)(-1);
+#endif /* HAVE_ICONV_H */
+
+#include <ctype.h>
+
+#include "util.h"
+#include "encodings.h"
+#include "my-snprintf.h"
+#include "message-window.h"
+
+#define MY_DEBUG 0
+
+#if MY_DEBUG
+# define TRACE_FIND_VERBOSE(x) TRACE_FIND(x)
+#else
+# define TRACE_FIND_VERBOSE(x) /* as nothing */
+#endif
+
+/*
+ The following encoding vectors are copied from catdvi's enc/xyz.h files;
+ only the `.notdef' values have been replaced by 0 instead of 0x003f
+ (question mark) to make the mapping more flexible.
+*/
+
+/* from enc/texmsym.h */
+static uint32_t m_cm_symbol_encoding[256] = {
+ 0x2212, 0x00b7, 0x00d7, 0x2217, 0x00f7, 0x22c4, 0x00b1, 0x2213,
+ 0x2295, 0x2296, 0x2297, 0x2298, 0x2299, 0x25ef, 0x25e6, 0x2022,
+ /* 0x10 */
+ 0x224d, 0x2261, 0x2286, 0x2287, 0x2264, 0x2265, 0x227c, 0x227d,
+ 0x223c, 0x2248, 0x2282, 0x2283, 0x226a, 0x226b, 0x227a, 0x227b,
+ /* 0x20 */
+ 0x2190, 0x2192, 0x2191, 0x2193, 0x2194, 0x2197, 0x2198, 0x2243,
+ 0x21d0, 0x21d2, 0x21d1, 0x21d3, 0x21d4, 0x2196, 0x2199, 0x221d,
+ /* 0x30 */
+ 0x2032, 0x221e, 0x2208, 0x220b, 0x25b3, 0x25bd, 0x10fffc, 0,
+ 0x2200, 0x2203, 0x00ac, 0x2205, 0x211c, 0x2111, 0x22a4, 0x22a5,
+ /* 0x40 */
+ 0x2135, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x222a, 0x2229, 0x228e, 0x2227, 0x2228,
+ /* 0x60 */
+ 0x22a2, 0x22a3, 0x230a, 0x230b, 0x2308, 0x2309, 0x007b, 0x007d,
+ 0x2329, 0x232a, 0x007c, 0x2225, 0x2195, 0x21d5, 0x005c, 0x2240,
+ /* 0x70 */
+ 0x221a, 0x2210, 0x2207, 0x222b, 0x2294, 0x2293, 0x2291, 0x2292,
+ 0x00a7, 0x2020, 0x2021, 0x00b6, 0x2663, 0x2666, 0x2665, 0x2660,
+ /* 0x80 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0b0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* from enc/texmital.h */
+static uint32_t m_cm_math_italics_encoding[256] = {
+ /* 0x00 */
+ 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03a0, 0x03a3, 0x03a5,
+ 0x03a6, 0x03a8, 0x03a9, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03f5,
+ /* 0x10 */
+ 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd,
+ 0x03be, 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d5, 0x03c7,
+ /* 0x20 */
+ 0x03c8, 0x03c9, 0x03b5, 0x03d1, 0x03d6, 0x03f1, 0x03c2, 0x03c6,
+ 0x21bc, 0x21bd, 0x21c0, 0x21c1, 0, 0, 0x22b3, 0x22b2,
+ /* 0x30 */
+ 0xf730, 0xf731, 0xf732, 0xf733, 0xf734, 0xf735, 0xf736, 0xf737,
+ 0xf738, 0xf739, 0x002e, 0x002c, 0x003c, 0x002f, 0x003e, 0x22c6,
+ /* 0x40 */
+ 0x2202, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x266d, 0x266e, 0x266f, 0x2323, 0x2322,
+ /* 0x60 */
+ 0x2113, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70 */
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x0131, 0xf6be, 0x2118, 0x10fffb, 0x2040,
+ /* 0x80 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xb0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* from enc/texmext.h */
+static uint32_t m_cm_math_extended_encoding[256] = {
+ /* 0x00 */
+ 0x10ff00, 0x10ff01, 0x10ff02, 0x10ff03, 0x10ff04, 0x10ff05, 0x10ff06, 0x10ff07,
+ 0x10ff08, 0x10ff09, 0x10ff0a, 0x10ff0b, 0x10ff0c, 0x10ff0d, 0x10ff0e, 0x10ff0f,
+ /* 0x10 */
+ 0x10ff10, 0x10ff11, 0x10ff12, 0x10ff13, 0x10ff14, 0x10ff15, 0x10ff16, 0x10ff17,
+ 0x10ff18, 0x10ff19, 0x10ff1a, 0x10ff1b, 0x10ff1c, 0x10ff1d, 0x10ff1e, 0x10ff1f,
+ /* 0x20 */
+ 0x10ff20, 0x10ff21, 0x10ff22, 0x10ff23, 0x10ff24, 0x10ff25, 0x10ff26, 0x10ff27,
+ 0x10ff28, 0x10ff29, 0x10ff2a, 0x10ff2b, 0x10ff2c, 0x10ff2d, 0x10ff2e, 0x10ff2f,
+ /* 0x30 */
+ 0xf8eb, 0xf8f6, 0xf8ee, 0xf8f9, 0xf8f0, 0xf8fb, 0xf8ef, 0xf8fa,
+ 0xf8f1, 0xf8fc, 0xf8f3, 0xf8fe, 0xf8f2, 0xf8fd, 0xf8f4, 0xf8e6,
+ /* 0x40 */
+ 0xf8ed, 0xf8f8, 0xf8ec, 0xf8f7, 0x10ff44, 0x10ff45, 0x10ff46, 0x10ff47,
+ 0x10ff48, 0x10ff49, 0x10ff4a, 0x10ff4b, 0x10ff4c, 0x10ff4d, 0x10ff4e, 0x10ff4f,
+ /* 0x50 */
+ 0x10ff50, 0x10ff51, 0x10ff52, 0x10ff53, 0x10ff54, 0x10ff55, 0x10ff56, 0x10ff57,
+ 0x10ff58, 0x10ff59, 0x10ff5a, 0x10ff5b, 0x10ff5c, 0x10ff5d, 0x10ff5e, 0x10ff5f,
+ /* 0x60 */
+ 0x10ff60, 0x10ff61, 0x10ff62, 0x10ff63, 0x10ff64, 0x10ff65, 0x10ff66, 0x10ff67,
+ 0x10ff68, 0x10ff69, 0x10ff6a, 0x10ff6b, 0x10ff6c, 0x10ff6d, 0x10ff6e, 0x10ff6f,
+ /* 0x70 */
+ 0x10ff70, 0x10ff71, 0x10ff72, 0x10ff73, 0x10ff74, 0x10ff75, 0x10ff76, 0x10ff77,
+ 0x10ff78, 0x10ff79, 0x10ff7a, 0x10ff7b, 0x10ff7c, 0x10ff7d, 0x10ff7e, 0x10ff7f,
+ /* 0x80 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xb0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* from enc/textt.h */
+static uint32_t m_cm_typewriter_encoding[256] = {
+ /* 0x00 */
+ 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03a0, 0x03a3, 0x03a5,
+ 0x03a6, 0x03a8, 0x03a9, 0x2191, 0x2193, 0x0027, 0x00a1, 0x00bf,
+ /* 0x10 */
+ 0x0131, 0xf6be, 0x0060, 0x00b4, 0x02c7, 0x02d8, 0x00af, 0x02da,
+ 0x00b8, 0x00df, 0x00e6, 0x0153, 0x00f8, 0x00c6, 0x0152, 0x00d8,
+ /* 0x20 */
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ /* 0x30 */
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ /* 0x40 */
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x02c6, 0x005f,
+ /* 0x60 */
+ 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70 */
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x02dc, 0x00a8,
+ /* 0x80 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xb0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* from enc/ot1.h */
+static uint32_t m_ot1_encoding[256] = {
+ /* 0x00 */
+ 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03a0, 0x03a3, 0x03a5,
+ 0x03a6, 0x03a8, 0x03a9, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04,
+ /* 0x10 */
+ 0x0131, 0xf6be, 0x0060, 0x00b4, 0x02c7, 0x02d8, 0x00af, 0x02da,
+ 0x00b8, 0x00df, 0x00e6, 0x0153, 0x00f8, 0x00c6, 0x0152, 0x00d8,
+ /* 0x20 */
+ 0x0020, 0x0021, 0x201c, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ /* 0x30 */
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x00a1, 0x003d, 0x00bf, 0x003f,
+ /* 0x40 */
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x201d, 0x005d, 0x02c6, 0x02d9,
+ /* 0x60 */
+ 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70 */
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x2013, 0x2014, 0x0022, 0x02dc, 0x00a8,
+ /* 0x80 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xa0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xb0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xc0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* Cyrilic e.g. fro larm1000.mf; from
+ http://www.tug.org/tex-archive/macros/latex/contrib/t2/enc-maps/OT2uni.map */
+static uint32_t m_t2_encoding[256] = {
+ 0x0060, 0x00b4, 0x02c6, 0x02dc, 0x00a8, 0x02dd, 0x02da, 0x02c7,
+ 0x02d8, 0x00af, 0x02d9, 0x00b8, 0x02db, 0x04c0, 0x2329, 0x232a,
+ /* 0x10 */
+ 0x201c, 0x201d, 0xf6d5, 0xf6d6, 0xf6d4, 0x2013, 0x2014, 0xfeff,
+ 0x2080, 0x0131, 0xf6be, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04,
+ /* 0x20 */
+ 0x2420, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ /* 0x30 */
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ /* 0x40 */
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ /* 0x60 */
+ 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70 */
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x002d,
+ /* 0x80 */
+ 0x0490, 0x0492, 0x0402, 0x040b, 0x04ba, 0x0496, 0x0498, 0x0409,
+ 0x0407, 0x049a, 0x04a0, 0x049c, 0x04d4, 0x04a2, 0x04a4, 0x0405,
+ /* 0x90 */
+ 0x04e8, 0x04aa, 0x040e, 0x04ae, 0x04b0, 0x04b2, 0x040f, 0x04b8,
+ 0x04b6, 0x0404, 0x04d8, 0x040a, 0x0401, 0x2116, 0x00a4, 0x00a7,
+ /* 0xa0 */
+ 0x0491, 0x0493, 0x0452, 0x045b, 0x04bb, 0x0497, 0x0499, 0x0459,
+ 0x0457, 0x049b, 0x04a1, 0x049d, 0x04d5, 0x04a3, 0x04a5, 0x0455,
+ /* 0xb0 */
+ 0x04e9, 0x04ab, 0x045e, 0x04af, 0x04b1, 0x04b3, 0x045f, 0x04b9,
+ 0x04b7, 0x0454, 0x04d9, 0x045a, 0x0451, 0x201e, 0x00ab, 0x00bb,
+ /* 0xc0 */
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ /* 0xd0 */
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+ /* 0xe0 */
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ /* 0xf0 */
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+};
+
+/* from enc/cork.h */
+static uint32_t m_cork_encoding[256] = {
+ /* 0x00 */
+ 0x0060, 0x00b4, 0x02c6, 0x02dc, 0x00a8, 0x02dd, 0x02da, 0x02c7,
+ 0x02d8, 0x00af, 0x02d9, 0x00b8, 0x02db, 0x201a, 0x2039, 0x203a,
+ /* 0x10 */
+ 0x201c, 0x201d, 0x201e, 0x00ab, 0x00bb, 0x2013, 0x2014, 0x0020,
+ 0x0030, 0x0131, 0xf6be, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04,
+ /* 0x20 */
+ 0x2420, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ /* 0x30 */
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ /* 0x40 */
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ /* 0x60 */
+ 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70 */
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x002d,
+ /* 0x80 */
+ 0x0102, 0x0104, 0x0106, 0x010c, 0x010e, 0x011a, 0x0118, 0x011e,
+ 0x0139, 0x013d, 0x0141, 0x0143, 0x0147, 0x10ffff, 0x0150, 0x0154,
+ /* 0x90 */
+ 0x0158, 0x015a, 0x0160, 0x015e, 0x0164, 0x0162, 0x0170, 0x016e,
+ 0x0178, 0x0179, 0x017d, 0x017b, 0x0132, 0x0130, 0x0111, 0x00a7,
+ /* 0xa0 */
+ 0x0103, 0x0105, 0x0107, 0x010d, 0x010f, 0x011b, 0x0119, 0x011f,
+ 0x013a, 0x013e, 0x0142, 0x0144, 0x0148, 0x10fffe, 0x0151, 0x0155,
+ /* 0xb0 */
+ 0x0159, 0x015b, 0x0161, 0x015f, 0x0165, 0x0163, 0x0171, 0x016f,
+ 0x00FF, 0x017a, 0x017e, 0x017c, 0x0133, 0x00a1, 0x00bf, 0x00a3,
+ /* 0xc0 */
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ /* 0xd0 */
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0152,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x10fffd,
+ /* 0xe0 */
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ /* 0xf0 */
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0153,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df
+};
+
+/* Newly created ts1-lm.h, which we use for TC (textcomp) fonts.
+ This only gets the accents and stuff from iso-latin1 right; lots of
+ the special characters aren't defined in the Adobe lookup list
+ used by catdvi's `pse2unic'.
+ */
+static uint32_t m_ts1_encoding[256] = {
+ /* 0x00 */
+ 0x0060, 0x00b4, 0x02c6, 0x02dc, 0x00a8, 0x02dd, 0x02da, 0x02c7,
+ 0x02d8, 0, 0x02d9, 0x00b8, 0x02db, 0, 0, 0,
+ /* 0x10 */
+ 0, 0, 0, 0, 0, 0x2013, 0xf6de, 0,
+ 0x2190, 0x2192, 0, 0, 0, 0, 0, 0,
+ /* 0x20 */
+ 0, 0, 0, 0, 0x0024, 0, 0, 0,
+ 0, 0, 0x2217, 0, 0x002c, 0, 0x002e, 0,
+ /* 0x30 */
+ 0xf730, 0xf731, 0xf732, 0xf733, 0xf734, 0xf735, 0xf736, 0xf737,
+ 0xf738, 0xf739, 0, 0, 0x2329, 0x2212, 0x232a, 0,
+ /* 0x40 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x50 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2191, 0x2193,
+ /* 0x60 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x266a, 0,
+ /* 0x70 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x007e, 0x003d,
+ /* 0x80 */
+ 0, 0, 0, 0, 0x2020, 0x2021, 0, 0x2030,
+ 0x2022, 0, 0xf724, 0xf7a2, 0x0192, 0x20a1, 0, 0,
+ /* 0x90 */
+ 0, 0, 0x20a4, 0, 0, 0, 0x20ab, 0x2122,
+ 0, 0, 0, 0, 0, 0x212e, 0x25e6, 0,
+ /* 0xa0 */
+ 0, 0, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0, 0x00a9, 0x00aa, 0, 0x00ac, 0, 0x00ae, 0,
+ /* 0xb0 */
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0, 0, 0x00b6, 0x00b7,
+ 0, 0x00b9, 0x00ba, 0x221a, 0x00bc, 0x00bd, 0x00be, 0x20ac,
+ /* 0xc0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xd0 */
+ 0, 0, 0, 0, 0, 0, 0x00d7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xe0 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xf0 */
+ 0, 0, 0, 0, 0, 0, 0x00f7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* blackletter fonts with funny encodings
+ */
+static uint32_t m_yfrak_encoding[176] = {
+ /* 0x00 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x10 */
+ 0x0131, 0xF6BE, 0x0060, 0x00b4, 0x02c7, 0x02d8, 0x00af, 0x02da,
+ 0x00b8, 0, 0x00df, 0, 0, 0, 0, 0,
+ /* 0x20 */
+ 0, 0x0021, 0x0022, 0x0023, 0, 0x0025, 0, 0x2019,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ /* 0x30 */
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0, 0x003c, 0x003d, 0, 0x003f,
+ /* 0x40 */
+ 0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ /* 0x50 */
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x00ab, 0x005d, 0x005e, 0x02d9,
+ /* 0x60 */
+ 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ /* 0x70 */
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x2013, 0x2014, 0x00a8, 0x02dd, 0,
+ /* 0x80 */ /* ch/ck ligatures treated as special cases */
+ 0, 0xfb00, 0xfb05, 0xfb00, 0xfb00, 0, 0, 0,
+ 0, 0x00e4, 0x00e4, 0, 0, 0x0073, 0, 0,
+ /* 0x90 */
+ 0x00eb, 0x00eb, 0, 0, 0, 0, 0, 0,
+ 0, 0x00f6, 0x00f6, 0, 0, 0, 0x00fc, 0x00fc,
+ /* 0xa0 */
+ 0, 0, 0, 0, 0x00B6, 0, 0, 0 /* sz */,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ Mapping table of adobe character names (from .enc files) to Unicode IDs.
+ Taken from catdvi's adobetbl.h; the original glyph list is available from:
+ http://partners.adobe.com/asn/tech/type/glyphlist.txt
+ All `private space' entries have been removed (I think they are of not
+ much use).
+
+ The names beginning with `$' have been added by the catdvi developers.
+
+ Changes:
+ - The macros DUP1/DUP2 have been #if 0'ed because I didn't understand them.
+ - `.notdef' has been replaced by 0 to remove ambiguity with the real question mark.
+
+ The list is sorted for strcmp() so that we can use bsearch() on it.
+*/
+static struct adobe2unicode adobe2unicode_table[] = {
+ { "$Delta" , 0x0394 }, /* GREEK CAPITAL LETTER DELTA; distinguish Adobe duplicates */
+ { "$Ohm" , 0x2126 }, /* OHM SIGN; distinguish Adobe duplicates */
+ { "$Omega" , 0x03A9 }, /* GREEK CAPITAL LETTER OMEGA; distinguish Adobe duplicates */
+ { "$Scedilla" , 0x015E }, /* LATIN CAPITAL LETTER S WITH CEDILLA; distinguish Adobe duplicates */
+ { "$Tcedilla", 0x0162 }, /* LATIN CAPITAL LETTER T WITH CEDILLA; distinguish Adobe duplicates */
+ { "$Tcommaaccent", 0x021A }, /* LATIN CAPITAL LETTER T WITH COMMA BELOW; distinguish Adobe duplicates */
+ { "$acutemodifier", 0x02CA }, /* MODIFIER LETTER ACUTE ACCENT */
+ { "$arrowdblupdn", 0x21D5 }, /* UP DOWN DOUBLE ARROW */
+ { "$arrownortheast", 0x2197 }, /* NORTH EAST ARROW */
+ { "$arrownorthwest", 0x2196 }, /* NORTH WEST ARROW */
+ { "$arrowsoutheast", 0x2198 }, /* SOUTH EAST ARROW */
+ { "$arrowsouthwest", 0x2199 }, /* SOUTH WEST ARROW */
+ { "$brevecomb", 0x0306 }, /* COMBINING BREVE */
+ { "$bulletmath" , 0x2219 }, /* BULLET OPERATOR; distinguish Adobe duplicates */
+ { "$caroncomb", 0x030C }, /* COMBINING CARON */
+ { "$cedillacomb", 0x0327 }, /* COMBINING CEDILLA */
+ { "$ceilingleft", 0x2308 }, /* LEFT CEILING */
+ { "$ceilingright", 0x2309 }, /* RIGHT CEILING */
+ { "$circlecomb", 0x20DD }, /* COMBINING ENCLOSING CIRCLE */
+ { "$circledivide", 0x2298 }, /* CIRCLED DIVISION SLASH */
+ { "$circledot", 0x2299 }, /* CIRCLED DOT OPERATOR */
+ { "$circlelarge", 0x25EF }, /* LARGE CIRCLE */
+ { "$circleminus", 0x2296 }, /* CIRCLED MINUS */
+ { "$circumflexcomb", 0x0302 }, /* COMBINING CIRCUMFLEX ACCENT */
+ { "$contintegral", 0x222E }, /* CONTOUR INTEGRAL */
+ { "$coproduct", 0x2210 }, /* N-ARY COPRODUCT */
+ { "$diamondmath", 0x22C4 }, /* DIAMOND OPERATOR */
+ { "$dieresiscomb", 0x0308 }, /* COMBINING DIAERESIS */
+ { "$divisionslash", 0x2215 }, /* DIVISION SLASH; distinguish Adobe duplicates */
+ { "$dotaccentcomb", 0x0307 }, /* COMBINING DOT ABOVE */
+ { "$epsilon1", 0x03F5 }, /* GREEK LUNATE EPSILON SYMBOL */
+ { "$equivasymptotic", 0x224D }, /* EQUIVALENT TO */
+ { "$flat", 0x266D }, /* MUSIC FLAT SIGN */
+ { "$floorleft", 0x230A }, /* LEFT FLOOR */
+ { "$floorright", 0x230B }, /* RIGHT FLOOR */
+ { "$follows", 0x227B }, /* SUCCEEDS */
+ { "$followsequal", 0x227D }, /* SUCCEEDS OR EQUAL TO */
+ { "$fractionslash", 0x2044 }, /* FRACTION SLASH; distinguish Adobe duplicates */
+ { "$frown", 0x2322 }, /* FROWN */
+ { "$gravemodifier", 0x02CB }, /* MODIFIER LETTER GRAVE ACCENT */
+ { "$greatermuch", 0x226B }, /* MUCH GREATER-THAN */
+ { "$harpoonleftbarbdown", 0x21BD }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS */
+ { "$harpoonleftbarbup", 0x21BC }, /* LEFTWARDS HARPOON WITH BARB UPWARDS */
+ { "$harpoonrightbarbdown", 0x21C1 }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS */
+ { "$harpoonrightbarbup", 0x21C0 }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS */
+ { "$hyphen" , 0x002D }, /* HYPHEN-MINUS; distinguish Adobe duplicates */
+ { "$hyphensoft" , 0x00AD }, /* SOFT HYPHEN; distinguish Adobe duplicates */
+ { "$increment" , 0x2206 }, /* INCREMENT; distinguish Adobe duplicates */
+ { "$intersectionsq", 0x2293 }, /* SQUARE CAP */
+ { "$latticetop", 0x22A4 }, /* DOWN TACK */
+ { "$lessmuch", 0x226A }, /* MUCH-LESS THAN */
+ { "$longst", 0xFB05 }, /* LATIN SMALL LIGATURE LONG S T */
+ { "$lscript", 0x2113 }, /* SCRIPT SMALL L; Adobe has this as "afii61289" */
+ { "$macron", 0x00AF }, /* MACRON; distinguish Adobe duplicates */
+ { "$macroncomb", 0x0304 }, /* COMBINING MACRON */
+ { "$macronmodifier", 0x02C9 }, /* MODIFIER LETTER MACRON */
+ { "$micro", 0x00B5 }, /* MICRO SIGN; distinguish Adobe duplicates */
+ { "$minusplus", 0x2213 }, /* MINUS-OR-PLUS SIGN */
+ { "$mu", 0x03BC }, /* GREEK SMALL LETTER MU; distinguish Adobe duplicates */
+ { "$natural", 0x266E }, /* MUSIC NATURAL SIGN */
+ { "$normalin", 0x22B2 }, /* NORMAL SUBGROUP OF */
+ { "$normalizes", 0x22B3 }, /* CONTAINS AS NORMAL SUBGROUP */
+ { "$ogonekcomb", 0x0328 }, /* COMBINING OGONEK */
+ { "$overlinecomb", 0x0305 }, /* COMBINING OVERLINE */
+ { "$parallel", 0x2225 }, /* PARALLEL TO */
+ { "$periodcentered" , 0x00B7 }, /* MIDDLE DOT; distinguish Adobe duplicates */
+ { "$pi1", 0x03D6 }, /* GREEK PI SYMBOL; Adobe has this as "omega1" which is too confusing */
+ { "$precedes", 0x227A }, /* PRECEDES */
+ { "$precedesequal", 0x227C }, /* PRECEDES OR EQUAL TO */
+ { "$quotedblreversed", 0x201F }, /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK */
+ { "$reflexnormalin", 0x22B4 }, /* NORMAL SUBGROUP OF OR EQUAL TO */
+ { "$reflexnormalizes", 0x22B5 }, /* CONTAINS AS NORMAL SUBGROUP OR EQUAL TO */
+ { "$reflexsubsetsq", 0x2291 }, /* SQUARE IMAGE OF OR EQUAL TO */
+ { "$reflexsupersetsq", 0x2292 }, /* SQUARE ORIGINAL OF OR EQUAL TO */
+ { "$rho1", 0x03F1 }, /* GREEK RHO SYMBOL */
+ { "$ringcomb", 0x030A }, /* COMBINING RING ABOVE */
+ { "$scedilla" , 0x015F }, /* LATIN SMALL LETTER S WITH CEDILLA; distinguish Adobe duplicates */
+ { "$sharp", 0x266F }, /* MUSIC SHARP SIGN */
+ { "$similarequal", 0x2243 }, /* ASYMPTOTICALLY EQUAL TO */
+ { "$slashlongcomb", 0x0338 }, /* COMBINING LONG SOLIDUS OVERLAY */
+ { "$smile", 0x2323 }, /* SMILE */
+ { "$space" , 0x0020 }, /* SPACE; distinguish Adobe duplicates */
+ { "$spacenobreak" , 0x00A0 }, /* NO-BREAK SPACE; distinguish Adobe duplicates */
+ { "$spacesymbol", 0x2420 }, /* SYMBOL FOR SPACE */
+ { "$st", 0xFB06 }, /* LATIN SMALL LIGATURE ST */
+ { "$starmath", 0x22C6 }, /* STAR OPERATOR */
+ { "$tcedilla", 0x0163 }, /* LATIN SMALL LETTER T WITH CEDILLA; distinguish Adobe duplicates */
+ { "$tcommaaccent", 0x021B }, /* LATIN SMALL LETTER T WITH COMMA BELOW; distinguish Adobe duplicates */
+ { "$tie", 0x2040 }, /* CHARACTER TIE */
+ { "$triagwhitedn", 0x25BD }, /* WHITE DOWN-POINTING TRIANGLE */
+ { "$triagwhiteup", 0x25B3 }, /* WHITE UP-POINTING TRIANGLE */
+ { "$turnstileleft", 0x22A2 }, /* RIGHT TACK */
+ { "$turnstileright", 0x22A3 }, /* LEFT TACK */
+ { "$unionmulti", 0x228E }, /* MULTISET UNION */
+ { "$unionsq", 0x2294 }, /* SQUARE CUP */
+ { "$vectorcomb", 0x20D7 }, /* COMBINING RIGHT ARROW ABOVE */
+ { "$wreathproduct", 0x2240 }, /* WREATH PRODUCT */
+ { ".notdef", 0 }, /* was: QUESTION MARK; changed to 0 */
+ { "A", 0x0041 }, /* LATIN CAPITAL LETTER A */
+ { "AE", 0x00C6 }, /* LATIN CAPITAL LETTER AE */
+ { "AEacute", 0x01FC }, /* LATIN CAPITAL LETTER AE WITH ACUTE */
+ { "AEsmall", 0xF7E6 }, /* LATIN SMALL CAPITAL LETTER AE */
+ { "Aacute", 0x00C1 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
+ { "Aacutesmall", 0xF7E1 }, /* LATIN SMALL CAPITAL LETTER A WITH ACUTE */
+ { "Abreve", 0x0102 }, /* LATIN CAPITAL LETTER A WITH BREVE */
+ { "Acircumflex", 0x00C2 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ { "Acircumflexsmall", 0xF7E2 }, /* LATIN SMALL CAPITAL LETTER A WITH CIRCUMFLEX */
+ { "Acute", 0xF6C9 }, /* CAPITAL ACUTE ACCENT */
+ { "Acutesmall", 0xF7B4 }, /* SMALL CAPITAL ACUTE ACCENT */
+ { "Adieresis", 0x00C4 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
+ { "Adieresissmall", 0xF7E4 }, /* LATIN SMALL CAPITAL LETTER A WITH DIAERESIS */
+ { "Agrave", 0x00C0 }, /* LATIN CAPITAL LETTER A WITH GRAVE */
+ { "Agravesmall", 0xF7E0 }, /* LATIN SMALL CAPITAL LETTER A WITH GRAVE */
+ { "Alpha", 0x0391 }, /* GREEK CAPITAL LETTER ALPHA */
+ { "Alphatonos", 0x0386 }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */
+ { "Amacron", 0x0100 }, /* LATIN CAPITAL LETTER A WITH MACRON */
+ { "Aogonek", 0x0104 }, /* LATIN CAPITAL LETTER A WITH OGONEK */
+ { "Aring", 0x00C5 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
+ { "Aringacute", 0x01FA }, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE */
+ { "Aringsmall", 0xF7E5 }, /* LATIN SMALL CAPITAL LETTER A WITH RING ABOVE */
+ { "Asmall", 0xF761 }, /* LATIN SMALL CAPITAL LETTER A */
+ { "Atilde", 0x00C3 }, /* LATIN CAPITAL LETTER A WITH TILDE */
+ { "Atildesmall", 0xF7E3 }, /* LATIN SMALL CAPITAL LETTER A WITH TILDE */
+ { "B", 0x0042 }, /* LATIN CAPITAL LETTER B */
+ { "Beta", 0x0392 }, /* GREEK CAPITAL LETTER BETA */
+ { "Brevesmall", 0xF6F4 }, /* SMALL CAPITAL BREVE */
+ { "Bsmall", 0xF762 }, /* LATIN SMALL CAPITAL LETTER B */
+ { "C", 0x0043 }, /* LATIN CAPITAL LETTER C */
+ { "Cacute", 0x0106 }, /* LATIN CAPITAL LETTER C WITH ACUTE */
+ { "Caron", 0xF6CA }, /* CAPITAL CARON */
+ { "Caronsmall", 0xF6F5 }, /* SMALL CAPITAL CARON */
+ { "Ccaron", 0x010C }, /* LATIN CAPITAL LETTER C WITH CARON */
+ { "Ccedilla", 0x00C7 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
+ { "Ccedillasmall", 0xF7E7 }, /* LATIN SMALL CAPITAL LETTER C WITH CEDILLA */
+ { "Ccircumflex", 0x0108 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+ { "Cdotaccent", 0x010A }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */
+ { "Cedillasmall", 0xF7B8 }, /* SMALL CAPITAL CEDILLA */
+ { "Chi", 0x03A7 }, /* GREEK CAPITAL LETTER CHI */
+ { "Circumflexsmall", 0xF6F6 }, /* SMALL CAPITAL MODIFIER LETTER CIRCUMFLEX ACCENT */
+ { "Csmall", 0xF763 }, /* LATIN SMALL CAPITAL LETTER C */
+ { "D", 0x0044 }, /* LATIN CAPITAL LETTER D */
+ { "Dcaron", 0x010E }, /* LATIN CAPITAL LETTER D WITH CARON */
+ { "Dcroat", 0x0110 }, /* LATIN CAPITAL LETTER D WITH STROKE */
+ { "Delta", 0x2206 }, /* INCREMENT */
+#if 0
+ { "Delta" DUP2, 0x0394 }, /* GREEK CAPITAL LETTER DELTA;Duplicate */
+#endif /* 0 */
+ { "Dieresis", 0xF6CB }, /* CAPITAL DIAERESIS */
+ { "DieresisAcute", 0xF6CC }, /* CAPITAL DIAERESIS ACUTE ACCENT */
+ { "DieresisGrave", 0xF6CD }, /* CAPITAL DIAERESIS GRAVE ACCENT */
+ { "Dieresissmall", 0xF7A8 }, /* SMALL CAPITAL DIAERESIS */
+ { "Dotaccentsmall", 0xF6F7 }, /* SMALL CAPITAL DOT ABOVE */
+ { "Dsmall", 0xF764 }, /* LATIN SMALL CAPITAL LETTER D */
+ { "E", 0x0045 }, /* LATIN CAPITAL LETTER E */
+ { "Eacute", 0x00C9 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
+ { "Eacutesmall", 0xF7E9 }, /* LATIN SMALL CAPITAL LETTER E WITH ACUTE */
+ { "Ebreve", 0x0114 }, /* LATIN CAPITAL LETTER E WITH BREVE */
+ { "Ecaron", 0x011A }, /* LATIN CAPITAL LETTER E WITH CARON */
+ { "Ecircumflex", 0x00CA }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ { "Ecircumflexsmall", 0xF7EA }, /* LATIN SMALL CAPITAL LETTER E WITH CIRCUMFLEX */
+ { "Edieresis", 0x00CB }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+ { "Edieresissmall", 0xF7EB }, /* LATIN SMALL CAPITAL LETTER E WITH DIAERESIS */
+ { "Edotaccent", 0x0116 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */
+ { "Egrave", 0x00C8 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
+ { "Egravesmall", 0xF7E8 }, /* LATIN SMALL CAPITAL LETTER E WITH GRAVE */
+ { "Emacron", 0x0112 }, /* LATIN CAPITAL LETTER E WITH MACRON */
+ { "Eng", 0x014A }, /* LATIN CAPITAL LETTER ENG */
+ { "Eogonek", 0x0118 }, /* LATIN CAPITAL LETTER E WITH OGONEK */
+ { "Epsilon", 0x0395 }, /* GREEK CAPITAL LETTER EPSILON */
+ { "Epsilontonos", 0x0388 }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */
+ { "Esmall", 0xF765 }, /* LATIN SMALL CAPITAL LETTER E */
+ { "Eta", 0x0397 }, /* GREEK CAPITAL LETTER ETA */
+ { "Etatonos", 0x0389 }, /* GREEK CAPITAL LETTER ETA WITH TONOS */
+ { "Eth", 0x00D0 }, /* LATIN CAPITAL LETTER ETH */
+ { "Ethsmall", 0xF7F0 }, /* LATIN SMALL CAPITAL LETTER ETH */
+ { "Euro", 0x20AC }, /* EURO SIGN */
+ { "F", 0x0046 }, /* LATIN CAPITAL LETTER F */
+ { "Fsmall", 0xF766 }, /* LATIN SMALL CAPITAL LETTER F */
+ { "G", 0x0047 }, /* LATIN CAPITAL LETTER G */
+ { "Gamma", 0x0393 }, /* GREEK CAPITAL LETTER GAMMA */
+ { "Gbreve", 0x011E }, /* LATIN CAPITAL LETTER G WITH BREVE */
+ { "Gcaron", 0x01E6 }, /* LATIN CAPITAL LETTER G WITH CARON */
+ { "Gcircumflex", 0x011C }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+ { "Gcommaaccent", 0x0122 }, /* LATIN CAPITAL LETTER G WITH CEDILLA */
+ { "Gdotaccent", 0x0120 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */
+ { "Grave", 0xF6CE }, /* CAPITAL GRAVE ACCENT */
+ { "Gravesmall", 0xF760 }, /* SMALL CAPITAL GRAVE ACCENT */
+ { "Gsmall", 0xF767 }, /* LATIN SMALL CAPITAL LETTER G */
+ { "H", 0x0048 }, /* LATIN CAPITAL LETTER H */
+ { "H18533", 0x25CF }, /* BLACK CIRCLE */
+ { "H18543", 0x25AA }, /* BLACK SMALL SQUARE */
+ { "H18551", 0x25AB }, /* WHITE SMALL SQUARE */
+ { "H22073", 0x25A1 }, /* WHITE SQUARE */
+ { "Hbar", 0x0126 }, /* LATIN CAPITAL LETTER H WITH STROKE */
+ { "Hcircumflex", 0x0124 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+ { "Hsmall", 0xF768 }, /* LATIN SMALL CAPITAL LETTER H */
+ { "Hungarumlaut", 0xF6CF }, /* CAPITAL DOUBLE ACUTE ACCENT */
+ { "Hungarumlautsmall", 0xF6F8 }, /* SMALL CAPITAL DOUBLE ACUTE ACCENT */
+ { "I", 0x0049 }, /* LATIN CAPITAL LETTER I */
+ { "IJ", 0x0132 }, /* LATIN CAPITAL LIGATURE IJ */
+ { "Iacute", 0x00CD }, /* LATIN CAPITAL LETTER I WITH ACUTE */
+ { "Iacutesmall", 0xF7ED }, /* LATIN SMALL CAPITAL LETTER I WITH ACUTE */
+ { "Ibreve", 0x012C }, /* LATIN CAPITAL LETTER I WITH BREVE */
+ { "Icircumflex", 0x00CE }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ { "Icircumflexsmall", 0xF7EE }, /* LATIN SMALL CAPITAL LETTER I WITH CIRCUMFLEX */
+ { "Idieresis", 0x00CF }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+ { "Idieresissmall", 0xF7EF }, /* LATIN SMALL CAPITAL LETTER I WITH DIAERESIS */
+ { "Idotaccent", 0x0130 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ { "Ifraktur", 0x2111 }, /* BLACK-LETTER CAPITAL I */
+ { "Igrave", 0x00CC }, /* LATIN CAPITAL LETTER I WITH GRAVE */
+ { "Igravesmall", 0xF7EC }, /* LATIN SMALL CAPITAL LETTER I WITH GRAVE */
+ { "Imacron", 0x012A }, /* LATIN CAPITAL LETTER I WITH MACRON */
+ { "Iogonek", 0x012E }, /* LATIN CAPITAL LETTER I WITH OGONEK */
+ { "Iota", 0x0399 }, /* GREEK CAPITAL LETTER IOTA */
+ { "Iotadieresis", 0x03AA }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+ { "Iotatonos", 0x038A }, /* GREEK CAPITAL LETTER IOTA WITH TONOS */
+ { "Ismall", 0xF769 }, /* LATIN SMALL CAPITAL LETTER I */
+ { "Itilde", 0x0128 }, /* LATIN CAPITAL LETTER I WITH TILDE */
+ { "J", 0x004A }, /* LATIN CAPITAL LETTER J */
+ { "Jcircumflex", 0x0134 }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+ { "Jsmall", 0xF76A }, /* LATIN SMALL CAPITAL LETTER J */
+ { "K", 0x004B }, /* LATIN CAPITAL LETTER K */
+ { "Kappa", 0x039A }, /* GREEK CAPITAL LETTER KAPPA */
+ { "Kcommaaccent", 0x0136 }, /* LATIN CAPITAL LETTER K WITH CEDILLA */
+ { "Ksmall", 0xF76B }, /* LATIN SMALL CAPITAL LETTER K */
+ { "L", 0x004C }, /* LATIN CAPITAL LETTER L */
+ { "LL", 0xF6BF }, /* LATIN CAPITAL LETTER LL */
+ { "Lacute", 0x0139 }, /* LATIN CAPITAL LETTER L WITH ACUTE */
+ { "Lambda", 0x039B }, /* GREEK CAPITAL LETTER LAMDA */
+ { "Lcaron", 0x013D }, /* LATIN CAPITAL LETTER L WITH CARON */
+ { "Lcommaaccent", 0x013B }, /* LATIN CAPITAL LETTER L WITH CEDILLA */
+ { "Ldot", 0x013F }, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */
+ { "Lslash", 0x0141 }, /* LATIN CAPITAL LETTER L WITH STROKE */
+ { "Lslashsmall", 0xF6F9 }, /* LATIN SMALL CAPITAL LETTER L WITH STROKE */
+ { "Lsmall", 0xF76C }, /* LATIN SMALL CAPITAL LETTER L */
+ { "M", 0x004D }, /* LATIN CAPITAL LETTER M */
+ { "Macron", 0xF6D0 }, /* CAPITAL MACRON */
+ { "Macronsmall", 0xF7AF }, /* SMALL CAPITAL MACRON */
+ { "Msmall", 0xF76D }, /* LATIN SMALL CAPITAL LETTER M */
+ { "Mu", 0x039C }, /* GREEK CAPITAL LETTER MU */
+ { "N", 0x004E }, /* LATIN CAPITAL LETTER N */
+ { "Nacute", 0x0143 }, /* LATIN CAPITAL LETTER N WITH ACUTE */
+ { "Ncaron", 0x0147 }, /* LATIN CAPITAL LETTER N WITH CARON */
+ { "Ncommaaccent", 0x0145 }, /* LATIN CAPITAL LETTER N WITH CEDILLA */
+ { "Nsmall", 0xF76E }, /* LATIN SMALL CAPITAL LETTER N */
+ { "Ntilde", 0x00D1 }, /* LATIN CAPITAL LETTER N WITH TILDE */
+ { "Ntildesmall", 0xF7F1 }, /* LATIN SMALL CAPITAL LETTER N WITH TILDE */
+ { "Nu", 0x039D }, /* GREEK CAPITAL LETTER NU */
+ { "O", 0x004F }, /* LATIN CAPITAL LETTER O */
+ { "OE", 0x0152 }, /* LATIN CAPITAL LIGATURE OE */
+ { "OEsmall", 0xF6FA }, /* LATIN SMALL CAPITAL LIGATURE OE */
+ { "Oacute", 0x00D3 }, /* LATIN CAPITAL LETTER O WITH ACUTE */
+ { "Oacutesmall", 0xF7F3 }, /* LATIN SMALL CAPITAL LETTER O WITH ACUTE */
+ { "Obreve", 0x014E }, /* LATIN CAPITAL LETTER O WITH BREVE */
+ { "Ocircumflex", 0x00D4 }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ { "Ocircumflexsmall", 0xF7F4 }, /* LATIN SMALL CAPITAL LETTER O WITH CIRCUMFLEX */
+ { "Odieresis", 0x00D6 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
+ { "Odieresissmall", 0xF7F6 }, /* LATIN SMALL CAPITAL LETTER O WITH DIAERESIS */
+ { "Ogoneksmall", 0xF6FB }, /* SMALL CAPITAL OGONEK */
+ { "Ograve", 0x00D2 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
+ { "Ogravesmall", 0xF7F2 }, /* LATIN SMALL CAPITAL LETTER O WITH GRAVE */
+ { "Ohorn", 0x01A0 }, /* LATIN CAPITAL LETTER O WITH HORN */
+ { "Ohungarumlaut", 0x0150 }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+ { "Omacron", 0x014C }, /* LATIN CAPITAL LETTER O WITH MACRON */
+ { "Omega", 0x2126 }, /* OHM SIGN */
+#if 0
+ { "Omega" DUP2, 0x03A9 }, /* GREEK CAPITAL LETTER OMEGA;Duplicate */
+#endif /* 0 */
+ { "Omegatonos", 0x038F }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */
+ { "Omicron", 0x039F }, /* GREEK CAPITAL LETTER OMICRON */
+ { "Omicrontonos", 0x038C }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */
+ { "Oslash", 0x00D8 }, /* LATIN CAPITAL LETTER O WITH STROKE */
+ { "Oslashacute", 0x01FE }, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE */
+ { "Oslashsmall", 0xF7F8 }, /* LATIN SMALL CAPITAL LETTER O WITH STROKE */
+ { "Osmall", 0xF76F }, /* LATIN SMALL CAPITAL LETTER O */
+ { "Otilde", 0x00D5 }, /* LATIN CAPITAL LETTER O WITH TILDE */
+ { "Otildesmall", 0xF7F5 }, /* LATIN SMALL CAPITAL LETTER O WITH TILDE */
+ { "P", 0x0050 }, /* LATIN CAPITAL LETTER P */
+ { "Phi", 0x03A6 }, /* GREEK CAPITAL LETTER PHI */
+ { "Pi", 0x03A0 }, /* GREEK CAPITAL LETTER PI */
+ { "Psi", 0x03A8 }, /* GREEK CAPITAL LETTER PSI */
+ { "Psmall", 0xF770 }, /* LATIN SMALL CAPITAL LETTER P */
+ { "Q", 0x0051 }, /* LATIN CAPITAL LETTER Q */
+ { "Qsmall", 0xF771 }, /* LATIN SMALL CAPITAL LETTER Q */
+ { "R", 0x0052 }, /* LATIN CAPITAL LETTER R */
+ { "Racute", 0x0154 }, /* LATIN CAPITAL LETTER R WITH ACUTE */
+ { "Rcaron", 0x0158 }, /* LATIN CAPITAL LETTER R WITH CARON */
+ { "Rcommaaccent", 0x0156 }, /* LATIN CAPITAL LETTER R WITH CEDILLA */
+ { "Rfraktur", 0x211C }, /* BLACK-LETTER CAPITAL R */
+ { "Rho", 0x03A1 }, /* GREEK CAPITAL LETTER RHO */
+ { "Ringsmall", 0xF6FC }, /* SMALL CAPITAL RING ABOVE */
+ { "Rsmall", 0xF772 }, /* LATIN SMALL CAPITAL LETTER R */
+ { "S", 0x0053 }, /* LATIN CAPITAL LETTER S */
+ { "SF010000", 0x250C }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */
+ { "SF020000", 0x2514 }, /* BOX DRAWINGS LIGHT UP AND RIGHT */
+ { "SF030000", 0x2510 }, /* BOX DRAWINGS LIGHT DOWN AND LEFT */
+ { "SF040000", 0x2518 }, /* BOX DRAWINGS LIGHT UP AND LEFT */
+ { "SF050000", 0x253C }, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+ { "SF060000", 0x252C }, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+ { "SF070000", 0x2534 }, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+ { "SF080000", 0x251C }, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+ { "SF090000", 0x2524 }, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+ { "SF100000", 0x2500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */
+ { "SF110000", 0x2502 }, /* BOX DRAWINGS LIGHT VERTICAL */
+ { "SF190000", 0x2561 }, /* BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE */
+ { "SF200000", 0x2562 }, /* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */
+ { "SF210000", 0x2556 }, /* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */
+ { "SF220000", 0x2555 }, /* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */
+ { "SF230000", 0x2563 }, /* BOX DRAWINGS DOUBLE VERTICAL AND LEFT */
+ { "SF240000", 0x2551 }, /* BOX DRAWINGS DOUBLE VERTICAL */
+ { "SF250000", 0x2557 }, /* BOX DRAWINGS DOUBLE DOWN AND LEFT */
+ { "SF260000", 0x255D }, /* BOX DRAWINGS DOUBLE UP AND LEFT */
+ { "SF270000", 0x255C }, /* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */
+ { "SF280000", 0x255B }, /* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */
+ { "SF360000", 0x255E }, /* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */
+ { "SF370000", 0x255F }, /* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */
+ { "SF380000", 0x255A }, /* BOX DRAWINGS DOUBLE UP AND RIGHT */
+ { "SF390000", 0x2554 }, /* BOX DRAWINGS DOUBLE DOWN AND RIGHT */
+ { "SF400000", 0x2569 }, /* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */
+ { "SF410000", 0x2566 }, /* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */
+ { "SF420000", 0x2560 }, /* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */
+ { "SF430000", 0x2550 }, /* BOX DRAWINGS DOUBLE HORIZONTAL */
+ { "SF440000", 0x256C }, /* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */
+ { "SF450000", 0x2567 }, /* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */
+ { "SF460000", 0x2568 }, /* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */
+ { "SF470000", 0x2564 }, /* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */
+ { "SF480000", 0x2565 }, /* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */
+ { "SF490000", 0x2559 }, /* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */
+ { "SF500000", 0x2558 }, /* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */
+ { "SF510000", 0x2552 }, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */
+ { "SF520000", 0x2553 }, /* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */
+ { "SF530000", 0x256B }, /* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */
+ { "SF540000", 0x256A }, /* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */
+ { "Sacute", 0x015A }, /* LATIN CAPITAL LETTER S WITH ACUTE */
+ { "Scaron", 0x0160 }, /* LATIN CAPITAL LETTER S WITH CARON */
+ { "Scaronsmall", 0xF6FD }, /* LATIN SMALL CAPITAL LETTER S WITH CARON */
+ { "Scedilla", 0x015E }, /* LATIN CAPITAL LETTER S WITH CEDILLA */
+#if 0
+ { "Scedilla" DUP2, 0xF6C1 }, /* LATIN CAPITAL LETTER S WITH CEDILLA;Duplicate */
+#endif /* 0 */
+ { "Scircumflex", 0x015C }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+ { "Scommaaccent", 0x0218 }, /* LATIN CAPITAL LETTER S WITH COMMA BELOW */
+ { "Sigma", 0x03A3 }, /* GREEK CAPITAL LETTER SIGMA */
+ { "Ssmall", 0xF773 }, /* LATIN SMALL CAPITAL LETTER S */
+ { "T", 0x0054 }, /* LATIN CAPITAL LETTER T */
+ { "Tau", 0x03A4 }, /* GREEK CAPITAL LETTER TAU */
+ { "Tbar", 0x0166 }, /* LATIN CAPITAL LETTER T WITH STROKE */
+ { "Tcaron", 0x0164 }, /* LATIN CAPITAL LETTER T WITH CARON */
+ { "Tcommaaccent", 0x0162 }, /* LATIN CAPITAL LETTER T WITH CEDILLA */
+#if 0
+ { "Tcommaaccent" DUP2, 0x021A }, /* LATIN CAPITAL LETTER T WITH COMMA BELOW;Duplicate */
+#endif /* 0 */
+ { "Theta", 0x0398 }, /* GREEK CAPITAL LETTER THETA */
+ { "Thorn", 0x00DE }, /* LATIN CAPITAL LETTER THORN */
+ { "Thornsmall", 0xF7FE }, /* LATIN SMALL CAPITAL LETTER THORN */
+ { "Tildesmall", 0xF6FE }, /* SMALL CAPITAL SMALL TILDE */
+ { "Tsmall", 0xF774 }, /* LATIN SMALL CAPITAL LETTER T */
+ { "U", 0x0055 }, /* LATIN CAPITAL LETTER U */
+ { "Uacute", 0x00DA }, /* LATIN CAPITAL LETTER U WITH ACUTE */
+ { "Uacutesmall", 0xF7FA }, /* LATIN SMALL CAPITAL LETTER U WITH ACUTE */
+ { "Ubreve", 0x016C }, /* LATIN CAPITAL LETTER U WITH BREVE */
+ { "Ucircumflex", 0x00DB }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ { "Ucircumflexsmall", 0xF7FB }, /* LATIN SMALL CAPITAL LETTER U WITH CIRCUMFLEX */
+ { "Udieresis", 0x00DC }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
+ { "Udieresissmall", 0xF7FC }, /* LATIN SMALL CAPITAL LETTER U WITH DIAERESIS */
+ { "Ugrave", 0x00D9 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
+ { "Ugravesmall", 0xF7F9 }, /* LATIN SMALL CAPITAL LETTER U WITH GRAVE */
+ { "Uhorn", 0x01AF }, /* LATIN CAPITAL LETTER U WITH HORN */
+ { "Uhungarumlaut", 0x0170 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+ { "Umacron", 0x016A }, /* LATIN CAPITAL LETTER U WITH MACRON */
+ { "Uogonek", 0x0172 }, /* LATIN CAPITAL LETTER U WITH OGONEK */
+ { "Upsilon", 0x03A5 }, /* GREEK CAPITAL LETTER UPSILON */
+ { "Upsilon1", 0x03D2 }, /* GREEK UPSILON WITH HOOK SYMBOL */
+ { "Upsilondieresis", 0x03AB }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+ { "Upsilontonos", 0x038E }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */
+ { "Uring", 0x016E }, /* LATIN CAPITAL LETTER U WITH RING ABOVE */
+ { "Usmall", 0xF775 }, /* LATIN SMALL CAPITAL LETTER U */
+ { "Utilde", 0x0168 }, /* LATIN CAPITAL LETTER U WITH TILDE */
+ { "V", 0x0056 }, /* LATIN CAPITAL LETTER V */
+ { "Vsmall", 0xF776 }, /* LATIN SMALL CAPITAL LETTER V */
+ { "W", 0x0057 }, /* LATIN CAPITAL LETTER W */
+ { "Wacute", 0x1E82 }, /* LATIN CAPITAL LETTER W WITH ACUTE */
+ { "Wcircumflex", 0x0174 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
+ { "Wdieresis", 0x1E84 }, /* LATIN CAPITAL LETTER W WITH DIAERESIS */
+ { "Wgrave", 0x1E80 }, /* LATIN CAPITAL LETTER W WITH GRAVE */
+ { "Wsmall", 0xF777 }, /* LATIN SMALL CAPITAL LETTER W */
+ { "X", 0x0058 }, /* LATIN CAPITAL LETTER X */
+ { "Xi", 0x039E }, /* GREEK CAPITAL LETTER XI */
+ { "Xsmall", 0xF778 }, /* LATIN SMALL CAPITAL LETTER X */
+ { "Y", 0x0059 }, /* LATIN CAPITAL LETTER Y */
+ { "Yacute", 0x00DD }, /* LATIN CAPITAL LETTER Y WITH ACUTE */
+ { "Yacutesmall", 0xF7FD }, /* LATIN SMALL CAPITAL LETTER Y WITH ACUTE */
+ { "Ycircumflex", 0x0176 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
+ { "Ydieresis", 0x0178 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ { "Ydieresissmall", 0xF7FF }, /* LATIN SMALL CAPITAL LETTER Y WITH DIAERESIS */
+ { "Ygrave", 0x1EF2 }, /* LATIN CAPITAL LETTER Y WITH GRAVE */
+ { "Ysmall", 0xF779 }, /* LATIN SMALL CAPITAL LETTER Y */
+ { "Z", 0x005A }, /* LATIN CAPITAL LETTER Z */
+ { "Zacute", 0x0179 }, /* LATIN CAPITAL LETTER Z WITH ACUTE */
+ { "Zcaron", 0x017D }, /* LATIN CAPITAL LETTER Z WITH CARON */
+ { "Zcaronsmall", 0xF6FF }, /* LATIN SMALL CAPITAL LETTER Z WITH CARON */
+ { "Zdotaccent", 0x017B }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+ { "Zeta", 0x0396 }, /* GREEK CAPITAL LETTER ZETA */
+ { "Zsmall", 0xF77A }, /* LATIN SMALL CAPITAL LETTER Z */
+ { "a", 0x0061 }, /* LATIN SMALL LETTER A */
+ { "aacute", 0x00E1 }, /* LATIN SMALL LETTER A WITH ACUTE */
+ { "abreve", 0x0103 }, /* LATIN SMALL LETTER A WITH BREVE */
+ { "acircumflex", 0x00E2 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ { "acute", 0x00B4 }, /* ACUTE ACCENT */
+ { "acutecomb", 0x0301 }, /* COMBINING ACUTE ACCENT */
+ { "adieresis", 0x00E4 }, /* LATIN SMALL LETTER A WITH DIAERESIS */
+ { "ae", 0x00E6 }, /* LATIN SMALL LETTER AE */
+ { "aeacute", 0x01FD }, /* LATIN SMALL LETTER AE WITH ACUTE */
+ { "afii00208", 0x2015 }, /* HORIZONTAL BAR */
+ { "afii10017", 0x0410 }, /* CYRILLIC CAPITAL LETTER A */
+ { "afii10018", 0x0411 }, /* CYRILLIC CAPITAL LETTER BE */
+ { "afii10019", 0x0412 }, /* CYRILLIC CAPITAL LETTER VE */
+ { "afii10020", 0x0413 }, /* CYRILLIC CAPITAL LETTER GHE */
+ { "afii10021", 0x0414 }, /* CYRILLIC CAPITAL LETTER DE */
+ { "afii10022", 0x0415 }, /* CYRILLIC CAPITAL LETTER IE */
+ { "afii10023", 0x0401 }, /* CYRILLIC CAPITAL LETTER IO */
+ { "afii10024", 0x0416 }, /* CYRILLIC CAPITAL LETTER ZHE */
+ { "afii10025", 0x0417 }, /* CYRILLIC CAPITAL LETTER ZE */
+ { "afii10026", 0x0418 }, /* CYRILLIC CAPITAL LETTER I */
+ { "afii10027", 0x0419 }, /* CYRILLIC CAPITAL LETTER SHORT I */
+ { "afii10028", 0x041A }, /* CYRILLIC CAPITAL LETTER KA */
+ { "afii10029", 0x041B }, /* CYRILLIC CAPITAL LETTER EL */
+ { "afii10030", 0x041C }, /* CYRILLIC CAPITAL LETTER EM */
+ { "afii10031", 0x041D }, /* CYRILLIC CAPITAL LETTER EN */
+ { "afii10032", 0x041E }, /* CYRILLIC CAPITAL LETTER O */
+ { "afii10033", 0x041F }, /* CYRILLIC CAPITAL LETTER PE */
+ { "afii10034", 0x0420 }, /* CYRILLIC CAPITAL LETTER ER */
+ { "afii10035", 0x0421 }, /* CYRILLIC CAPITAL LETTER ES */
+ { "afii10036", 0x0422 }, /* CYRILLIC CAPITAL LETTER TE */
+ { "afii10037", 0x0423 }, /* CYRILLIC CAPITAL LETTER U */
+ { "afii10038", 0x0424 }, /* CYRILLIC CAPITAL LETTER EF */
+ { "afii10039", 0x0425 }, /* CYRILLIC CAPITAL LETTER HA */
+ { "afii10040", 0x0426 }, /* CYRILLIC CAPITAL LETTER TSE */
+ { "afii10041", 0x0427 }, /* CYRILLIC CAPITAL LETTER CHE */
+ { "afii10042", 0x0428 }, /* CYRILLIC CAPITAL LETTER SHA */
+ { "afii10043", 0x0429 }, /* CYRILLIC CAPITAL LETTER SHCHA */
+ { "afii10044", 0x042A }, /* CYRILLIC CAPITAL LETTER HARD SIGN */
+ { "afii10045", 0x042B }, /* CYRILLIC CAPITAL LETTER YERU */
+ { "afii10046", 0x042C }, /* CYRILLIC CAPITAL LETTER SOFT SIGN */
+ { "afii10047", 0x042D }, /* CYRILLIC CAPITAL LETTER E */
+ { "afii10048", 0x042E }, /* CYRILLIC CAPITAL LETTER YU */
+ { "afii10049", 0x042F }, /* CYRILLIC CAPITAL LETTER YA */
+ { "afii10050", 0x0490 }, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
+ { "afii10051", 0x0402 }, /* CYRILLIC CAPITAL LETTER DJE */
+ { "afii10052", 0x0403 }, /* CYRILLIC CAPITAL LETTER GJE */
+ { "afii10053", 0x0404 }, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+ { "afii10054", 0x0405 }, /* CYRILLIC CAPITAL LETTER DZE */
+ { "afii10055", 0x0406 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+ { "afii10056", 0x0407 }, /* CYRILLIC CAPITAL LETTER YI */
+ { "afii10057", 0x0408 }, /* CYRILLIC CAPITAL LETTER JE */
+ { "afii10058", 0x0409 }, /* CYRILLIC CAPITAL LETTER LJE */
+ { "afii10059", 0x040A }, /* CYRILLIC CAPITAL LETTER NJE */
+ { "afii10060", 0x040B }, /* CYRILLIC CAPITAL LETTER TSHE */
+ { "afii10061", 0x040C }, /* CYRILLIC CAPITAL LETTER KJE */
+ { "afii10062", 0x040E }, /* CYRILLIC CAPITAL LETTER SHORT U */
+ { "afii10063", 0xF6C4 }, /* CYRILLIC SMALL LETTER GHE VARIANT */
+ { "afii10064", 0xF6C5 }, /* CYRILLIC SMALL LETTER BE VARIANT */
+ { "afii10065", 0x0430 }, /* CYRILLIC SMALL LETTER A */
+ { "afii10066", 0x0431 }, /* CYRILLIC SMALL LETTER BE */
+ { "afii10067", 0x0432 }, /* CYRILLIC SMALL LETTER VE */
+ { "afii10068", 0x0433 }, /* CYRILLIC SMALL LETTER GHE */
+ { "afii10069", 0x0434 }, /* CYRILLIC SMALL LETTER DE */
+ { "afii10070", 0x0435 }, /* CYRILLIC SMALL LETTER IE */
+ { "afii10071", 0x0451 }, /* CYRILLIC SMALL LETTER IO */
+ { "afii10072", 0x0436 }, /* CYRILLIC SMALL LETTER ZHE */
+ { "afii10073", 0x0437 }, /* CYRILLIC SMALL LETTER ZE */
+ { "afii10074", 0x0438 }, /* CYRILLIC SMALL LETTER I */
+ { "afii10075", 0x0439 }, /* CYRILLIC SMALL LETTER SHORT I */
+ { "afii10076", 0x043A }, /* CYRILLIC SMALL LETTER KA */
+ { "afii10077", 0x043B }, /* CYRILLIC SMALL LETTER EL */
+ { "afii10078", 0x043C }, /* CYRILLIC SMALL LETTER EM */
+ { "afii10079", 0x043D }, /* CYRILLIC SMALL LETTER EN */
+ { "afii10080", 0x043E }, /* CYRILLIC SMALL LETTER O */
+ { "afii10081", 0x043F }, /* CYRILLIC SMALL LETTER PE */
+ { "afii10082", 0x0440 }, /* CYRILLIC SMALL LETTER ER */
+ { "afii10083", 0x0441 }, /* CYRILLIC SMALL LETTER ES */
+ { "afii10084", 0x0442 }, /* CYRILLIC SMALL LETTER TE */
+ { "afii10085", 0x0443 }, /* CYRILLIC SMALL LETTER U */
+ { "afii10086", 0x0444 }, /* CYRILLIC SMALL LETTER EF */
+ { "afii10087", 0x0445 }, /* CYRILLIC SMALL LETTER HA */
+ { "afii10088", 0x0446 }, /* CYRILLIC SMALL LETTER TSE */
+ { "afii10089", 0x0447 }, /* CYRILLIC SMALL LETTER CHE */
+ { "afii10090", 0x0448 }, /* CYRILLIC SMALL LETTER SHA */
+ { "afii10091", 0x0449 }, /* CYRILLIC SMALL LETTER SHCHA */
+ { "afii10092", 0x044A }, /* CYRILLIC SMALL LETTER HARD SIGN */
+ { "afii10093", 0x044B }, /* CYRILLIC SMALL LETTER YERU */
+ { "afii10094", 0x044C }, /* CYRILLIC SMALL LETTER SOFT SIGN */
+ { "afii10095", 0x044D }, /* CYRILLIC SMALL LETTER E */
+ { "afii10096", 0x044E }, /* CYRILLIC SMALL LETTER YU */
+ { "afii10097", 0x044F }, /* CYRILLIC SMALL LETTER YA */
+ { "afii10098", 0x0491 }, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */
+ { "afii10099", 0x0452 }, /* CYRILLIC SMALL LETTER DJE */
+ { "afii10100", 0x0453 }, /* CYRILLIC SMALL LETTER GJE */
+ { "afii10101", 0x0454 }, /* CYRILLIC SMALL LETTER UKRAINIAN IE */
+ { "afii10102", 0x0455 }, /* CYRILLIC SMALL LETTER DZE */
+ { "afii10103", 0x0456 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+ { "afii10104", 0x0457 }, /* CYRILLIC SMALL LETTER YI */
+ { "afii10105", 0x0458 }, /* CYRILLIC SMALL LETTER JE */
+ { "afii10106", 0x0459 }, /* CYRILLIC SMALL LETTER LJE */
+ { "afii10107", 0x045A }, /* CYRILLIC SMALL LETTER NJE */
+ { "afii10108", 0x045B }, /* CYRILLIC SMALL LETTER TSHE */
+ { "afii10109", 0x045C }, /* CYRILLIC SMALL LETTER KJE */
+ { "afii10110", 0x045E }, /* CYRILLIC SMALL LETTER SHORT U */
+ { "afii10145", 0x040F }, /* CYRILLIC CAPITAL LETTER DZHE */
+ { "afii10146", 0x0462 }, /* CYRILLIC CAPITAL LETTER YAT */
+ { "afii10147", 0x0472 }, /* CYRILLIC CAPITAL LETTER FITA */
+ { "afii10148", 0x0474 }, /* CYRILLIC CAPITAL LETTER IZHITSA */
+ { "afii10192", 0xF6C6 }, /* CYRILLIC SMALL LETTER DE VARIANT */
+ { "afii10193", 0x045F }, /* CYRILLIC SMALL LETTER DZHE */
+ { "afii10194", 0x0463 }, /* CYRILLIC SMALL LETTER YAT */
+ { "afii10195", 0x0473 }, /* CYRILLIC SMALL LETTER FITA */
+ { "afii10196", 0x0475 }, /* CYRILLIC SMALL LETTER IZHITSA */
+ { "afii10831", 0xF6C7 }, /* CYRILLIC SMALL LETTER PE VARIANT */
+ { "afii10832", 0xF6C8 }, /* CYRILLIC SMALL LETTER TE VARIANT */
+ { "afii10846", 0x04D9 }, /* CYRILLIC SMALL LETTER SCHWA */
+ { "afii299", 0x200E }, /* LEFT-TO-RIGHT MARK */
+ { "afii300", 0x200F }, /* RIGHT-TO-LEFT MARK */
+ { "afii301", 0x200D }, /* ZERO WIDTH JOINER */
+ { "afii57381", 0x066A }, /* ARABIC PERCENT SIGN */
+ { "afii57388", 0x060C }, /* ARABIC COMMA */
+ { "afii57392", 0x0660 }, /* ARABIC-INDIC DIGIT ZERO */
+ { "afii57393", 0x0661 }, /* ARABIC-INDIC DIGIT ONE */
+ { "afii57394", 0x0662 }, /* ARABIC-INDIC DIGIT TWO */
+ { "afii57395", 0x0663 }, /* ARABIC-INDIC DIGIT THREE */
+ { "afii57396", 0x0664 }, /* ARABIC-INDIC DIGIT FOUR */
+ { "afii57397", 0x0665 }, /* ARABIC-INDIC DIGIT FIVE */
+ { "afii57398", 0x0666 }, /* ARABIC-INDIC DIGIT SIX */
+ { "afii57399", 0x0667 }, /* ARABIC-INDIC DIGIT SEVEN */
+ { "afii57400", 0x0668 }, /* ARABIC-INDIC DIGIT EIGHT */
+ { "afii57401", 0x0669 }, /* ARABIC-INDIC DIGIT NINE */
+ { "afii57403", 0x061B }, /* ARABIC SEMICOLON */
+ { "afii57407", 0x061F }, /* ARABIC QUESTION MARK */
+ { "afii57409", 0x0621 }, /* ARABIC LETTER HAMZA */
+ { "afii57410", 0x0622 }, /* ARABIC LETTER ALEF WITH MADDA ABOVE */
+ { "afii57411", 0x0623 }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE */
+ { "afii57412", 0x0624 }, /* ARABIC LETTER WAW WITH HAMZA ABOVE */
+ { "afii57413", 0x0625 }, /* ARABIC LETTER ALEF WITH HAMZA BELOW */
+ { "afii57414", 0x0626 }, /* ARABIC LETTER YEH WITH HAMZA ABOVE */
+ { "afii57415", 0x0627 }, /* ARABIC LETTER ALEF */
+ { "afii57416", 0x0628 }, /* ARABIC LETTER BEH */
+ { "afii57417", 0x0629 }, /* ARABIC LETTER TEH MARBUTA */
+ { "afii57418", 0x062A }, /* ARABIC LETTER TEH */
+ { "afii57419", 0x062B }, /* ARABIC LETTER THEH */
+ { "afii57420", 0x062C }, /* ARABIC LETTER JEEM */
+ { "afii57421", 0x062D }, /* ARABIC LETTER HAH */
+ { "afii57422", 0x062E }, /* ARABIC LETTER KHAH */
+ { "afii57423", 0x062F }, /* ARABIC LETTER DAL */
+ { "afii57424", 0x0630 }, /* ARABIC LETTER THAL */
+ { "afii57425", 0x0631 }, /* ARABIC LETTER REH */
+ { "afii57426", 0x0632 }, /* ARABIC LETTER ZAIN */
+ { "afii57427", 0x0633 }, /* ARABIC LETTER SEEN */
+ { "afii57428", 0x0634 }, /* ARABIC LETTER SHEEN */
+ { "afii57429", 0x0635 }, /* ARABIC LETTER SAD */
+ { "afii57430", 0x0636 }, /* ARABIC LETTER DAD */
+ { "afii57431", 0x0637 }, /* ARABIC LETTER TAH */
+ { "afii57432", 0x0638 }, /* ARABIC LETTER ZAH */
+ { "afii57433", 0x0639 }, /* ARABIC LETTER AIN */
+ { "afii57434", 0x063A }, /* ARABIC LETTER GHAIN */
+ { "afii57440", 0x0640 }, /* ARABIC TATWEEL */
+ { "afii57441", 0x0641 }, /* ARABIC LETTER FEH */
+ { "afii57442", 0x0642 }, /* ARABIC LETTER QAF */
+ { "afii57443", 0x0643 }, /* ARABIC LETTER KAF */
+ { "afii57444", 0x0644 }, /* ARABIC LETTER LAM */
+ { "afii57445", 0x0645 }, /* ARABIC LETTER MEEM */
+ { "afii57446", 0x0646 }, /* ARABIC LETTER NOON */
+ { "afii57448", 0x0648 }, /* ARABIC LETTER WAW */
+ { "afii57449", 0x0649 }, /* ARABIC LETTER ALEF MAKSURA */
+ { "afii57450", 0x064A }, /* ARABIC LETTER YEH */
+ { "afii57451", 0x064B }, /* ARABIC FATHATAN */
+ { "afii57452", 0x064C }, /* ARABIC DAMMATAN */
+ { "afii57453", 0x064D }, /* ARABIC KASRATAN */
+ { "afii57454", 0x064E }, /* ARABIC FATHA */
+ { "afii57455", 0x064F }, /* ARABIC DAMMA */
+ { "afii57456", 0x0650 }, /* ARABIC KASRA */
+ { "afii57457", 0x0651 }, /* ARABIC SHADDA */
+ { "afii57458", 0x0652 }, /* ARABIC SUKUN */
+ { "afii57470", 0x0647 }, /* ARABIC LETTER HEH */
+ { "afii57505", 0x06A4 }, /* ARABIC LETTER VEH */
+ { "afii57506", 0x067E }, /* ARABIC LETTER PEH */
+ { "afii57507", 0x0686 }, /* ARABIC LETTER TCHEH */
+ { "afii57508", 0x0698 }, /* ARABIC LETTER JEH */
+ { "afii57509", 0x06AF }, /* ARABIC LETTER GAF */
+ { "afii57511", 0x0679 }, /* ARABIC LETTER TTEH */
+ { "afii57512", 0x0688 }, /* ARABIC LETTER DDAL */
+ { "afii57513", 0x0691 }, /* ARABIC LETTER RREH */
+ { "afii57514", 0x06BA }, /* ARABIC LETTER NOON GHUNNA */
+ { "afii57519", 0x06D2 }, /* ARABIC LETTER YEH BARREE */
+ { "afii57534", 0x06D5 }, /* ARABIC LETTER AE */
+ { "afii57636", 0x20AA }, /* NEW SHEQEL SIGN */
+ { "afii57645", 0x05BE }, /* HEBREW PUNCTUATION MAQAF */
+ { "afii57658", 0x05C3 }, /* HEBREW PUNCTUATION SOF PASUQ */
+ { "afii57664", 0x05D0 }, /* HEBREW LETTER ALEF */
+ { "afii57665", 0x05D1 }, /* HEBREW LETTER BET */
+ { "afii57666", 0x05D2 }, /* HEBREW LETTER GIMEL */
+ { "afii57667", 0x05D3 }, /* HEBREW LETTER DALET */
+ { "afii57668", 0x05D4 }, /* HEBREW LETTER HE */
+ { "afii57669", 0x05D5 }, /* HEBREW LETTER VAV */
+ { "afii57670", 0x05D6 }, /* HEBREW LETTER ZAYIN */
+ { "afii57671", 0x05D7 }, /* HEBREW LETTER HET */
+ { "afii57672", 0x05D8 }, /* HEBREW LETTER TET */
+ { "afii57673", 0x05D9 }, /* HEBREW LETTER YOD */
+ { "afii57674", 0x05DA }, /* HEBREW LETTER FINAL KAF */
+ { "afii57675", 0x05DB }, /* HEBREW LETTER KAF */
+ { "afii57676", 0x05DC }, /* HEBREW LETTER LAMED */
+ { "afii57677", 0x05DD }, /* HEBREW LETTER FINAL MEM */
+ { "afii57678", 0x05DE }, /* HEBREW LETTER MEM */
+ { "afii57679", 0x05DF }, /* HEBREW LETTER FINAL NUN */
+ { "afii57680", 0x05E0 }, /* HEBREW LETTER NUN */
+ { "afii57681", 0x05E1 }, /* HEBREW LETTER SAMEKH */
+ { "afii57682", 0x05E2 }, /* HEBREW LETTER AYIN */
+ { "afii57683", 0x05E3 }, /* HEBREW LETTER FINAL PE */
+ { "afii57684", 0x05E4 }, /* HEBREW LETTER PE */
+ { "afii57685", 0x05E5 }, /* HEBREW LETTER FINAL TSADI */
+ { "afii57686", 0x05E6 }, /* HEBREW LETTER TSADI */
+ { "afii57687", 0x05E7 }, /* HEBREW LETTER QOF */
+ { "afii57688", 0x05E8 }, /* HEBREW LETTER RESH */
+ { "afii57689", 0x05E9 }, /* HEBREW LETTER SHIN */
+ { "afii57690", 0x05EA }, /* HEBREW LETTER TAV */
+ { "afii57694", 0xFB2A }, /* HEBREW LETTER SHIN WITH SHIN DOT */
+ { "afii57695", 0xFB2B }, /* HEBREW LETTER SHIN WITH SIN DOT */
+ { "afii57700", 0xFB4B }, /* HEBREW LETTER VAV WITH HOLAM */
+ { "afii57705", 0xFB1F }, /* HEBREW LIGATURE YIDDISH YOD YOD PATAH */
+ { "afii57716", 0x05F0 }, /* HEBREW LIGATURE YIDDISH DOUBLE VAV */
+ { "afii57717", 0x05F1 }, /* HEBREW LIGATURE YIDDISH VAV YOD */
+ { "afii57718", 0x05F2 }, /* HEBREW LIGATURE YIDDISH DOUBLE YOD */
+ { "afii57723", 0xFB35 }, /* HEBREW LETTER VAV WITH DAGESH */
+ { "afii57793", 0x05B4 }, /* HEBREW POINT HIRIQ */
+ { "afii57794", 0x05B5 }, /* HEBREW POINT TSERE */
+ { "afii57795", 0x05B6 }, /* HEBREW POINT SEGOL */
+ { "afii57796", 0x05BB }, /* HEBREW POINT QUBUTS */
+ { "afii57797", 0x05B8 }, /* HEBREW POINT QAMATS */
+ { "afii57798", 0x05B7 }, /* HEBREW POINT PATAH */
+ { "afii57799", 0x05B0 }, /* HEBREW POINT SHEVA */
+ { "afii57800", 0x05B2 }, /* HEBREW POINT HATAF PATAH */
+ { "afii57801", 0x05B1 }, /* HEBREW POINT HATAF SEGOL */
+ { "afii57802", 0x05B3 }, /* HEBREW POINT HATAF QAMATS */
+ { "afii57803", 0x05C2 }, /* HEBREW POINT SIN DOT */
+ { "afii57804", 0x05C1 }, /* HEBREW POINT SHIN DOT */
+ { "afii57806", 0x05B9 }, /* HEBREW POINT HOLAM */
+ { "afii57807", 0x05BC }, /* HEBREW POINT DAGESH OR MAPIQ */
+ { "afii57839", 0x05BD }, /* HEBREW POINT METEG */
+ { "afii57841", 0x05BF }, /* HEBREW POINT RAFE */
+ { "afii57842", 0x05C0 }, /* HEBREW PUNCTUATION PASEQ */
+ { "afii57929", 0x02BC }, /* MODIFIER LETTER APOSTROPHE */
+ { "afii61248", 0x2105 }, /* CARE OF */
+ { "afii61289", 0x2113 }, /* SCRIPT SMALL L */
+ { "afii61352", 0x2116 }, /* NUMERO SIGN */
+ { "afii61573", 0x202C }, /* POP DIRECTIONAL FORMATTING */
+ { "afii61574", 0x202D }, /* LEFT-TO-RIGHT OVERRIDE */
+ { "afii61575", 0x202E }, /* RIGHT-TO-LEFT OVERRIDE */
+ { "afii61664", 0x200C }, /* ZERO WIDTH NON-JOINER */
+ { "afii63167", 0x066D }, /* ARABIC FIVE POINTED STAR */
+ { "afii64937", 0x02BD }, /* MODIFIER LETTER REVERSED COMMA */
+ { "agrave", 0x00E0 }, /* LATIN SMALL LETTER A WITH GRAVE */
+ { "aleph", 0x2135 }, /* ALEF SYMBOL */
+ { "alpha", 0x03B1 }, /* GREEK SMALL LETTER ALPHA */
+ { "alphatonos", 0x03AC }, /* GREEK SMALL LETTER ALPHA WITH TONOS */
+ { "amacron", 0x0101 }, /* LATIN SMALL LETTER A WITH MACRON */
+ { "ampersand", 0x0026 }, /* AMPERSAND */
+ { "ampersandsmall", 0xF726 }, /* SMALL CAPITAL AMPERSAND */
+ { "angle", 0x2220 }, /* ANGLE */
+ { "angleleft", 0x2329 }, /* LEFT-POINTING ANGLE BRACKET */
+ { "angleright", 0x232A }, /* RIGHT-POINTING ANGLE BRACKET */
+ { "anoteleia", 0x0387 }, /* GREEK ANO TELEIA */
+ { "aogonek", 0x0105 }, /* LATIN SMALL LETTER A WITH OGONEK */
+ { "approxequal", 0x2248 }, /* ALMOST EQUAL TO */
+ { "aring", 0x00E5 }, /* LATIN SMALL LETTER A WITH RING ABOVE */
+ { "aringacute", 0x01FB }, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE */
+ { "arrowboth", 0x2194 }, /* LEFT RIGHT ARROW */
+ { "arrowdblboth", 0x21D4 }, /* LEFT RIGHT DOUBLE ARROW */
+ { "arrowdbldown", 0x21D3 }, /* DOWNWARDS DOUBLE ARROW */
+ { "arrowdblleft", 0x21D0 }, /* LEFTWARDS DOUBLE ARROW */
+ { "arrowdblright", 0x21D2 }, /* RIGHTWARDS DOUBLE ARROW */
+ { "arrowdblup", 0x21D1 }, /* UPWARDS DOUBLE ARROW */
+ { "arrowdown", 0x2193 }, /* DOWNWARDS ARROW */
+ { "arrowhorizex", 0xF8E7 }, /* HORIZONTAL ARROW EXTENDER */
+ { "arrowleft", 0x2190 }, /* LEFTWARDS ARROW */
+ { "arrowright", 0x2192 }, /* RIGHTWARDS ARROW */
+ { "arrowup", 0x2191 }, /* UPWARDS ARROW */
+ { "arrowupdn", 0x2195 }, /* UP DOWN ARROW */
+ { "arrowupdnbse", 0x21A8 }, /* UP DOWN ARROW WITH BASE */
+ { "arrowvertex", 0xF8E6 }, /* VERTICAL ARROW EXTENDER */
+ { "asciicircum", 0x005E }, /* CIRCUMFLEX ACCENT */
+ { "asciitilde", 0x007E }, /* TILDE */
+ { "asterisk", 0x002A }, /* ASTERISK */
+ { "asteriskmath", 0x2217 }, /* ASTERISK OPERATOR */
+ { "asuperior", 0xF6E9 }, /* SUPERSCRIPT LATIN SMALL LETTER A */
+ { "at", 0x0040 }, /* COMMERCIAL AT */
+ { "atilde", 0x00E3 }, /* LATIN SMALL LETTER A WITH TILDE */
+ { "b", 0x0062 }, /* LATIN SMALL LETTER B */
+ { "backslash", 0x005C }, /* REVERSE SOLIDUS */
+ { "bar", 0x007C }, /* VERTICAL LINE */
+ { "beta", 0x03B2 }, /* GREEK SMALL LETTER BETA */
+ { "block", 0x2588 }, /* FULL BLOCK */
+ { "braceex", 0xF8F4 }, /* CURLY BRACKET EXTENDER */
+ { "braceleft", 0x007B }, /* LEFT CURLY BRACKET */
+ { "braceleftbt", 0xF8F3 }, /* LEFT CURLY BRACKET BOTTOM */
+ { "braceleftmid", 0xF8F2 }, /* LEFT CURLY BRACKET MID */
+ { "bracelefttp", 0xF8F1 }, /* LEFT CURLY BRACKET TOP */
+ { "braceright", 0x007D }, /* RIGHT CURLY BRACKET */
+ { "bracerightbt", 0xF8FE }, /* RIGHT CURLY BRACKET BOTTOM */
+ { "bracerightmid", 0xF8FD }, /* RIGHT CURLY BRACKET MID */
+ { "bracerighttp", 0xF8FC }, /* RIGHT CURLY BRACKET TOP */
+ { "bracketleft", 0x005B }, /* LEFT SQUARE BRACKET */
+ { "bracketleftbt", 0xF8F0 }, /* LEFT SQUARE BRACKET BOTTOM */
+ { "bracketleftex", 0xF8EF }, /* LEFT SQUARE BRACKET EXTENDER */
+ { "bracketlefttp", 0xF8EE }, /* LEFT SQUARE BRACKET TOP */
+ { "bracketright", 0x005D }, /* RIGHT SQUARE BRACKET */
+ { "bracketrightbt", 0xF8FB }, /* RIGHT SQUARE BRACKET BOTTOM */
+ { "bracketrightex", 0xF8FA }, /* RIGHT SQUARE BRACKET EXTENDER */
+ { "bracketrighttp", 0xF8F9 }, /* RIGHT SQUARE BRACKET TOP */
+ { "breve", 0x02D8 }, /* BREVE */
+ { "brokenbar", 0x00A6 }, /* BROKEN BAR */
+ { "bsuperior", 0xF6EA }, /* SUPERSCRIPT LATIN SMALL LETTER B */
+ { "bullet", 0x2022 }, /* BULLET */
+ { "c", 0x0063 }, /* LATIN SMALL LETTER C */
+ { "cacute", 0x0107 }, /* LATIN SMALL LETTER C WITH ACUTE */
+ { "caron", 0x02C7 }, /* CARON */
+ { "carriagereturn", 0x21B5 }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS */
+ { "ccaron", 0x010D }, /* LATIN SMALL LETTER C WITH CARON */
+ { "ccedilla", 0x00E7 }, /* LATIN SMALL LETTER C WITH CEDILLA */
+ { "ccircumflex", 0x0109 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */
+ { "cdotaccent", 0x010B }, /* LATIN SMALL LETTER C WITH DOT ABOVE */
+ { "cedilla", 0x00B8 }, /* CEDILLA */
+ { "cent", 0x00A2 }, /* CENT SIGN */
+ { "centinferior", 0xF6DF }, /* SUBSCRIPT CENT SIGN */
+ { "centoldstyle", 0xF7A2 }, /* OLDSTYLE CENT SIGN */
+ { "centsuperior", 0xF6E0 }, /* SUPERSCRIPT CENT SIGN */
+ { "chi", 0x03C7 }, /* GREEK SMALL LETTER CHI */
+ { "circle", 0x25CB }, /* WHITE CIRCLE */
+ { "circlemultiply", 0x2297 }, /* CIRCLED TIMES */
+ { "circleplus", 0x2295 }, /* CIRCLED PLUS */
+/* { "circumflex", 0x02C6 }, /\* MODIFIER LETTER CIRCUMFLEX ACCENT *\/ */
+ { "circumflex", 0x005E }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ { "club", 0x2663 }, /* BLACK CLUB SUIT */
+ { "colon", 0x003A }, /* COLON */
+ { "colonmonetary", 0x20A1 }, /* COLON SIGN */
+ { "comma", 0x002C }, /* COMMA */
+ { "commaaccent", 0xF6C3 }, /* COMMA BELOW */
+ { "commainferior", 0xF6E1 }, /* SUBSCRIPT COMMA */
+ { "commasuperior", 0xF6E2 }, /* SUPERSCRIPT COMMA */
+ { "congruent", 0x2245 }, /* APPROXIMATELY EQUAL TO */
+ { "copyright", 0x00A9 }, /* COPYRIGHT SIGN */
+ { "copyrightsans", 0xF8E9 }, /* COPYRIGHT SIGN SANS SERIF */
+ { "copyrightserif", 0xF6D9 }, /* COPYRIGHT SIGN SERIF */
+ { "currency", 0x00A4 }, /* CURRENCY SIGN */
+ { "cyrBreve", 0xF6D1 }, /* CAPITAL CYRILLIC BREVE */
+ { "cyrFlex", 0xF6D2 }, /* CAPITAL CYRILLIC CIRCUMFLEX */
+ { "cyrbreve", 0xF6D4 }, /* CYRILLIC BREVE */
+ { "cyrflex", 0xF6D5 }, /* CYRILLIC CIRCUMFLEX */
+ { "d", 0x0064 }, /* LATIN SMALL LETTER D */
+ { "dagger", 0x2020 }, /* DAGGER */
+ { "daggerdbl", 0x2021 }, /* DOUBLE DAGGER */
+ { "dblGrave", 0xF6D3 }, /* CAPITAL DOUBLE GRAVE ACCENT */
+ { "dblgrave", 0xF6D6 }, /* DOUBLE GRAVE ACCENT */
+ { "dcaron", 0x010F }, /* LATIN SMALL LETTER D WITH CARON */
+ { "dcroat", 0x0111 }, /* LATIN SMALL LETTER D WITH STROKE */
+ { "degree", 0x00B0 }, /* DEGREE SIGN */
+ { "delta", 0x03B4 }, /* GREEK SMALL LETTER DELTA */
+ { "diamond", 0x2666 }, /* BLACK DIAMOND SUIT */
+ { "dieresis", 0x00A8 }, /* DIAERESIS */
+ { "dieresisacute", 0xF6D7 }, /* DIAERESIS ACUTE ACCENT */
+ { "dieresisgrave", 0xF6D8 }, /* DIAERESIS GRAVE ACCENT */
+ { "dieresistonos", 0x0385 }, /* GREEK DIALYTIKA TONOS */
+ { "divide", 0x00F7 }, /* DIVISION SIGN */
+ { "dkshade", 0x2593 }, /* DARK SHADE */
+ { "dnblock", 0x2584 }, /* LOWER HALF BLOCK */
+ { "dollar", 0x0024 }, /* DOLLAR SIGN */
+ { "dollarinferior", 0xF6E3 }, /* SUBSCRIPT DOLLAR SIGN */
+ { "dollaroldstyle", 0xF724 }, /* OLDSTYLE DOLLAR SIGN */
+ { "dollarsuperior", 0xF6E4 }, /* SUPERSCRIPT DOLLAR SIGN */
+ { "dong", 0x20AB }, /* DONG SIGN */
+ { "dotaccent", 0x02D9 }, /* DOT ABOVE */
+ { "dotbelowcomb", 0x0323 }, /* COMBINING DOT BELOW */
+ { "dotlessi", 0x0131 }, /* LATIN SMALL LETTER DOTLESS I */
+ { "dotlessj", 0xF6BE }, /* LATIN SMALL LETTER DOTLESS J */
+ { "dotmath", 0x22C5 }, /* DOT OPERATOR */
+ { "dsuperior", 0xF6EB }, /* SUPERSCRIPT LATIN SMALL LETTER D */
+ { "e", 0x0065 }, /* LATIN SMALL LETTER E */
+ { "eacute", 0x00E9 }, /* LATIN SMALL LETTER E WITH ACUTE */
+ { "ebreve", 0x0115 }, /* LATIN SMALL LETTER E WITH BREVE */
+ { "ecaron", 0x011B }, /* LATIN SMALL LETTER E WITH CARON */
+ { "ecircumflex", 0x00EA }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ { "edieresis", 0x00EB }, /* LATIN SMALL LETTER E WITH DIAERESIS */
+ { "edotaccent", 0x0117 }, /* LATIN SMALL LETTER E WITH DOT ABOVE */
+ { "egrave", 0x00E8 }, /* LATIN SMALL LETTER E WITH GRAVE */
+ { "eight", 0x0038 }, /* DIGIT EIGHT */
+ { "eightinferior", 0x2088 }, /* SUBSCRIPT EIGHT */
+ { "eightoldstyle", 0xF738 }, /* OLDSTYLE DIGIT EIGHT */
+ { "eightsuperior", 0x2078 }, /* SUPERSCRIPT EIGHT */
+ { "element", 0x2208 }, /* ELEMENT OF */
+ { "ellipsis", 0x2026 }, /* HORIZONTAL ELLIPSIS */
+ { "emacron", 0x0113 }, /* LATIN SMALL LETTER E WITH MACRON */
+ { "emdash", 0x2014 }, /* EM DASH */
+ { "emptyset", 0x2205 }, /* EMPTY SET */
+ { "endash", 0x2013 }, /* EN DASH */
+ { "eng", 0x014B }, /* LATIN SMALL LETTER ENG */
+ { "eogonek", 0x0119 }, /* LATIN SMALL LETTER E WITH OGONEK */
+ { "epsilon", 0x03B5 }, /* GREEK SMALL LETTER EPSILON */
+ { "epsilontonos", 0x03AD }, /* GREEK SMALL LETTER EPSILON WITH TONOS */
+ { "equal", 0x003D }, /* EQUALS SIGN */
+ { "equivalence", 0x2261 }, /* IDENTICAL TO */
+ { "estimated", 0x212E }, /* ESTIMATED SYMBOL */
+ { "esuperior", 0xF6EC }, /* SUPERSCRIPT LATIN SMALL LETTER E */
+ { "eta", 0x03B7 }, /* GREEK SMALL LETTER ETA */
+ { "etatonos", 0x03AE }, /* GREEK SMALL LETTER ETA WITH TONOS */
+ { "eth", 0x00F0 }, /* LATIN SMALL LETTER ETH */
+ { "exclam", 0x0021 }, /* EXCLAMATION MARK */
+ { "exclamdbl", 0x203C }, /* DOUBLE EXCLAMATION MARK */
+ { "exclamdown", 0x00A1 }, /* INVERTED EXCLAMATION MARK */
+ { "exclamdownsmall", 0xF7A1 }, /* SMALL CAPITAL INVERTED EXCLAMATION MARK */
+ { "exclamsmall", 0xF721 }, /* SMALL CAPITAL EXCLAMATION MARK */
+ { "existential", 0x2203 }, /* THERE EXISTS */
+ { "f", 0x0066 }, /* LATIN SMALL LETTER F */
+ { "female", 0x2640 }, /* FEMALE SIGN */
+ { "ff", 0xFB00 }, /* LATIN SMALL LIGATURE FF */
+ { "ffi", 0xFB03 }, /* LATIN SMALL LIGATURE FFI */
+ { "ffl", 0xFB04 }, /* LATIN SMALL LIGATURE FFL */
+ { "fi", 0xFB01 }, /* LATIN SMALL LIGATURE FI */
+ { "figuredash", 0x2012 }, /* FIGURE DASH */
+ { "filledbox", 0x25A0 }, /* BLACK SQUARE */
+ { "filledrect", 0x25AC }, /* BLACK RECTANGLE */
+ { "five", 0x0035 }, /* DIGIT FIVE */
+ { "fiveeighths", 0x215D }, /* VULGAR FRACTION FIVE EIGHTHS */
+ { "fiveinferior", 0x2085 }, /* SUBSCRIPT FIVE */
+ { "fiveoldstyle", 0xF735 }, /* OLDSTYLE DIGIT FIVE */
+ { "fivesuperior", 0x2075 }, /* SUPERSCRIPT FIVE */
+ { "fl", 0xFB02 }, /* LATIN SMALL LIGATURE FL */
+ { "florin", 0x0192 }, /* LATIN SMALL LETTER F WITH HOOK */
+ { "four", 0x0034 }, /* DIGIT FOUR */
+ { "fourinferior", 0x2084 }, /* SUBSCRIPT FOUR */
+ { "fouroldstyle", 0xF734 }, /* OLDSTYLE DIGIT FOUR */
+ { "foursuperior", 0x2074 }, /* SUPERSCRIPT FOUR */
+ { "fraction", 0x2044 }, /* FRACTION SLASH */
+#if 0
+ { "fraction" DUP2, 0x2215 }, /* DIVISION SLASH;Duplicate */
+#endif /* 0 */
+ { "franc", 0x20A3 }, /* FRENCH FRANC SIGN */
+ { "ft", 0xFB05 }, /* LATIN SMALL LIGATURE FT */
+ { "g", 0x0067 }, /* LATIN SMALL LETTER G */
+ { "gamma", 0x03B3 }, /* GREEK SMALL LETTER GAMMA */
+ { "gbreve", 0x011F }, /* LATIN SMALL LETTER G WITH BREVE */
+ { "gcaron", 0x01E7 }, /* LATIN SMALL LETTER G WITH CARON */
+ { "gcircumflex", 0x011D }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */
+ { "gcommaaccent", 0x0123 }, /* LATIN SMALL LETTER G WITH CEDILLA */
+ { "gdotaccent", 0x0121 }, /* LATIN SMALL LETTER G WITH DOT ABOVE */
+ { "germandbls", 0x00DF }, /* LATIN SMALL LETTER SHARP S */
+ { "gradient", 0x2207 }, /* NABLA */
+ { "grave", 0x0060 }, /* GRAVE ACCENT */
+ { "gravecomb", 0x0300 }, /* COMBINING GRAVE ACCENT */
+ { "greater", 0x003E }, /* GREATER-THAN SIGN */
+ { "greaterequal", 0x2265 }, /* GREATER-THAN OR EQUAL TO */
+ { "guillemotleft", 0x00AB }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ { "guillemotright", 0x00BB }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ { "guilsinglleft", 0x2039 }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ { "guilsinglright", 0x203A }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ { "h", 0x0068 }, /* LATIN SMALL LETTER H */
+ { "hbar", 0x0127 }, /* LATIN SMALL LETTER H WITH STROKE */
+ { "hcircumflex", 0x0125 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */
+ { "heart", 0x2665 }, /* BLACK HEART SUIT */
+ { "hookabovecomb", 0x0309 }, /* COMBINING HOOK ABOVE */
+ { "house", 0x2302 }, /* HOUSE */
+ { "hungarumlaut", 0x02DD }, /* DOUBLE ACUTE ACCENT */
+ { "hyphen", 0x002D }, /* HYPHEN-MINUS */
+#if 0
+ { "hyphen" DUP2, 0x00AD }, /* SOFT HYPHEN;Duplicate */
+#endif /* 0 */
+ { "hypheninferior", 0xF6E5 }, /* SUBSCRIPT HYPHEN-MINUS */
+ { "hyphensuperior", 0xF6E6 }, /* SUPERSCRIPT HYPHEN-MINUS */
+ { "i", 0x0069 }, /* LATIN SMALL LETTER I */
+ { "iacute", 0x00ED }, /* LATIN SMALL LETTER I WITH ACUTE */
+ { "ibreve", 0x012D }, /* LATIN SMALL LETTER I WITH BREVE */
+ { "icircumflex", 0x00EE }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ { "idieresis", 0x00EF }, /* LATIN SMALL LETTER I WITH DIAERESIS */
+ { "igrave", 0x00EC }, /* LATIN SMALL LETTER I WITH GRAVE */
+ { "ij", 0x0133 }, /* LATIN SMALL LIGATURE IJ */
+ { "imacron", 0x012B }, /* LATIN SMALL LETTER I WITH MACRON */
+ { "infinity", 0x221E }, /* INFINITY */
+ { "integral", 0x222B }, /* INTEGRAL */
+ { "integralbt", 0x2321 }, /* BOTTOM HALF INTEGRAL */
+ { "integralex", 0xF8F5 }, /* INTEGRAL EXTENDER */
+ { "integraltp", 0x2320 }, /* TOP HALF INTEGRAL */
+ { "intersection", 0x2229 }, /* INTERSECTION */
+ { "invbullet", 0x25D8 }, /* INVERSE BULLET */
+ { "invcircle", 0x25D9 }, /* INVERSE WHITE CIRCLE */
+ { "invsmileface", 0x263B }, /* BLACK SMILING FACE */
+ { "iogonek", 0x012F }, /* LATIN SMALL LETTER I WITH OGONEK */
+ { "iota", 0x03B9 }, /* GREEK SMALL LETTER IOTA */
+ { "iotadieresis", 0x03CA }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */
+ { "iotadieresistonos", 0x0390 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+ { "iotatonos", 0x03AF }, /* GREEK SMALL LETTER IOTA WITH TONOS */
+ { "isuperior", 0xF6ED }, /* SUPERSCRIPT LATIN SMALL LETTER I */
+ { "itilde", 0x0129 }, /* LATIN SMALL LETTER I WITH TILDE */
+ { "j", 0x006A }, /* LATIN SMALL LETTER J */
+ { "jcircumflex", 0x0135 }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */
+ { "k", 0x006B }, /* LATIN SMALL LETTER K */
+ { "kappa", 0x03BA }, /* GREEK SMALL LETTER KAPPA */
+ { "kcommaaccent", 0x0137 }, /* LATIN SMALL LETTER K WITH CEDILLA */
+ { "kgreenlandic", 0x0138 }, /* LATIN SMALL LETTER KRA */
+ { "l", 0x006C }, /* LATIN SMALL LETTER L */
+ { "lacute", 0x013A }, /* LATIN SMALL LETTER L WITH ACUTE */
+ { "lambda", 0x03BB }, /* GREEK SMALL LETTER LAMDA */
+ { "lcaron", 0x013E }, /* LATIN SMALL LETTER L WITH CARON */
+ { "lcommaaccent", 0x013C }, /* LATIN SMALL LETTER L WITH CEDILLA */
+ { "ldot", 0x0140 }, /* LATIN SMALL LETTER L WITH MIDDLE DOT */
+ { "less", 0x003C }, /* LESS-THAN SIGN */
+ { "lessequal", 0x2264 }, /* LESS-THAN OR EQUAL TO */
+ { "lfblock", 0x258C }, /* LEFT HALF BLOCK */
+ { "lira", 0x20A4 }, /* LIRA SIGN */
+ { "ll", 0xF6C0 }, /* LATIN SMALL LETTER LL */
+ { "logicaland", 0x2227 }, /* LOGICAL AND */
+ { "logicalnot", 0x00AC }, /* NOT SIGN */
+ { "logicalor", 0x2228 }, /* LOGICAL OR */
+ { "longs", 0x017F }, /* LATIN SMALL LETTER LONG S */
+ { "lozenge", 0x25CA }, /* LOZENGE */
+ { "lslash", 0x0142 }, /* LATIN SMALL LETTER L WITH STROKE */
+ { "lsuperior", 0xF6EE }, /* SUPERSCRIPT LATIN SMALL LETTER L */
+ { "ltshade", 0x2591 }, /* LIGHT SHADE */
+ { "m", 0x006D }, /* LATIN SMALL LETTER M */
+ { "macron", 0x00AF }, /* MACRON */
+#if 0
+ { "macron" DUP2, 0x02C9 }, /* MODIFIER LETTER MACRON;Duplicate */
+#endif /* 0 */
+ { "male", 0x2642 }, /* MALE SIGN */
+ { "minus", 0x2212 }, /* MINUS SIGN */
+ { "minute", 0x2032 }, /* PRIME */
+ { "msuperior", 0xF6EF }, /* SUPERSCRIPT LATIN SMALL LETTER M */
+ { "mu", 0x00B5 }, /* MICRO SIGN */
+#if 0
+ { "mu" DUP2, 0x03BC }, /* GREEK SMALL LETTER MU;Duplicate */
+#endif /* 0 */
+ { "multiply", 0x00D7 }, /* MULTIPLICATION SIGN */
+ { "musicalnote", 0x266A }, /* EIGHTH NOTE */
+ { "musicalnotedbl", 0x266B }, /* BEAMED EIGHTH NOTES */
+ { "n", 0x006E }, /* LATIN SMALL LETTER N */
+ { "nacute", 0x0144 }, /* LATIN SMALL LETTER N WITH ACUTE */
+ { "napostrophe", 0x0149 }, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
+ { "ncaron", 0x0148 }, /* LATIN SMALL LETTER N WITH CARON */
+ { "ncommaaccent", 0x0146 }, /* LATIN SMALL LETTER N WITH CEDILLA */
+ { "nine", 0x0039 }, /* DIGIT NINE */
+ { "nineinferior", 0x2089 }, /* SUBSCRIPT NINE */
+ { "nineoldstyle", 0xF739 }, /* OLDSTYLE DIGIT NINE */
+ { "ninesuperior", 0x2079 }, /* SUPERSCRIPT NINE */
+ { "notelement", 0x2209 }, /* NOT AN ELEMENT OF */
+ { "notequal", 0x2260 }, /* NOT EQUAL TO */
+ { "notsubset", 0x2284 }, /* NOT A SUBSET OF */
+ { "nsuperior", 0x207F }, /* SUPERSCRIPT LATIN SMALL LETTER N */
+ { "ntilde", 0x00F1 }, /* LATIN SMALL LETTER N WITH TILDE */
+ { "nu", 0x03BD }, /* GREEK SMALL LETTER NU */
+ { "numbersign", 0x0023 }, /* NUMBER SIGN */
+ { "o", 0x006F }, /* LATIN SMALL LETTER O */
+ { "oacute", 0x00F3 }, /* LATIN SMALL LETTER O WITH ACUTE */
+ { "obreve", 0x014F }, /* LATIN SMALL LETTER O WITH BREVE */
+ { "ocircumflex", 0x00F4 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ { "odieresis", 0x00F6 }, /* LATIN SMALL LETTER O WITH DIAERESIS */
+ { "oe", 0x0153 }, /* LATIN SMALL LIGATURE OE */
+ { "ogonek", 0x02DB }, /* OGONEK */
+ { "ograve", 0x00F2 }, /* LATIN SMALL LETTER O WITH GRAVE */
+ { "ohorn", 0x01A1 }, /* LATIN SMALL LETTER O WITH HORN */
+ { "ohungarumlaut", 0x0151 }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */
+ { "omacron", 0x014D }, /* LATIN SMALL LETTER O WITH MACRON */
+ { "omega", 0x03C9 }, /* GREEK SMALL LETTER OMEGA */
+ { "omega1", 0x03D6 }, /* GREEK PI SYMBOL */
+ { "omegatonos", 0x03CE }, /* GREEK SMALL LETTER OMEGA WITH TONOS */
+ { "omicron", 0x03BF }, /* GREEK SMALL LETTER OMICRON */
+ { "omicrontonos", 0x03CC }, /* GREEK SMALL LETTER OMICRON WITH TONOS */
+ { "one", 0x0031 }, /* DIGIT ONE */
+ { "onedotenleader", 0x2024 }, /* ONE DOT LEADER */
+ { "oneeighth", 0x215B }, /* VULGAR FRACTION ONE EIGHTH */
+ { "onefitted", 0xF6DC }, /* PROPORTIONAL DIGIT ONE */
+ { "onehalf", 0x00BD }, /* VULGAR FRACTION ONE HALF */
+ { "oneinferior", 0x2081 }, /* SUBSCRIPT ONE */
+ { "oneoldstyle", 0xF731 }, /* OLDSTYLE DIGIT ONE */
+ { "onequarter", 0x00BC }, /* VULGAR FRACTION ONE QUARTER */
+ { "onesuperior", 0x00B9 }, /* SUPERSCRIPT ONE */
+ { "onethird", 0x2153 }, /* VULGAR FRACTION ONE THIRD */
+ { "openbullet", 0x25E6 }, /* WHITE BULLET */
+ { "ordfeminine", 0x00AA }, /* FEMININE ORDINAL INDICATOR */
+ { "ordmasculine", 0x00BA }, /* MASCULINE ORDINAL INDICATOR */
+ { "orthogonal", 0x221F }, /* RIGHT ANGLE */
+ { "oslash", 0x00F8 }, /* LATIN SMALL LETTER O WITH STROKE */
+ { "oslashacute", 0x01FF }, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE */
+ { "osuperior", 0xF6F0 }, /* SUPERSCRIPT LATIN SMALL LETTER O */
+ { "otilde", 0x00F5 }, /* LATIN SMALL LETTER O WITH TILDE */
+ { "p", 0x0070 }, /* LATIN SMALL LETTER P */
+ { "paragraph", 0x00B6 }, /* PILCROW SIGN */
+ { "parenleft", 0x0028 }, /* LEFT PARENTHESIS */
+ { "parenleftbt", 0xF8ED }, /* LEFT PAREN BOTTOM */
+ { "parenleftex", 0xF8EC }, /* LEFT PAREN EXTENDER */
+ { "parenleftinferior", 0x208D }, /* SUBSCRIPT LEFT PARENTHESIS */
+ { "parenleftsuperior", 0x207D }, /* SUPERSCRIPT LEFT PARENTHESIS */
+ { "parenlefttp", 0xF8EB }, /* LEFT PAREN TOP */
+ { "parenright", 0x0029 }, /* RIGHT PARENTHESIS */
+ { "parenrightbt", 0xF8F8 }, /* RIGHT PAREN BOTTOM */
+ { "parenrightex", 0xF8F7 }, /* RIGHT PAREN EXTENDER */
+ { "parenrightinferior", 0x208E }, /* SUBSCRIPT RIGHT PARENTHESIS */
+ { "parenrightsuperior", 0x207E }, /* SUPERSCRIPT RIGHT PARENTHESIS */
+ { "parenrighttp", 0xF8F6 }, /* RIGHT PAREN TOP */
+ { "partialdiff", 0x2202 }, /* PARTIAL DIFFERENTIAL */
+ { "percent", 0x0025 }, /* PERCENT SIGN */
+ { "period", 0x002E }, /* FULL STOP */
+ { "periodcentered", 0x00B7 }, /* MIDDLE DOT */
+#if 0
+ { "periodcentered" DUP2, 0x2219 }, /* BULLET OPERATOR;Duplicate */
+#endif /* 0 */
+ { "periodinferior", 0xF6E7 }, /* SUBSCRIPT FULL STOP */
+ { "periodsuperior", 0xF6E8 }, /* SUPERSCRIPT FULL STOP */
+ { "perpendicular", 0x22A5 }, /* UP TACK */
+ { "perthousand", 0x2030 }, /* PER MILLE SIGN */
+ { "peseta", 0x20A7 }, /* PESETA SIGN */
+ { "phi", 0x03C6 }, /* GREEK SMALL LETTER PHI */
+ { "phi1", 0x03D5 }, /* GREEK PHI SYMBOL */
+ { "pi", 0x03C0 }, /* GREEK SMALL LETTER PI */
+ { "plus", 0x002B }, /* PLUS SIGN */
+ { "plusminus", 0x00B1 }, /* PLUS-MINUS SIGN */
+ { "prescription", 0x211E }, /* PRESCRIPTION TAKE */
+ { "product", 0x220F }, /* N-ARY PRODUCT */
+ { "propersubset", 0x2282 }, /* SUBSET OF */
+ { "propersuperset", 0x2283 }, /* SUPERSET OF */
+ { "proportional", 0x221D }, /* PROPORTIONAL TO */
+ { "psi", 0x03C8 }, /* GREEK SMALL LETTER PSI */
+ { "q", 0x0071 }, /* LATIN SMALL LETTER Q */
+ { "question", 0x003F }, /* QUESTION MARK */
+ { "questiondown", 0x00BF }, /* INVERTED QUESTION MARK */
+ { "questiondownsmall", 0xF7BF }, /* SMALL CAPITAL INVERTED QUESTION MARK */
+ { "questionsmall", 0xF73F }, /* SMALL CAPITAL QUESTION MARK */
+ { "quotedbl", 0x0022 }, /* QUOTATION MARK */
+ { "quotedblbase", 0x201E }, /* DOUBLE LOW-9 QUOTATION MARK */
+ { "quotedblleft", 0x201C }, /* LEFT DOUBLE QUOTATION MARK */
+ { "quotedblright", 0x201D }, /* RIGHT DOUBLE QUOTATION MARK */
+ { "quoteleft", 0x2018 }, /* LEFT SINGLE QUOTATION MARK */
+ { "quotereversed", 0x201B }, /* SINGLE HIGH-REVERSED-9 QUOTATION MARK */
+ { "quoteright", 0x2019 }, /* RIGHT SINGLE QUOTATION MARK */
+ { "quotesinglbase", 0x201A }, /* SINGLE LOW-9 QUOTATION MARK */
+ { "quotesingle", 0x0027 }, /* APOSTROPHE */
+ { "r", 0x0072 }, /* LATIN SMALL LETTER R */
+ { "racute", 0x0155 }, /* LATIN SMALL LETTER R WITH ACUTE */
+ { "radical", 0x221A }, /* SQUARE ROOT */
+ { "radicalex", 0xF8E5 }, /* RADICAL EXTENDER */
+ { "rcaron", 0x0159 }, /* LATIN SMALL LETTER R WITH CARON */
+ { "rcommaaccent", 0x0157 }, /* LATIN SMALL LETTER R WITH CEDILLA */
+ { "reflexsubset", 0x2286 }, /* SUBSET OF OR EQUAL TO */
+ { "reflexsuperset", 0x2287 }, /* SUPERSET OF OR EQUAL TO */
+ { "registered", 0x00AE }, /* REGISTERED SIGN */
+ { "registersans", 0xF8E8 }, /* REGISTERED SIGN SANS SERIF */
+ { "registerserif", 0xF6DA }, /* REGISTERED SIGN SERIF */
+ { "revlogicalnot", 0x2310 }, /* REVERSED NOT SIGN */
+ { "rho", 0x03C1 }, /* GREEK SMALL LETTER RHO */
+ { "ring", 0x02DA }, /* RING ABOVE */
+ { "rsuperior", 0xF6F1 }, /* SUPERSCRIPT LATIN SMALL LETTER R */
+ { "rtblock", 0x2590 }, /* RIGHT HALF BLOCK */
+ { "rupiah", 0xF6DD }, /* RUPIAH SIGN */
+ { "s", 0x0073 }, /* LATIN SMALL LETTER S */
+ { "sacute", 0x015B }, /* LATIN SMALL LETTER S WITH ACUTE */
+ { "scaron", 0x0161 }, /* LATIN SMALL LETTER S WITH CARON */
+ { "scedilla", 0x015F }, /* LATIN SMALL LETTER S WITH CEDILLA */
+#if 0
+ { "scedilla" DUP2, 0xF6C2 }, /* LATIN SMALL LETTER S WITH CEDILLA;Duplicate */
+#endif /* 0 */
+ { "scircumflex", 0x015D }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */
+ { "scommaaccent", 0x0219 }, /* LATIN SMALL LETTER S WITH COMMA BELOW */
+ { "second", 0x2033 }, /* DOUBLE PRIME */
+ { "section", 0x00A7 }, /* SECTION SIGN */
+ { "semicolon", 0x003B }, /* SEMICOLON */
+ { "seven", 0x0037 }, /* DIGIT SEVEN */
+ { "seveneighths", 0x215E }, /* VULGAR FRACTION SEVEN EIGHTHS */
+ { "seveninferior", 0x2087 }, /* SUBSCRIPT SEVEN */
+ { "sevenoldstyle", 0xF737 }, /* OLDSTYLE DIGIT SEVEN */
+ { "sevensuperior", 0x2077 }, /* SUPERSCRIPT SEVEN */
+ { "shade", 0x2592 }, /* MEDIUM SHADE */
+ { "sigma", 0x03C3 }, /* GREEK SMALL LETTER SIGMA */
+ { "sigma1", 0x03C2 }, /* GREEK SMALL LETTER FINAL SIGMA */
+ { "similar", 0x223C }, /* TILDE OPERATOR */
+ { "six", 0x0036 }, /* DIGIT SIX */
+ { "sixinferior", 0x2086 }, /* SUBSCRIPT SIX */
+ { "sixoldstyle", 0xF736 }, /* OLDSTYLE DIGIT SIX */
+ { "sixsuperior", 0x2076 }, /* SUPERSCRIPT SIX */
+ { "slash", 0x002F }, /* SOLIDUS */
+ { "smileface", 0x263A }, /* WHITE SMILING FACE */
+ { "space", 0x0020 }, /* SPACE */
+#if 0
+ { "space" DUP2, 0x00A0 }, /* NO-BREAK SPACE;Duplicate */
+#endif /* 0 */
+ { "spade", 0x2660 }, /* BLACK SPADE SUIT */
+ { "ssuperior", 0xF6F2 }, /* SUPERSCRIPT LATIN SMALL LETTER S */
+ { "st", 0xFB06 }, /* LATIN SMALL LIGATURE ST */
+ { "sterling", 0x00A3 }, /* POUND SIGN */
+ { "suchthat", 0x220B }, /* CONTAINS AS MEMBER */
+ { "summation", 0x2211 }, /* N-ARY SUMMATION */
+ { "summationtext", 0x2211 }, /* N-ARY SUMMATION - apparently this is the name used in cmex? */
+ { "sun", 0x263C }, /* WHITE SUN WITH RAYS */
+ { "t", 0x0074 }, /* LATIN SMALL LETTER T */
+ { "tau", 0x03C4 }, /* GREEK SMALL LETTER TAU */
+ { "tbar", 0x0167 }, /* LATIN SMALL LETTER T WITH STROKE */
+ { "tcaron", 0x0165 }, /* LATIN SMALL LETTER T WITH CARON */
+ { "tcommaaccent", 0x0163 }, /* LATIN SMALL LETTER T WITH CEDILLA */
+#if 0
+ { "tcommaaccent" DUP2, 0x021B }, /* LATIN SMALL LETTER T WITH COMMA BELOW;Duplicate */
+#endif /* 0 */
+ { "therefore", 0x2234 }, /* THEREFORE */
+ { "theta", 0x03B8 }, /* GREEK SMALL LETTER THETA */
+ { "theta1", 0x03D1 }, /* GREEK THETA SYMBOL */
+ { "thorn", 0x00FE }, /* LATIN SMALL LETTER THORN */
+ { "three", 0x0033 }, /* DIGIT THREE */
+ { "threeeighths", 0x215C }, /* VULGAR FRACTION THREE EIGHTHS */
+ { "threeinferior", 0x2083 }, /* SUBSCRIPT THREE */
+ { "threeoldstyle", 0xF733 }, /* OLDSTYLE DIGIT THREE */
+ { "threequarters", 0x00BE }, /* VULGAR FRACTION THREE QUARTERS */
+ { "threequartersemdash", 0xF6DE }, /* THREE QUARTERS EM DASH */
+ { "threesuperior", 0x00B3 }, /* SUPERSCRIPT THREE */
+/* { "tilde", 0x02DC }, /\* SMALL TILDE *\/ */
+ { "tilde", 0x007E }, /* ASCII TILDE */
+ { "tildecomb", 0x0303 }, /* COMBINING TILDE */
+ { "tonos", 0x0384 }, /* GREEK TONOS */
+ { "trademark", 0x2122 }, /* TRADE MARK SIGN */
+ { "trademarksans", 0xF8EA }, /* TRADE MARK SIGN SANS SERIF */
+ { "trademarkserif", 0xF6DB }, /* TRADE MARK SIGN SERIF */
+ { "triagdn", 0x25BC }, /* BLACK DOWN-POINTING TRIANGLE */
+ { "triaglf", 0x25C4 }, /* BLACK LEFT-POINTING POINTER */
+ { "triagrt", 0x25BA }, /* BLACK RIGHT-POINTING POINTER */
+ { "triagup", 0x25B2 }, /* BLACK UP-POINTING TRIANGLE */
+ { "tsuperior", 0xF6F3 }, /* SUPERSCRIPT LATIN SMALL LETTER T */
+ { "two", 0x0032 }, /* DIGIT TWO */
+ { "twodotenleader", 0x2025 }, /* TWO DOT LEADER */
+ { "twoinferior", 0x2082 }, /* SUBSCRIPT TWO */
+ { "twooldstyle", 0xF732 }, /* OLDSTYLE DIGIT TWO */
+ { "twosuperior", 0x00B2 }, /* SUPERSCRIPT TWO */
+ { "twothirds", 0x2154 }, /* VULGAR FRACTION TWO THIRDS */
+ { "u", 0x0075 }, /* LATIN SMALL LETTER U */
+ { "uacute", 0x00FA }, /* LATIN SMALL LETTER U WITH ACUTE */
+ { "ubreve", 0x016D }, /* LATIN SMALL LETTER U WITH BREVE */
+ { "ucircumflex", 0x00FB }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ { "udieresis", 0x00FC }, /* LATIN SMALL LETTER U WITH DIAERESIS */
+ { "ugrave", 0x00F9 }, /* LATIN SMALL LETTER U WITH GRAVE */
+ { "uhorn", 0x01B0 }, /* LATIN SMALL LETTER U WITH HORN */
+ { "uhungarumlaut", 0x0171 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */
+ { "umacron", 0x016B }, /* LATIN SMALL LETTER U WITH MACRON */
+ { "underscore", 0x005F }, /* LOW LINE */
+ { "underscoredbl", 0x2017 }, /* DOUBLE LOW LINE */
+ { "union", 0x222A }, /* UNION */
+ { "universal", 0x2200 }, /* FOR ALL */
+ { "uogonek", 0x0173 }, /* LATIN SMALL LETTER U WITH OGONEK */
+ { "upblock", 0x2580 }, /* UPPER HALF BLOCK */
+ { "upsilon", 0x03C5 }, /* GREEK SMALL LETTER UPSILON */
+ { "upsilondieresis", 0x03CB }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
+ { "upsilondieresistonos", 0x03B0 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+ { "upsilontonos", 0x03CD }, /* GREEK SMALL LETTER UPSILON WITH TONOS */
+ { "uring", 0x016F }, /* LATIN SMALL LETTER U WITH RING ABOVE */
+ { "utilde", 0x0169 }, /* LATIN SMALL LETTER U WITH TILDE */
+ { "v", 0x0076 }, /* LATIN SMALL LETTER V */
+ { "w", 0x0077 }, /* LATIN SMALL LETTER W */
+ { "wacute", 0x1E83 }, /* LATIN SMALL LETTER W WITH ACUTE */
+ { "wcircumflex", 0x0175 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */
+ { "wdieresis", 0x1E85 }, /* LATIN SMALL LETTER W WITH DIAERESIS */
+ { "weierstrass", 0x2118 }, /* SCRIPT CAPITAL P */
+ { "wgrave", 0x1E81 }, /* LATIN SMALL LETTER W WITH GRAVE */
+ { "x", 0x0078 }, /* LATIN SMALL LETTER X */
+ { "xi", 0x03BE }, /* GREEK SMALL LETTER XI */
+ { "y", 0x0079 }, /* LATIN SMALL LETTER Y */
+ { "yacute", 0x00FD }, /* LATIN SMALL LETTER Y WITH ACUTE */
+ { "ycircumflex", 0x0177 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */
+ { "ydieresis", 0x00FF }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
+ { "yen", 0x00A5 }, /* YEN SIGN */
+ { "ygrave", 0x1EF3 }, /* LATIN SMALL LETTER Y WITH GRAVE */
+ { "z", 0x007A }, /* LATIN SMALL LETTER Z */
+ { "zacute", 0x017A }, /* LATIN SMALL LETTER Z WITH ACUTE */
+ { "zcaron", 0x017E }, /* LATIN SMALL LETTER Z WITH CARON */
+ { "zdotaccent", 0x017C }, /* LATIN SMALL LETTER Z WITH DOT ABOVE */
+ { "zero", 0x0030 }, /* DIGIT ZERO */
+ { "zeroinferior", 0x2080 }, /* SUBSCRIPT ZERO */
+ { "zerooldstyle", 0xF730 }, /* OLDSTYLE DIGIT ZERO */
+ { "zerosuperior", 0x2070 }, /* SUPERSCRIPT ZERO */
+ { "zeta", 0x03B6 } /* GREEK SMALL LETTER ZETA */
+};
+
+#if 0
+static struct unicode2adobe unicode2adobe_table[] = {
+ { 0, ".notdef" }, /* was: QUESTION MARK; changed to 0 */
+ { 0x0020, "space" }, /* SPACE */
+ { 0x0021, "exclam" }, /* EXCLAMATION MARK */
+ { 0x0022, "quotedbl" }, /* QUOTATION MARK */
+ { 0x0023, "numbersign" }, /* NUMBER SIGN */
+ { 0x0024, "dollar" }, /* DOLLAR SIGN */
+ { 0x0025, "percent" }, /* PERCENT SIGN */
+ { 0x0026, "ampersand" }, /* AMPERSAND */
+ { 0x0027, "quotesingle" }, /* APOSTROPHE */
+ { 0x0028, "parenleft" }, /* LEFT PARENTHESIS */
+ { 0x0029, "parenright" }, /* RIGHT PARENTHESIS */
+ { 0x002A, "asterisk" }, /* ASTERISK */
+ { 0x002B, "plus" }, /* PLUS SIGN */
+ { 0x002C, "comma" }, /* COMMA */
+ { 0x002D, "hyphen" }, /* HYPHEN-MINUS */
+ { 0x002D, "$hyphen" }, /* HYPHEN-MINUS; distinguish Adobe duplicates */
+ { 0x002E, "period" }, /* FULL STOP */
+ { 0x002F, "slash" }, /* SOLIDUS */
+ { 0x0030, "zero" }, /* DIGIT ZERO */
+ { 0x0031, "one" }, /* DIGIT ONE */
+ { 0x0032, "two" }, /* DIGIT TWO */
+ { 0x0033, "three" }, /* DIGIT THREE */
+ { 0x0034, "four" }, /* DIGIT FOUR */
+ { 0x0035, "five" }, /* DIGIT FIVE */
+ { 0x0036, "six" }, /* DIGIT SIX */
+ { 0x0037, "seven" }, /* DIGIT SEVEN */
+ { 0x0038, "eight" }, /* DIGIT EIGHT */
+ { 0x0039, "nine" }, /* DIGIT NINE */
+ { 0x003A, "colon" }, /* COLON */
+ { 0x003B, "semicolon" }, /* SEMICOLON */
+ { 0x003C, "less" }, /* LESS-THAN SIGN */
+ { 0x003D, "equal" }, /* EQUALS SIGN */
+ { 0x003E, "greater" }, /* GREATER-THAN SIGN */
+ { 0x003F, "question" }, /* QUESTION MARK */
+ { 0x0040, "at" }, /* COMMERCIAL AT */
+ { 0x0041, "A" }, /* LATIN CAPITAL LETTER A */
+ { 0x0042, "B" }, /* LATIN CAPITAL LETTER B */
+ { 0x0043, "C" }, /* LATIN CAPITAL LETTER C */
+ { 0x0044, "D" }, /* LATIN CAPITAL LETTER D */
+ { 0x0045, "E" }, /* LATIN CAPITAL LETTER E */
+ { 0x0046, "F" }, /* LATIN CAPITAL LETTER F */
+ { 0x0047, "G" }, /* LATIN CAPITAL LETTER G */
+ { 0x0048, "H" }, /* LATIN CAPITAL LETTER H */
+ { 0x0049, "I" }, /* LATIN CAPITAL LETTER I */
+ { 0x004A, "J" }, /* LATIN CAPITAL LETTER J */
+ { 0x004B, "K" }, /* LATIN CAPITAL LETTER K */
+ { 0x004C, "L" }, /* LATIN CAPITAL LETTER L */
+ { 0x004D, "M" }, /* LATIN CAPITAL LETTER M */
+ { 0x004E, "N" }, /* LATIN CAPITAL LETTER N */
+ { 0x004F, "O" }, /* LATIN CAPITAL LETTER O */
+ { 0x0050, "P" }, /* LATIN CAPITAL LETTER P */
+ { 0x0051, "Q" }, /* LATIN CAPITAL LETTER Q */
+ { 0x0052, "R" }, /* LATIN CAPITAL LETTER R */
+ { 0x0053, "S" }, /* LATIN CAPITAL LETTER S */
+ { 0x0054, "T" }, /* LATIN CAPITAL LETTER T */
+ { 0x0055, "U" }, /* LATIN CAPITAL LETTER U */
+ { 0x0056, "V" }, /* LATIN CAPITAL LETTER V */
+ { 0x0057, "W" }, /* LATIN CAPITAL LETTER W */
+ { 0x0058, "X" }, /* LATIN CAPITAL LETTER X */
+ { 0x0059, "Y" }, /* LATIN CAPITAL LETTER Y */
+ { 0x005A, "Z" }, /* LATIN CAPITAL LETTER Z */
+ { 0x005B, "bracketleft" }, /* LEFT SQUARE BRACKET */
+ { 0x005C, "backslash" }, /* REVERSE SOLIDUS */
+ { 0x005D, "bracketright" }, /* RIGHT SQUARE BRACKET */
+ { 0x005E, "circumflex" }, /* CIRCUMFLEX ACCENT */ /* SU: renamed from asciicircum */
+ { 0x005F, "underscore" }, /* LOW LINE */
+ { 0x0060, "grave" }, /* GRAVE ACCENT */
+ { 0x0061, "a" }, /* LATIN SMALL LETTER A */
+ { 0x0062, "b" }, /* LATIN SMALL LETTER B */
+ { 0x0063, "c" }, /* LATIN SMALL LETTER C */
+ { 0x0064, "d" }, /* LATIN SMALL LETTER D */
+ { 0x0065, "e" }, /* LATIN SMALL LETTER E */
+ { 0x0066, "f" }, /* LATIN SMALL LETTER F */
+ { 0x0067, "g" }, /* LATIN SMALL LETTER G */
+ { 0x0068, "h" }, /* LATIN SMALL LETTER H */
+ { 0x0069, "i" }, /* LATIN SMALL LETTER I */
+ { 0x006A, "j" }, /* LATIN SMALL LETTER J */
+ { 0x006B, "k" }, /* LATIN SMALL LETTER K */
+ { 0x006C, "l" }, /* LATIN SMALL LETTER L */
+ { 0x006D, "m" }, /* LATIN SMALL LETTER M */
+ { 0x006E, "n" }, /* LATIN SMALL LETTER N */
+ { 0x006F, "o" }, /* LATIN SMALL LETTER O */
+ { 0x0070, "p" }, /* LATIN SMALL LETTER P */
+ { 0x0071, "q" }, /* LATIN SMALL LETTER Q */
+ { 0x0072, "r" }, /* LATIN SMALL LETTER R */
+ { 0x0073, "s" }, /* LATIN SMALL LETTER S */
+ { 0x0074, "t" }, /* LATIN SMALL LETTER T */
+ { 0x0075, "u" }, /* LATIN SMALL LETTER U */
+ { 0x0076, "v" }, /* LATIN SMALL LETTER V */
+ { 0x0077, "w" }, /* LATIN SMALL LETTER W */
+ { 0x0078, "x" }, /* LATIN SMALL LETTER X */
+ { 0x0079, "y" }, /* LATIN SMALL LETTER Y */
+ { 0x007A, "z" }, /* LATIN SMALL LETTER Z */
+ { 0x007B, "braceleft" }, /* LEFT CURLY BRACKET */
+ { 0x007C, "bar" }, /* VERTICAL LINE */
+ { 0x007D, "braceright" }, /* RIGHT CURLY BRACKET */
+ { 0x007E, "tilde" }, /* TILDE */ /* SU: renamed from asciitilde */
+ { 0x00A0, "$spacenobreak" }, /* NO-BREAK SPACE; distinguish Adobe duplicates */
+ { 0x00A1, "exclamdown" }, /* INVERTED EXCLAMATION MARK */
+ { 0x00A2, "cent" }, /* CENT SIGN */
+ { 0x00A3, "sterling" }, /* POUND SIGN */
+ { 0x00A4, "currency" }, /* CURRENCY SIGN */
+ { 0x00A5, "yen" }, /* YEN SIGN */
+ { 0x00A6, "brokenbar" }, /* BROKEN BAR */
+ { 0x00A7, "section" }, /* SECTION SIGN */
+ { 0x00A8, "dieresis" }, /* DIAERESIS */
+ { 0x00A9, "copyright" }, /* COPYRIGHT SIGN */
+ { 0x00AA, "ordfeminine" }, /* FEMININE ORDINAL INDICATOR */
+ { 0x00AB, "guillemotleft" }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ { 0x00AC, "logicalnot" }, /* NOT SIGN */
+ { 0x00AD, "$hyphensoft" }, /* SOFT HYPHEN; distinguish Adobe duplicates */
+ { 0x00AE, "registered" }, /* REGISTERED SIGN */
+ { 0x00AF, "macron" }, /* MACRON */
+ { 0x00AF, "$macron" }, /* MACRON; distinguish Adobe duplicates */
+ { 0x00B0, "degree" }, /* DEGREE SIGN */
+ { 0x00B1, "plusminus" }, /* PLUS-MINUS SIGN */
+ { 0x00B2, "twosuperior" }, /* SUPERSCRIPT TWO */
+ { 0x00B3, "threesuperior" }, /* SUPERSCRIPT THREE */
+ { 0x00B4, "acute" }, /* ACUTE ACCENT */
+ { 0x00B5, "$micro" }, /* MICRO SIGN; distinguish Adobe duplicates */
+ { 0x00B5, "mu" }, /* MICRO SIGN */
+ { 0x00B6, "paragraph" }, /* PILCROW SIGN */
+ { 0x00B7, "periodcentered" }, /* MIDDLE DOT */
+ { 0x00B7, "$periodcentered" }, /* MIDDLE DOT; distinguish Adobe duplicates */
+ { 0x00B8, "cedilla" }, /* CEDILLA */
+ { 0x00B9, "onesuperior" }, /* SUPERSCRIPT ONE */
+ { 0x00BA, "ordmasculine" }, /* MASCULINE ORDINAL INDICATOR */
+ { 0x00BB, "guillemotright" }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+ { 0x00BC, "onequarter" }, /* VULGAR FRACTION ONE QUARTER */
+ { 0x00BD, "onehalf" }, /* VULGAR FRACTION ONE HALF */
+ { 0x00BE, "threequarters" }, /* VULGAR FRACTION THREE QUARTERS */
+ { 0x00BF, "questiondown" }, /* INVERTED QUESTION MARK */
+ { 0x00C0, "Agrave" }, /* LATIN CAPITAL LETTER A WITH GRAVE */
+ { 0x00C1, "Aacute" }, /* LATIN CAPITAL LETTER A WITH ACUTE */
+ { 0x00C2, "Acircumflex" }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ { 0x00C3, "Atilde" }, /* LATIN CAPITAL LETTER A WITH TILDE */
+ { 0x00C4, "Adieresis" }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
+ { 0x00C5, "Aring" }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
+ { 0x00C6, "AE" }, /* LATIN CAPITAL LETTER AE */
+ { 0x00C7, "Ccedilla" }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
+ { 0x00C8, "Egrave" }, /* LATIN CAPITAL LETTER E WITH GRAVE */
+ { 0x00C9, "Eacute" }, /* LATIN CAPITAL LETTER E WITH ACUTE */
+ { 0x00CA, "Ecircumflex" }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ { 0x00CB, "Edieresis" }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+ { 0x00CC, "Igrave" }, /* LATIN CAPITAL LETTER I WITH GRAVE */
+ { 0x00CD, "Iacute" }, /* LATIN CAPITAL LETTER I WITH ACUTE */
+ { 0x00CE, "Icircumflex" }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ { 0x00CF, "Idieresis" }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+ { 0x00D0, "Eth" }, /* LATIN CAPITAL LETTER ETH */
+ { 0x00D1, "Ntilde" }, /* LATIN CAPITAL LETTER N WITH TILDE */
+ { 0x00D2, "Ograve" }, /* LATIN CAPITAL LETTER O WITH GRAVE */
+ { 0x00D3, "Oacute" }, /* LATIN CAPITAL LETTER O WITH ACUTE */
+ { 0x00D4, "Ocircumflex" }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ { 0x00D5, "Otilde" }, /* LATIN CAPITAL LETTER O WITH TILDE */
+ { 0x00D6, "Odieresis" }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
+ { 0x00D7, "multiply" }, /* MULTIPLICATION SIGN */
+ { 0x00D8, "Oslash" }, /* LATIN CAPITAL LETTER O WITH STROKE */
+ { 0x00D9, "Ugrave" }, /* LATIN CAPITAL LETTER U WITH GRAVE */
+ { 0x00DA, "Uacute" }, /* LATIN CAPITAL LETTER U WITH ACUTE */
+ { 0x00DB, "Ucircumflex" }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ { 0x00DC, "Udieresis" }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
+ { 0x00DD, "Yacute" }, /* LATIN CAPITAL LETTER Y WITH ACUTE */
+ { 0x00DE, "Thorn" }, /* LATIN CAPITAL LETTER THORN */
+ { 0x00DF, "germandbls" }, /* LATIN SMALL LETTER SHARP S */
+ { 0x00E0, "agrave" }, /* LATIN SMALL LETTER A WITH GRAVE */
+ { 0x00E1, "aacute" }, /* LATIN SMALL LETTER A WITH ACUTE */
+ { 0x00E2, "acircumflex" }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ { 0x00E3, "atilde" }, /* LATIN SMALL LETTER A WITH TILDE */
+ { 0x00E4, "adieresis" }, /* LATIN SMALL LETTER A WITH DIAERESIS */
+ { 0x00E5, "aring" }, /* LATIN SMALL LETTER A WITH RING ABOVE */
+ { 0x00E6, "ae" }, /* LATIN SMALL LETTER AE */
+ { 0x00E7, "ccedilla" }, /* LATIN SMALL LETTER C WITH CEDILLA */
+ { 0x00E8, "egrave" }, /* LATIN SMALL LETTER E WITH GRAVE */
+ { 0x00E9, "eacute" }, /* LATIN SMALL LETTER E WITH ACUTE */
+ { 0x00EA, "ecircumflex" }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ { 0x00EB, "edieresis" }, /* LATIN SMALL LETTER E WITH DIAERESIS */
+ { 0x00EC, "igrave" }, /* LATIN SMALL LETTER I WITH GRAVE */
+ { 0x00ED, "iacute" }, /* LATIN SMALL LETTER I WITH ACUTE */
+ { 0x00EE, "icircumflex" }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ { 0x00EF, "idieresis" }, /* LATIN SMALL LETTER I WITH DIAERESIS */
+ { 0x00F0, "eth" }, /* LATIN SMALL LETTER ETH */
+ { 0x00F1, "ntilde" }, /* LATIN SMALL LETTER N WITH TILDE */
+ { 0x00F2, "ograve" }, /* LATIN SMALL LETTER O WITH GRAVE */
+ { 0x00F3, "oacute" }, /* LATIN SMALL LETTER O WITH ACUTE */
+ { 0x00F4, "ocircumflex" }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ { 0x00F5, "otilde" }, /* LATIN SMALL LETTER O WITH TILDE */
+ { 0x00F6, "odieresis" }, /* LATIN SMALL LETTER O WITH DIAERESIS */
+ { 0x00F7, "divide" }, /* DIVISION SIGN */
+ { 0x00F8, "oslash" }, /* LATIN SMALL LETTER O WITH STROKE */
+ { 0x00F9, "ugrave" }, /* LATIN SMALL LETTER U WITH GRAVE */
+ { 0x00FA, "uacute" }, /* LATIN SMALL LETTER U WITH ACUTE */
+ { 0x00FB, "ucircumflex" }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ { 0x00FC, "udieresis" }, /* LATIN SMALL LETTER U WITH DIAERESIS */
+ { 0x00FD, "yacute" }, /* LATIN SMALL LETTER Y WITH ACUTE */
+ { 0x00FE, "thorn" }, /* LATIN SMALL LETTER THORN */
+ { 0x00FF, "ydieresis" }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
+ { 0x0100, "Amacron" }, /* LATIN CAPITAL LETTER A WITH MACRON */
+ { 0x0101, "amacron" }, /* LATIN SMALL LETTER A WITH MACRON */
+ { 0x0102, "Abreve" }, /* LATIN CAPITAL LETTER A WITH BREVE */
+ { 0x0103, "abreve" }, /* LATIN SMALL LETTER A WITH BREVE */
+ { 0x0104, "Aogonek" }, /* LATIN CAPITAL LETTER A WITH OGONEK */
+ { 0x0105, "aogonek" }, /* LATIN SMALL LETTER A WITH OGONEK */
+ { 0x0106, "Cacute" }, /* LATIN CAPITAL LETTER C WITH ACUTE */
+ { 0x0107, "cacute" }, /* LATIN SMALL LETTER C WITH ACUTE */
+ { 0x0108, "Ccircumflex" }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
+ { 0x0109, "ccircumflex" }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */
+ { 0x010A, "Cdotaccent" }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */
+ { 0x010B, "cdotaccent" }, /* LATIN SMALL LETTER C WITH DOT ABOVE */
+ { 0x010C, "Ccaron" }, /* LATIN CAPITAL LETTER C WITH CARON */
+ { 0x010D, "ccaron" }, /* LATIN SMALL LETTER C WITH CARON */
+ { 0x010E, "Dcaron" }, /* LATIN CAPITAL LETTER D WITH CARON */
+ { 0x010F, "dcaron" }, /* LATIN SMALL LETTER D WITH CARON */
+ { 0x0110, "Dcroat" }, /* LATIN CAPITAL LETTER D WITH STROKE */
+ { 0x0111, "dcroat" }, /* LATIN SMALL LETTER D WITH STROKE */
+ { 0x0112, "Emacron" }, /* LATIN CAPITAL LETTER E WITH MACRON */
+ { 0x0113, "emacron" }, /* LATIN SMALL LETTER E WITH MACRON */
+ { 0x0114, "Ebreve" }, /* LATIN CAPITAL LETTER E WITH BREVE */
+ { 0x0115, "ebreve" }, /* LATIN SMALL LETTER E WITH BREVE */
+ { 0x0116, "Edotaccent" }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */
+ { 0x0117, "edotaccent" }, /* LATIN SMALL LETTER E WITH DOT ABOVE */
+ { 0x0118, "Eogonek" }, /* LATIN CAPITAL LETTER E WITH OGONEK */
+ { 0x0119, "eogonek" }, /* LATIN SMALL LETTER E WITH OGONEK */
+ { 0x011A, "Ecaron" }, /* LATIN CAPITAL LETTER E WITH CARON */
+ { 0x011B, "ecaron" }, /* LATIN SMALL LETTER E WITH CARON */
+ { 0x011C, "Gcircumflex" }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
+ { 0x011D, "gcircumflex" }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */
+ { 0x011E, "Gbreve" }, /* LATIN CAPITAL LETTER G WITH BREVE */
+ { 0x011F, "gbreve" }, /* LATIN SMALL LETTER G WITH BREVE */
+ { 0x0120, "Gdotaccent" }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */
+ { 0x0121, "gdotaccent" }, /* LATIN SMALL LETTER G WITH DOT ABOVE */
+ { 0x0122, "Gcommaaccent" }, /* LATIN CAPITAL LETTER G WITH CEDILLA */
+ { 0x0123, "gcommaaccent" }, /* LATIN SMALL LETTER G WITH CEDILLA */
+ { 0x0124, "Hcircumflex" }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
+ { 0x0125, "hcircumflex" }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */
+ { 0x0126, "Hbar" }, /* LATIN CAPITAL LETTER H WITH STROKE */
+ { 0x0127, "hbar" }, /* LATIN SMALL LETTER H WITH STROKE */
+ { 0x0128, "Itilde" }, /* LATIN CAPITAL LETTER I WITH TILDE */
+ { 0x0129, "itilde" }, /* LATIN SMALL LETTER I WITH TILDE */
+ { 0x012A, "Imacron" }, /* LATIN CAPITAL LETTER I WITH MACRON */
+ { 0x012B, "imacron" }, /* LATIN SMALL LETTER I WITH MACRON */
+ { 0x012C, "Ibreve" }, /* LATIN CAPITAL LETTER I WITH BREVE */
+ { 0x012D, "ibreve" }, /* LATIN SMALL LETTER I WITH BREVE */
+ { 0x012E, "Iogonek" }, /* LATIN CAPITAL LETTER I WITH OGONEK */
+ { 0x012F, "iogonek" }, /* LATIN SMALL LETTER I WITH OGONEK */
+ { 0x0130, "Idotaccent" }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ { 0x0131, "dotlessi" }, /* LATIN SMALL LETTER DOTLESS I */
+ { 0x0132, "IJ" }, /* LATIN CAPITAL LIGATURE IJ */
+ { 0x0133, "ij" }, /* LATIN SMALL LIGATURE IJ */
+ { 0x0134, "Jcircumflex" }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
+ { 0x0135, "jcircumflex" }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */
+ { 0x0136, "Kcommaaccent" }, /* LATIN CAPITAL LETTER K WITH CEDILLA */
+ { 0x0137, "kcommaaccent" }, /* LATIN SMALL LETTER K WITH CEDILLA */
+ { 0x0138, "kgreenlandic" }, /* LATIN SMALL LETTER KRA */
+ { 0x0139, "Lacute" }, /* LATIN CAPITAL LETTER L WITH ACUTE */
+ { 0x013A, "lacute" }, /* LATIN SMALL LETTER L WITH ACUTE */
+ { 0x013B, "Lcommaaccent" }, /* LATIN CAPITAL LETTER L WITH CEDILLA */
+ { 0x013C, "lcommaaccent" }, /* LATIN SMALL LETTER L WITH CEDILLA */
+ { 0x013D, "Lcaron" }, /* LATIN CAPITAL LETTER L WITH CARON */
+ { 0x013E, "lcaron" }, /* LATIN SMALL LETTER L WITH CARON */
+ { 0x013F, "Ldot" }, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */
+ { 0x0140, "ldot" }, /* LATIN SMALL LETTER L WITH MIDDLE DOT */
+ { 0x0141, "Lslash" }, /* LATIN CAPITAL LETTER L WITH STROKE */
+ { 0x0142, "lslash" }, /* LATIN SMALL LETTER L WITH STROKE */
+ { 0x0143, "Nacute" }, /* LATIN CAPITAL LETTER N WITH ACUTE */
+ { 0x0144, "nacute" }, /* LATIN SMALL LETTER N WITH ACUTE */
+ { 0x0145, "Ncommaaccent" }, /* LATIN CAPITAL LETTER N WITH CEDILLA */
+ { 0x0146, "ncommaaccent" }, /* LATIN SMALL LETTER N WITH CEDILLA */
+ { 0x0147, "Ncaron" }, /* LATIN CAPITAL LETTER N WITH CARON */
+ { 0x0148, "ncaron" }, /* LATIN SMALL LETTER N WITH CARON */
+ { 0x0149, "napostrophe" }, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
+ { 0x014A, "Eng" }, /* LATIN CAPITAL LETTER ENG */
+ { 0x014B, "eng" }, /* LATIN SMALL LETTER ENG */
+ { 0x014C, "Omacron" }, /* LATIN CAPITAL LETTER O WITH MACRON */
+ { 0x014D, "omacron" }, /* LATIN SMALL LETTER O WITH MACRON */
+ { 0x014E, "Obreve" }, /* LATIN CAPITAL LETTER O WITH BREVE */
+ { 0x014F, "obreve" }, /* LATIN SMALL LETTER O WITH BREVE */
+ { 0x0150, "Ohungarumlaut" }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
+ { 0x0151, "ohungarumlaut" }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */
+ { 0x0152, "OE" }, /* LATIN CAPITAL LIGATURE OE */
+ { 0x0153, "oe" }, /* LATIN SMALL LIGATURE OE */
+ { 0x0154, "Racute" }, /* LATIN CAPITAL LETTER R WITH ACUTE */
+ { 0x0155, "racute" }, /* LATIN SMALL LETTER R WITH ACUTE */
+ { 0x0156, "Rcommaaccent" }, /* LATIN CAPITAL LETTER R WITH CEDILLA */
+ { 0x0157, "rcommaaccent" }, /* LATIN SMALL LETTER R WITH CEDILLA */
+ { 0x0158, "Rcaron" }, /* LATIN CAPITAL LETTER R WITH CARON */
+ { 0x0159, "rcaron" }, /* LATIN SMALL LETTER R WITH CARON */
+ { 0x015A, "Sacute" }, /* LATIN CAPITAL LETTER S WITH ACUTE */
+ { 0x015B, "sacute" }, /* LATIN SMALL LETTER S WITH ACUTE */
+ { 0x015C, "Scircumflex" }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
+ { 0x015D, "scircumflex" }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */
+ { 0x015E, "Scedilla" }, /* LATIN CAPITAL LETTER S WITH CEDILLA */
+ { 0x015E, "$Scedilla" }, /* LATIN CAPITAL LETTER S WITH CEDILLA; distinguish Adobe duplicates */
+ { 0x015F, "scedilla" }, /* LATIN SMALL LETTER S WITH CEDILLA */
+ { 0x015F, "$scedilla" }, /* LATIN SMALL LETTER S WITH CEDILLA; distinguish Adobe duplicates */
+ { 0x0160, "Scaron" }, /* LATIN CAPITAL LETTER S WITH CARON */
+ { 0x0161, "scaron" }, /* LATIN SMALL LETTER S WITH CARON */
+ { 0x0162, "$Tcedilla" }, /* LATIN CAPITAL LETTER T WITH CEDILLA; distinguish Adobe duplicates */
+ { 0x0162, "Tcommaaccent" }, /* LATIN CAPITAL LETTER T WITH CEDILLA */
+ { 0x0163, "$tcedilla" }, /* LATIN SMALL LETTER T WITH CEDILLA; distinguish Adobe duplicates */
+ { 0x0163, "tcommaaccent" }, /* LATIN SMALL LETTER T WITH CEDILLA */
+ { 0x0164, "Tcaron" }, /* LATIN CAPITAL LETTER T WITH CARON */
+ { 0x0165, "tcaron" }, /* LATIN SMALL LETTER T WITH CARON */
+ { 0x0166, "Tbar" }, /* LATIN CAPITAL LETTER T WITH STROKE */
+ { 0x0167, "tbar" }, /* LATIN SMALL LETTER T WITH STROKE */
+ { 0x0168, "Utilde" }, /* LATIN CAPITAL LETTER U WITH TILDE */
+ { 0x0169, "utilde" }, /* LATIN SMALL LETTER U WITH TILDE */
+ { 0x016A, "Umacron" }, /* LATIN CAPITAL LETTER U WITH MACRON */
+ { 0x016B, "umacron" }, /* LATIN SMALL LETTER U WITH MACRON */
+ { 0x016C, "Ubreve" }, /* LATIN CAPITAL LETTER U WITH BREVE */
+ { 0x016D, "ubreve" }, /* LATIN SMALL LETTER U WITH BREVE */
+ { 0x016E, "Uring" }, /* LATIN CAPITAL LETTER U WITH RING ABOVE */
+ { 0x016F, "uring" }, /* LATIN SMALL LETTER U WITH RING ABOVE */
+ { 0x0170, "Uhungarumlaut" }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
+ { 0x0171, "uhungarumlaut" }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */
+ { 0x0172, "Uogonek" }, /* LATIN CAPITAL LETTER U WITH OGONEK */
+ { 0x0173, "uogonek" }, /* LATIN SMALL LETTER U WITH OGONEK */
+ { 0x0174, "Wcircumflex" }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */
+ { 0x0175, "wcircumflex" }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */
+ { 0x0176, "Ycircumflex" }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */
+ { 0x0177, "ycircumflex" }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */
+ { 0x0178, "Ydieresis" }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+ { 0x0179, "Zacute" }, /* LATIN CAPITAL LETTER Z WITH ACUTE */
+ { 0x017A, "zacute" }, /* LATIN SMALL LETTER Z WITH ACUTE */
+ { 0x017B, "Zdotaccent" }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */
+ { 0x017C, "zdotaccent" }, /* LATIN SMALL LETTER Z WITH DOT ABOVE */
+ { 0x017D, "Zcaron" }, /* LATIN CAPITAL LETTER Z WITH CARON */
+ { 0x017E, "zcaron" }, /* LATIN SMALL LETTER Z WITH CARON */
+ { 0x017F, "longs" }, /* LATIN SMALL LETTER LONG S */
+ { 0x0192, "florin" }, /* LATIN SMALL LETTER F WITH HOOK */
+ { 0x01A0, "Ohorn" }, /* LATIN CAPITAL LETTER O WITH HORN */
+ { 0x01A1, "ohorn" }, /* LATIN SMALL LETTER O WITH HORN */
+ { 0x01AF, "Uhorn" }, /* LATIN CAPITAL LETTER U WITH HORN */
+ { 0x01B0, "uhorn" }, /* LATIN SMALL LETTER U WITH HORN */
+ { 0x01E6, "Gcaron" }, /* LATIN CAPITAL LETTER G WITH CARON */
+ { 0x01E7, "gcaron" }, /* LATIN SMALL LETTER G WITH CARON */
+ { 0x01FA, "Aringacute" }, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE */
+ { 0x01FB, "aringacute" }, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE */
+ { 0x01FC, "AEacute" }, /* LATIN CAPITAL LETTER AE WITH ACUTE */
+ { 0x01FD, "aeacute" }, /* LATIN SMALL LETTER AE WITH ACUTE */
+ { 0x01FE, "Oslashacute" }, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE */
+ { 0x01FF, "oslashacute" }, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE */
+ { 0x0218, "Scommaaccent" }, /* LATIN CAPITAL LETTER S WITH COMMA BELOW */
+ { 0x0219, "scommaaccent" }, /* LATIN SMALL LETTER S WITH COMMA BELOW */
+ { 0x021A, "$Tcommaaccent" }, /* LATIN CAPITAL LETTER T WITH COMMA BELOW; distinguish Adobe duplicates */
+ { 0x021B, "$tcommaaccent" }, /* LATIN SMALL LETTER T WITH COMMA BELOW; distinguish Adobe duplicates */
+ { 0x02BC, "afii57929" }, /* MODIFIER LETTER APOSTROPHE */
+ { 0x02BD, "afii64937" }, /* MODIFIER LETTER REVERSED COMMA */
+ { 0x02C6, "circumflex" }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+ { 0x02C7, "caron" }, /* CARON */
+ { 0x02C9, "$macronmodifier" }, /* MODIFIER LETTER MACRON */
+ { 0x02CA, "$acutemodifier" }, /* MODIFIER LETTER ACUTE ACCENT */
+ { 0x02CB, "$gravemodifier" }, /* MODIFIER LETTER GRAVE ACCENT */
+ { 0x02D8, "breve" }, /* BREVE */
+ { 0x02D9, "dotaccent" }, /* DOT ABOVE */
+ { 0x02DA, "ring" }, /* RING ABOVE */
+ { 0x02DB, "ogonek" }, /* OGONEK */
+ { 0x02DC, "tilde" }, /* SMALL TILDE */
+ { 0x02DD, "hungarumlaut" }, /* DOUBLE ACUTE ACCENT */
+ { 0x0300, "gravecomb" }, /* COMBINING GRAVE ACCENT */
+ { 0x0301, "acutecomb" }, /* COMBINING ACUTE ACCENT */
+ { 0x0302, "$circumflexcomb" }, /* COMBINING CIRCUMFLEX ACCENT */
+ { 0x0303, "tildecomb" }, /* COMBINING TILDE */
+ { 0x0304, "$macroncomb" }, /* COMBINING MACRON */
+ { 0x0305, "$overlinecomb" }, /* COMBINING OVERLINE */
+ { 0x0306, "$brevecomb" }, /* COMBINING BREVE */
+ { 0x0307, "$dotaccentcomb" }, /* COMBINING DOT ABOVE */
+ { 0x0308, "$dieresiscomb" }, /* COMBINING DIAERESIS */
+ { 0x0309, "hookabovecomb" }, /* COMBINING HOOK ABOVE */
+ { 0x030A, "$ringcomb" }, /* COMBINING RING ABOVE */
+ { 0x030C, "$caroncomb" }, /* COMBINING CARON */
+ { 0x0323, "dotbelowcomb" }, /* COMBINING DOT BELOW */
+ { 0x0327, "$cedillacomb" }, /* COMBINING CEDILLA */
+ { 0x0328, "$ogonekcomb" }, /* COMBINING OGONEK */
+ { 0x0338, "$slashlongcomb" }, /* COMBINING LONG SOLIDUS OVERLAY */
+ { 0x0384, "tonos" }, /* GREEK TONOS */
+ { 0x0385, "dieresistonos" }, /* GREEK DIALYTIKA TONOS */
+ { 0x0386, "Alphatonos" }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */
+ { 0x0387, "anoteleia" }, /* GREEK ANO TELEIA */
+ { 0x0388, "Epsilontonos" }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */
+ { 0x0389, "Etatonos" }, /* GREEK CAPITAL LETTER ETA WITH TONOS */
+ { 0x038A, "Iotatonos" }, /* GREEK CAPITAL LETTER IOTA WITH TONOS */
+ { 0x038C, "Omicrontonos" }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */
+ { 0x038E, "Upsilontonos" }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */
+ { 0x038F, "Omegatonos" }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */
+ { 0x0390, "iotadieresistonos" }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+ { 0x0391, "Alpha" }, /* GREEK CAPITAL LETTER ALPHA */
+ { 0x0392, "Beta" }, /* GREEK CAPITAL LETTER BETA */
+ { 0x0393, "Gamma" }, /* GREEK CAPITAL LETTER GAMMA */
+ { 0x0394, "$Delta" }, /* GREEK CAPITAL LETTER DELTA; distinguish Adobe duplicates */
+ { 0x0395, "Epsilon" }, /* GREEK CAPITAL LETTER EPSILON */
+ { 0x0396, "Zeta" }, /* GREEK CAPITAL LETTER ZETA */
+ { 0x0397, "Eta" }, /* GREEK CAPITAL LETTER ETA */
+ { 0x0398, "Theta" }, /* GREEK CAPITAL LETTER THETA */
+ { 0x0399, "Iota" }, /* GREEK CAPITAL LETTER IOTA */
+ { 0x039A, "Kappa" }, /* GREEK CAPITAL LETTER KAPPA */
+ { 0x039B, "Lambda" }, /* GREEK CAPITAL LETTER LAMDA */
+ { 0x039C, "Mu" }, /* GREEK CAPITAL LETTER MU */
+ { 0x039D, "Nu" }, /* GREEK CAPITAL LETTER NU */
+ { 0x039E, "Xi" }, /* GREEK CAPITAL LETTER XI */
+ { 0x039F, "Omicron" }, /* GREEK CAPITAL LETTER OMICRON */
+ { 0x03A0, "Pi" }, /* GREEK CAPITAL LETTER PI */
+ { 0x03A1, "Rho" }, /* GREEK CAPITAL LETTER RHO */
+ { 0x03A3, "Sigma" }, /* GREEK CAPITAL LETTER SIGMA */
+ { 0x03A4, "Tau" }, /* GREEK CAPITAL LETTER TAU */
+ { 0x03A5, "Upsilon" }, /* GREEK CAPITAL LETTER UPSILON */
+ { 0x03A6, "Phi" }, /* GREEK CAPITAL LETTER PHI */
+ { 0x03A7, "Chi" }, /* GREEK CAPITAL LETTER CHI */
+ { 0x03A8, "Psi" }, /* GREEK CAPITAL LETTER PSI */
+ { 0x03A9, "$Omega" }, /* GREEK CAPITAL LETTER OMEGA; distinguish Adobe duplicates */
+ { 0x03AA, "Iotadieresis" }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
+ { 0x03AB, "Upsilondieresis" }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
+ { 0x03AC, "alphatonos" }, /* GREEK SMALL LETTER ALPHA WITH TONOS */
+ { 0x03AD, "epsilontonos" }, /* GREEK SMALL LETTER EPSILON WITH TONOS */
+ { 0x03AE, "etatonos" }, /* GREEK SMALL LETTER ETA WITH TONOS */
+ { 0x03AF, "iotatonos" }, /* GREEK SMALL LETTER IOTA WITH TONOS */
+ { 0x03B0, "upsilondieresistonos" }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+ { 0x03B1, "alpha" }, /* GREEK SMALL LETTER ALPHA */
+ { 0x03B2, "beta" }, /* GREEK SMALL LETTER BETA */
+ { 0x03B3, "gamma" }, /* GREEK SMALL LETTER GAMMA */
+ { 0x03B4, "delta" }, /* GREEK SMALL LETTER DELTA */
+ { 0x03B5, "epsilon" }, /* GREEK SMALL LETTER EPSILON */
+ { 0x03B6, "zeta" }, /* GREEK SMALL LETTER ZETA */
+ { 0x03B7, "eta" }, /* GREEK SMALL LETTER ETA */
+ { 0x03B8, "theta" }, /* GREEK SMALL LETTER THETA */
+ { 0x03B9, "iota" }, /* GREEK SMALL LETTER IOTA */
+ { 0x03BA, "kappa" }, /* GREEK SMALL LETTER KAPPA */
+ { 0x03BB, "lambda" }, /* GREEK SMALL LETTER LAMDA */
+ { 0x03BC, "$mu" }, /* GREEK SMALL LETTER MU; distinguish Adobe duplicates */
+ { 0x03BD, "nu" }, /* GREEK SMALL LETTER NU */
+ { 0x03BE, "xi" }, /* GREEK SMALL LETTER XI */
+ { 0x03BF, "omicron" }, /* GREEK SMALL LETTER OMICRON */
+ { 0x03C0, "pi" }, /* GREEK SMALL LETTER PI */
+ { 0x03C1, "rho" }, /* GREEK SMALL LETTER RHO */
+ { 0x03C2, "sigma1" }, /* GREEK SMALL LETTER FINAL SIGMA */
+ { 0x03C3, "sigma" }, /* GREEK SMALL LETTER SIGMA */
+ { 0x03C4, "tau" }, /* GREEK SMALL LETTER TAU */
+ { 0x03C5, "upsilon" }, /* GREEK SMALL LETTER UPSILON */
+ { 0x03C6, "phi" }, /* GREEK SMALL LETTER PHI */
+ { 0x03C7, "chi" }, /* GREEK SMALL LETTER CHI */
+ { 0x03C8, "psi" }, /* GREEK SMALL LETTER PSI */
+ { 0x03C9, "omega" }, /* GREEK SMALL LETTER OMEGA */
+ { 0x03CA, "iotadieresis" }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */
+ { 0x03CB, "upsilondieresis" }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
+ { 0x03CC, "omicrontonos" }, /* GREEK SMALL LETTER OMICRON WITH TONOS */
+ { 0x03CD, "upsilontonos" }, /* GREEK SMALL LETTER UPSILON WITH TONOS */
+ { 0x03CE, "omegatonos" }, /* GREEK SMALL LETTER OMEGA WITH TONOS */
+ { 0x03D1, "theta1" }, /* GREEK THETA SYMBOL */
+ { 0x03D2, "Upsilon1" }, /* GREEK UPSILON WITH HOOK SYMBOL */
+ { 0x03D5, "phi1" }, /* GREEK PHI SYMBOL */
+ { 0x03D6, "omega1" }, /* GREEK PI SYMBOL */
+ { 0x03D6, "$pi1" }, /* GREEK PI SYMBOL; Adobe has this as "omega1" which is too confusing */
+ { 0x03F1, "$rho1" }, /* GREEK RHO SYMBOL */
+ { 0x03F5, "$epsilon1" }, /* GREEK LUNATE EPSILON SYMBOL */
+ { 0x0401, "afii10023" }, /* CYRILLIC CAPITAL LETTER IO */
+ { 0x0402, "afii10051" }, /* CYRILLIC CAPITAL LETTER DJE */
+ { 0x0403, "afii10052" }, /* CYRILLIC CAPITAL LETTER GJE */
+ { 0x0404, "afii10053" }, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */
+ { 0x0405, "afii10054" }, /* CYRILLIC CAPITAL LETTER DZE */
+ { 0x0406, "afii10055" }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
+ { 0x0407, "afii10056" }, /* CYRILLIC CAPITAL LETTER YI */
+ { 0x0408, "afii10057" }, /* CYRILLIC CAPITAL LETTER JE */
+ { 0x0409, "afii10058" }, /* CYRILLIC CAPITAL LETTER LJE */
+ { 0x040A, "afii10059" }, /* CYRILLIC CAPITAL LETTER NJE */
+ { 0x040B, "afii10060" }, /* CYRILLIC CAPITAL LETTER TSHE */
+ { 0x040C, "afii10061" }, /* CYRILLIC CAPITAL LETTER KJE */
+ { 0x040E, "afii10062" }, /* CYRILLIC CAPITAL LETTER SHORT U */
+ { 0x040F, "afii10145" }, /* CYRILLIC CAPITAL LETTER DZHE */
+ { 0x0410, "afii10017" }, /* CYRILLIC CAPITAL LETTER A */
+ { 0x0411, "afii10018" }, /* CYRILLIC CAPITAL LETTER BE */
+ { 0x0412, "afii10019" }, /* CYRILLIC CAPITAL LETTER VE */
+ { 0x0413, "afii10020" }, /* CYRILLIC CAPITAL LETTER GHE */
+ { 0x0414, "afii10021" }, /* CYRILLIC CAPITAL LETTER DE */
+ { 0x0415, "afii10022" }, /* CYRILLIC CAPITAL LETTER IE */
+ { 0x0416, "afii10024" }, /* CYRILLIC CAPITAL LETTER ZHE */
+ { 0x0417, "afii10025" }, /* CYRILLIC CAPITAL LETTER ZE */
+ { 0x0418, "afii10026" }, /* CYRILLIC CAPITAL LETTER I */
+ { 0x0419, "afii10027" }, /* CYRILLIC CAPITAL LETTER SHORT I */
+ { 0x041A, "afii10028" }, /* CYRILLIC CAPITAL LETTER KA */
+ { 0x041B, "afii10029" }, /* CYRILLIC CAPITAL LETTER EL */
+ { 0x041C, "afii10030" }, /* CYRILLIC CAPITAL LETTER EM */
+ { 0x041D, "afii10031" }, /* CYRILLIC CAPITAL LETTER EN */
+ { 0x041E, "afii10032" }, /* CYRILLIC CAPITAL LETTER O */
+ { 0x041F, "afii10033" }, /* CYRILLIC CAPITAL LETTER PE */
+ { 0x0420, "afii10034" }, /* CYRILLIC CAPITAL LETTER ER */
+ { 0x0421, "afii10035" }, /* CYRILLIC CAPITAL LETTER ES */
+ { 0x0422, "afii10036" }, /* CYRILLIC CAPITAL LETTER TE */
+ { 0x0423, "afii10037" }, /* CYRILLIC CAPITAL LETTER U */
+ { 0x0424, "afii10038" }, /* CYRILLIC CAPITAL LETTER EF */
+ { 0x0425, "afii10039" }, /* CYRILLIC CAPITAL LETTER HA */
+ { 0x0426, "afii10040" }, /* CYRILLIC CAPITAL LETTER TSE */
+ { 0x0427, "afii10041" }, /* CYRILLIC CAPITAL LETTER CHE */
+ { 0x0428, "afii10042" }, /* CYRILLIC CAPITAL LETTER SHA */
+ { 0x0429, "afii10043" }, /* CYRILLIC CAPITAL LETTER SHCHA */
+ { 0x042A, "afii10044" }, /* CYRILLIC CAPITAL LETTER HARD SIGN */
+ { 0x042B, "afii10045" }, /* CYRILLIC CAPITAL LETTER YERU */
+ { 0x042C, "afii10046" }, /* CYRILLIC CAPITAL LETTER SOFT SIGN */
+ { 0x042D, "afii10047" }, /* CYRILLIC CAPITAL LETTER E */
+ { 0x042E, "afii10048" }, /* CYRILLIC CAPITAL LETTER YU */
+ { 0x042F, "afii10049" }, /* CYRILLIC CAPITAL LETTER YA */
+ { 0x0430, "afii10065" }, /* CYRILLIC SMALL LETTER A */
+ { 0x0431, "afii10066" }, /* CYRILLIC SMALL LETTER BE */
+ { 0x0432, "afii10067" }, /* CYRILLIC SMALL LETTER VE */
+ { 0x0433, "afii10068" }, /* CYRILLIC SMALL LETTER GHE */
+ { 0x0434, "afii10069" }, /* CYRILLIC SMALL LETTER DE */
+ { 0x0435, "afii10070" }, /* CYRILLIC SMALL LETTER IE */
+ { 0x0436, "afii10072" }, /* CYRILLIC SMALL LETTER ZHE */
+ { 0x0437, "afii10073" }, /* CYRILLIC SMALL LETTER ZE */
+ { 0x0438, "afii10074" }, /* CYRILLIC SMALL LETTER I */
+ { 0x0439, "afii10075" }, /* CYRILLIC SMALL LETTER SHORT I */
+ { 0x043A, "afii10076" }, /* CYRILLIC SMALL LETTER KA */
+ { 0x043B, "afii10077" }, /* CYRILLIC SMALL LETTER EL */
+ { 0x043C, "afii10078" }, /* CYRILLIC SMALL LETTER EM */
+ { 0x043D, "afii10079" }, /* CYRILLIC SMALL LETTER EN */
+ { 0x043E, "afii10080" }, /* CYRILLIC SMALL LETTER O */
+ { 0x043F, "afii10081" }, /* CYRILLIC SMALL LETTER PE */
+ { 0x0440, "afii10082" }, /* CYRILLIC SMALL LETTER ER */
+ { 0x0441, "afii10083" }, /* CYRILLIC SMALL LETTER ES */
+ { 0x0442, "afii10084" }, /* CYRILLIC SMALL LETTER TE */
+ { 0x0443, "afii10085" }, /* CYRILLIC SMALL LETTER U */
+ { 0x0444, "afii10086" }, /* CYRILLIC SMALL LETTER EF */
+ { 0x0445, "afii10087" }, /* CYRILLIC SMALL LETTER HA */
+ { 0x0446, "afii10088" }, /* CYRILLIC SMALL LETTER TSE */
+ { 0x0447, "afii10089" }, /* CYRILLIC SMALL LETTER CHE */
+ { 0x0448, "afii10090" }, /* CYRILLIC SMALL LETTER SHA */
+ { 0x0449, "afii10091" }, /* CYRILLIC SMALL LETTER SHCHA */
+ { 0x044A, "afii10092" }, /* CYRILLIC SMALL LETTER HARD SIGN */
+ { 0x044B, "afii10093" }, /* CYRILLIC SMALL LETTER YERU */
+ { 0x044C, "afii10094" }, /* CYRILLIC SMALL LETTER SOFT SIGN */
+ { 0x044D, "afii10095" }, /* CYRILLIC SMALL LETTER E */
+ { 0x044E, "afii10096" }, /* CYRILLIC SMALL LETTER YU */
+ { 0x044F, "afii10097" }, /* CYRILLIC SMALL LETTER YA */
+ { 0x0451, "afii10071" }, /* CYRILLIC SMALL LETTER IO */
+ { 0x0452, "afii10099" }, /* CYRILLIC SMALL LETTER DJE */
+ { 0x0453, "afii10100" }, /* CYRILLIC SMALL LETTER GJE */
+ { 0x0454, "afii10101" }, /* CYRILLIC SMALL LETTER UKRAINIAN IE */
+ { 0x0455, "afii10102" }, /* CYRILLIC SMALL LETTER DZE */
+ { 0x0456, "afii10103" }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+ { 0x0457, "afii10104" }, /* CYRILLIC SMALL LETTER YI */
+ { 0x0458, "afii10105" }, /* CYRILLIC SMALL LETTER JE */
+ { 0x0459, "afii10106" }, /* CYRILLIC SMALL LETTER LJE */
+ { 0x045A, "afii10107" }, /* CYRILLIC SMALL LETTER NJE */
+ { 0x045B, "afii10108" }, /* CYRILLIC SMALL LETTER TSHE */
+ { 0x045C, "afii10109" }, /* CYRILLIC SMALL LETTER KJE */
+ { 0x045E, "afii10110" }, /* CYRILLIC SMALL LETTER SHORT U */
+ { 0x045F, "afii10193" }, /* CYRILLIC SMALL LETTER DZHE */
+ { 0x0462, "afii10146" }, /* CYRILLIC CAPITAL LETTER YAT */
+ { 0x0463, "afii10194" }, /* CYRILLIC SMALL LETTER YAT */
+ { 0x0472, "afii10147" }, /* CYRILLIC CAPITAL LETTER FITA */
+ { 0x0473, "afii10195" }, /* CYRILLIC SMALL LETTER FITA */
+ { 0x0474, "afii10148" }, /* CYRILLIC CAPITAL LETTER IZHITSA */
+ { 0x0475, "afii10196" }, /* CYRILLIC SMALL LETTER IZHITSA */
+ { 0x0490, "afii10050" }, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
+ { 0x0491, "afii10098" }, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */
+ { 0x04D9, "afii10846" }, /* CYRILLIC SMALL LETTER SCHWA */
+ { 0x05B0, "afii57799" }, /* HEBREW POINT SHEVA */
+ { 0x05B1, "afii57801" }, /* HEBREW POINT HATAF SEGOL */
+ { 0x05B2, "afii57800" }, /* HEBREW POINT HATAF PATAH */
+ { 0x05B3, "afii57802" }, /* HEBREW POINT HATAF QAMATS */
+ { 0x05B4, "afii57793" }, /* HEBREW POINT HIRIQ */
+ { 0x05B5, "afii57794" }, /* HEBREW POINT TSERE */
+ { 0x05B6, "afii57795" }, /* HEBREW POINT SEGOL */
+ { 0x05B7, "afii57798" }, /* HEBREW POINT PATAH */
+ { 0x05B8, "afii57797" }, /* HEBREW POINT QAMATS */
+ { 0x05B9, "afii57806" }, /* HEBREW POINT HOLAM */
+ { 0x05BB, "afii57796" }, /* HEBREW POINT QUBUTS */
+ { 0x05BC, "afii57807" }, /* HEBREW POINT DAGESH OR MAPIQ */
+ { 0x05BD, "afii57839" }, /* HEBREW POINT METEG */
+ { 0x05BE, "afii57645" }, /* HEBREW PUNCTUATION MAQAF */
+ { 0x05BF, "afii57841" }, /* HEBREW POINT RAFE */
+ { 0x05C0, "afii57842" }, /* HEBREW PUNCTUATION PASEQ */
+ { 0x05C1, "afii57804" }, /* HEBREW POINT SHIN DOT */
+ { 0x05C2, "afii57803" }, /* HEBREW POINT SIN DOT */
+ { 0x05C3, "afii57658" }, /* HEBREW PUNCTUATION SOF PASUQ */
+ { 0x05D0, "afii57664" }, /* HEBREW LETTER ALEF */
+ { 0x05D1, "afii57665" }, /* HEBREW LETTER BET */
+ { 0x05D2, "afii57666" }, /* HEBREW LETTER GIMEL */
+ { 0x05D3, "afii57667" }, /* HEBREW LETTER DALET */
+ { 0x05D4, "afii57668" }, /* HEBREW LETTER HE */
+ { 0x05D5, "afii57669" }, /* HEBREW LETTER VAV */
+ { 0x05D6, "afii57670" }, /* HEBREW LETTER ZAYIN */
+ { 0x05D7, "afii57671" }, /* HEBREW LETTER HET */
+ { 0x05D8, "afii57672" }, /* HEBREW LETTER TET */
+ { 0x05D9, "afii57673" }, /* HEBREW LETTER YOD */
+ { 0x05DA, "afii57674" }, /* HEBREW LETTER FINAL KAF */
+ { 0x05DB, "afii57675" }, /* HEBREW LETTER KAF */
+ { 0x05DC, "afii57676" }, /* HEBREW LETTER LAMED */
+ { 0x05DD, "afii57677" }, /* HEBREW LETTER FINAL MEM */
+ { 0x05DE, "afii57678" }, /* HEBREW LETTER MEM */
+ { 0x05DF, "afii57679" }, /* HEBREW LETTER FINAL NUN */
+ { 0x05E0, "afii57680" }, /* HEBREW LETTER NUN */
+ { 0x05E1, "afii57681" }, /* HEBREW LETTER SAMEKH */
+ { 0x05E2, "afii57682" }, /* HEBREW LETTER AYIN */
+ { 0x05E3, "afii57683" }, /* HEBREW LETTER FINAL PE */
+ { 0x05E4, "afii57684" }, /* HEBREW LETTER PE */
+ { 0x05E5, "afii57685" }, /* HEBREW LETTER FINAL TSADI */
+ { 0x05E6, "afii57686" }, /* HEBREW LETTER TSADI */
+ { 0x05E7, "afii57687" }, /* HEBREW LETTER QOF */
+ { 0x05E8, "afii57688" }, /* HEBREW LETTER RESH */
+ { 0x05E9, "afii57689" }, /* HEBREW LETTER SHIN */
+ { 0x05EA, "afii57690" }, /* HEBREW LETTER TAV */
+ { 0x05F0, "afii57716" }, /* HEBREW LIGATURE YIDDISH DOUBLE VAV */
+ { 0x05F1, "afii57717" }, /* HEBREW LIGATURE YIDDISH VAV YOD */
+ { 0x05F2, "afii57718" }, /* HEBREW LIGATURE YIDDISH DOUBLE YOD */
+ { 0x060C, "afii57388" }, /* ARABIC COMMA */
+ { 0x061B, "afii57403" }, /* ARABIC SEMICOLON */
+ { 0x061F, "afii57407" }, /* ARABIC QUESTION MARK */
+ { 0x0621, "afii57409" }, /* ARABIC LETTER HAMZA */
+ { 0x0622, "afii57410" }, /* ARABIC LETTER ALEF WITH MADDA ABOVE */
+ { 0x0623, "afii57411" }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE */
+ { 0x0624, "afii57412" }, /* ARABIC LETTER WAW WITH HAMZA ABOVE */
+ { 0x0625, "afii57413" }, /* ARABIC LETTER ALEF WITH HAMZA BELOW */
+ { 0x0626, "afii57414" }, /* ARABIC LETTER YEH WITH HAMZA ABOVE */
+ { 0x0627, "afii57415" }, /* ARABIC LETTER ALEF */
+ { 0x0628, "afii57416" }, /* ARABIC LETTER BEH */
+ { 0x0629, "afii57417" }, /* ARABIC LETTER TEH MARBUTA */
+ { 0x062A, "afii57418" }, /* ARABIC LETTER TEH */
+ { 0x062B, "afii57419" }, /* ARABIC LETTER THEH */
+ { 0x062C, "afii57420" }, /* ARABIC LETTER JEEM */
+ { 0x062D, "afii57421" }, /* ARABIC LETTER HAH */
+ { 0x062E, "afii57422" }, /* ARABIC LETTER KHAH */
+ { 0x062F, "afii57423" }, /* ARABIC LETTER DAL */
+ { 0x0630, "afii57424" }, /* ARABIC LETTER THAL */
+ { 0x0631, "afii57425" }, /* ARABIC LETTER REH */
+ { 0x0632, "afii57426" }, /* ARABIC LETTER ZAIN */
+ { 0x0633, "afii57427" }, /* ARABIC LETTER SEEN */
+ { 0x0634, "afii57428" }, /* ARABIC LETTER SHEEN */
+ { 0x0635, "afii57429" }, /* ARABIC LETTER SAD */
+ { 0x0636, "afii57430" }, /* ARABIC LETTER DAD */
+ { 0x0637, "afii57431" }, /* ARABIC LETTER TAH */
+ { 0x0638, "afii57432" }, /* ARABIC LETTER ZAH */
+ { 0x0639, "afii57433" }, /* ARABIC LETTER AIN */
+ { 0x063A, "afii57434" }, /* ARABIC LETTER GHAIN */
+ { 0x0640, "afii57440" }, /* ARABIC TATWEEL */
+ { 0x0641, "afii57441" }, /* ARABIC LETTER FEH */
+ { 0x0642, "afii57442" }, /* ARABIC LETTER QAF */
+ { 0x0643, "afii57443" }, /* ARABIC LETTER KAF */
+ { 0x0644, "afii57444" }, /* ARABIC LETTER LAM */
+ { 0x0645, "afii57445" }, /* ARABIC LETTER MEEM */
+ { 0x0646, "afii57446" }, /* ARABIC LETTER NOON */
+ { 0x0647, "afii57470" }, /* ARABIC LETTER HEH */
+ { 0x0648, "afii57448" }, /* ARABIC LETTER WAW */
+ { 0x0649, "afii57449" }, /* ARABIC LETTER ALEF MAKSURA */
+ { 0x064A, "afii57450" }, /* ARABIC LETTER YEH */
+ { 0x064B, "afii57451" }, /* ARABIC FATHATAN */
+ { 0x064C, "afii57452" }, /* ARABIC DAMMATAN */
+ { 0x064D, "afii57453" }, /* ARABIC KASRATAN */
+ { 0x064E, "afii57454" }, /* ARABIC FATHA */
+ { 0x064F, "afii57455" }, /* ARABIC DAMMA */
+ { 0x0650, "afii57456" }, /* ARABIC KASRA */
+ { 0x0651, "afii57457" }, /* ARABIC SHADDA */
+ { 0x0652, "afii57458" }, /* ARABIC SUKUN */
+ { 0x0660, "afii57392" }, /* ARABIC-INDIC DIGIT ZERO */
+ { 0x0661, "afii57393" }, /* ARABIC-INDIC DIGIT ONE */
+ { 0x0662, "afii57394" }, /* ARABIC-INDIC DIGIT TWO */
+ { 0x0663, "afii57395" }, /* ARABIC-INDIC DIGIT THREE */
+ { 0x0664, "afii57396" }, /* ARABIC-INDIC DIGIT FOUR */
+ { 0x0665, "afii57397" }, /* ARABIC-INDIC DIGIT FIVE */
+ { 0x0666, "afii57398" }, /* ARABIC-INDIC DIGIT SIX */
+ { 0x0667, "afii57399" }, /* ARABIC-INDIC DIGIT SEVEN */
+ { 0x0668, "afii57400" }, /* ARABIC-INDIC DIGIT EIGHT */
+ { 0x0669, "afii57401" }, /* ARABIC-INDIC DIGIT NINE */
+ { 0x066A, "afii57381" }, /* ARABIC PERCENT SIGN */
+ { 0x066D, "afii63167" }, /* ARABIC FIVE POINTED STAR */
+ { 0x0679, "afii57511" }, /* ARABIC LETTER TTEH */
+ { 0x067E, "afii57506" }, /* ARABIC LETTER PEH */
+ { 0x0686, "afii57507" }, /* ARABIC LETTER TCHEH */
+ { 0x0688, "afii57512" }, /* ARABIC LETTER DDAL */
+ { 0x0691, "afii57513" }, /* ARABIC LETTER RREH */
+ { 0x0698, "afii57508" }, /* ARABIC LETTER JEH */
+ { 0x06A4, "afii57505" }, /* ARABIC LETTER VEH */
+ { 0x06AF, "afii57509" }, /* ARABIC LETTER GAF */
+ { 0x06BA, "afii57514" }, /* ARABIC LETTER NOON GHUNNA */
+ { 0x06D2, "afii57519" }, /* ARABIC LETTER YEH BARREE */
+ { 0x06D5, "afii57534" }, /* ARABIC LETTER AE */
+ { 0x1E80, "Wgrave" }, /* LATIN CAPITAL LETTER W WITH GRAVE */
+ { 0x1E81, "wgrave" }, /* LATIN SMALL LETTER W WITH GRAVE */
+ { 0x1E82, "Wacute" }, /* LATIN CAPITAL LETTER W WITH ACUTE */
+ { 0x1E83, "wacute" }, /* LATIN SMALL LETTER W WITH ACUTE */
+ { 0x1E84, "Wdieresis" }, /* LATIN CAPITAL LETTER W WITH DIAERESIS */
+ { 0x1E85, "wdieresis" }, /* LATIN SMALL LETTER W WITH DIAERESIS */
+ { 0x1EF2, "Ygrave" }, /* LATIN CAPITAL LETTER Y WITH GRAVE */
+ { 0x1EF3, "ygrave" }, /* LATIN SMALL LETTER Y WITH GRAVE */
+ { 0x200C, "afii61664" }, /* ZERO WIDTH NON-JOINER */
+ { 0x200D, "afii301" }, /* ZERO WIDTH JOINER */
+ { 0x200E, "afii299" }, /* LEFT-TO-RIGHT MARK */
+ { 0x200F, "afii300" }, /* RIGHT-TO-LEFT MARK */
+ { 0x2012, "figuredash" }, /* FIGURE DASH */
+ { 0x2013, "endash" }, /* EN DASH */
+ { 0x2014, "emdash" }, /* EM DASH */
+ { 0x2015, "afii00208" }, /* HORIZONTAL BAR */
+ { 0x2017, "underscoredbl" }, /* DOUBLE LOW LINE */
+ { 0x2018, "quoteleft" }, /* LEFT SINGLE QUOTATION MARK */
+ { 0x2019, "quoteright" }, /* RIGHT SINGLE QUOTATION MARK */
+ { 0x201A, "quotesinglbase" }, /* SINGLE LOW-9 QUOTATION MARK */
+ { 0x201B, "quotereversed" }, /* SINGLE HIGH-REVERSED-9 QUOTATION MARK */
+ { 0x201C, "quotedblleft" }, /* LEFT DOUBLE QUOTATION MARK */
+ { 0x201D, "quotedblright" }, /* RIGHT DOUBLE QUOTATION MARK */
+ { 0x201E, "quotedblbase" }, /* DOUBLE LOW-9 QUOTATION MARK */
+ { 0x201F, "$quotedblreversed" }, /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK */
+ { 0x2020, "dagger" }, /* DAGGER */
+ { 0x2021, "daggerdbl" }, /* DOUBLE DAGGER */
+ { 0x2022, "bullet" }, /* BULLET */
+ { 0x2024, "onedotenleader" }, /* ONE DOT LEADER */
+ { 0x2025, "twodotenleader" }, /* TWO DOT LEADER */
+ { 0x2026, "ellipsis" }, /* HORIZONTAL ELLIPSIS */
+ { 0x202C, "afii61573" }, /* POP DIRECTIONAL FORMATTING */
+ { 0x202D, "afii61574" }, /* LEFT-TO-RIGHT OVERRIDE */
+ { 0x202E, "afii61575" }, /* RIGHT-TO-LEFT OVERRIDE */
+ { 0x2030, "perthousand" }, /* PER MILLE SIGN */
+ { 0x2032, "minute" }, /* PRIME */
+ { 0x2033, "second" }, /* DOUBLE PRIME */
+ { 0x2039, "guilsinglleft" }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+ { 0x203A, "guilsinglright" }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+ { 0x203C, "exclamdbl" }, /* DOUBLE EXCLAMATION MARK */
+ { 0x2040, "$tie" }, /* CHARACTER TIE */
+ { 0x2044, "fraction" }, /* FRACTION SLASH */
+ { 0x2044, "$fractionslash" }, /* FRACTION SLASH; distinguish Adobe duplicates */
+ { 0x2070, "zerosuperior" }, /* SUPERSCRIPT ZERO */
+ { 0x2074, "foursuperior" }, /* SUPERSCRIPT FOUR */
+ { 0x2075, "fivesuperior" }, /* SUPERSCRIPT FIVE */
+ { 0x2076, "sixsuperior" }, /* SUPERSCRIPT SIX */
+ { 0x2077, "sevensuperior" }, /* SUPERSCRIPT SEVEN */
+ { 0x2078, "eightsuperior" }, /* SUPERSCRIPT EIGHT */
+ { 0x2079, "ninesuperior" }, /* SUPERSCRIPT NINE */
+ { 0x207D, "parenleftsuperior" }, /* SUPERSCRIPT LEFT PARENTHESIS */
+ { 0x207E, "parenrightsuperior" }, /* SUPERSCRIPT RIGHT PARENTHESIS */
+ { 0x207F, "nsuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER N */
+ { 0x2080, "zeroinferior" }, /* SUBSCRIPT ZERO */
+ { 0x2081, "oneinferior" }, /* SUBSCRIPT ONE */
+ { 0x2082, "twoinferior" }, /* SUBSCRIPT TWO */
+ { 0x2083, "threeinferior" }, /* SUBSCRIPT THREE */
+ { 0x2084, "fourinferior" }, /* SUBSCRIPT FOUR */
+ { 0x2085, "fiveinferior" }, /* SUBSCRIPT FIVE */
+ { 0x2086, "sixinferior" }, /* SUBSCRIPT SIX */
+ { 0x2087, "seveninferior" }, /* SUBSCRIPT SEVEN */
+ { 0x2088, "eightinferior" }, /* SUBSCRIPT EIGHT */
+ { 0x2089, "nineinferior" }, /* SUBSCRIPT NINE */
+ { 0x208D, "parenleftinferior" }, /* SUBSCRIPT LEFT PARENTHESIS */
+ { 0x208E, "parenrightinferior" }, /* SUBSCRIPT RIGHT PARENTHESIS */
+ { 0x20A1, "colonmonetary" }, /* COLON SIGN */
+ { 0x20A3, "franc" }, /* FRENCH FRANC SIGN */
+ { 0x20A4, "lira" }, /* LIRA SIGN */
+ { 0x20A7, "peseta" }, /* PESETA SIGN */
+ { 0x20AA, "afii57636" }, /* NEW SHEQEL SIGN */
+ { 0x20AB, "dong" }, /* DONG SIGN */
+ { 0x20AC, "Euro" }, /* EURO SIGN */
+ { 0x20D7, "$vectorcomb" }, /* COMBINING RIGHT ARROW ABOVE */
+ { 0x20DD, "$circlecomb" }, /* COMBINING ENCLOSING CIRCLE */
+ { 0x2105, "afii61248" }, /* CARE OF */
+ { 0x2111, "Ifraktur" }, /* BLACK-LETTER CAPITAL I */
+ { 0x2113, "afii61289" }, /* SCRIPT SMALL L */
+ { 0x2113, "$lscript" }, /* SCRIPT SMALL L; Adobe has this as "afii61289" */
+ { 0x2116, "afii61352" }, /* NUMERO SIGN */
+ { 0x2118, "weierstrass" }, /* SCRIPT CAPITAL P */
+ { 0x211C, "Rfraktur" }, /* BLACK-LETTER CAPITAL R */
+ { 0x211E, "prescription" }, /* PRESCRIPTION TAKE */
+ { 0x2122, "trademark" }, /* TRADE MARK SIGN */
+ { 0x2126, "$Ohm" }, /* OHM SIGN; distinguish Adobe duplicates */
+ { 0x2126, "Omega" }, /* OHM SIGN */
+ { 0x212E, "estimated" }, /* ESTIMATED SYMBOL */
+ { 0x2135, "aleph" }, /* ALEF SYMBOL */
+ { 0x2153, "onethird" }, /* VULGAR FRACTION ONE THIRD */
+ { 0x2154, "twothirds" }, /* VULGAR FRACTION TWO THIRDS */
+ { 0x215B, "oneeighth" }, /* VULGAR FRACTION ONE EIGHTH */
+ { 0x215C, "threeeighths" }, /* VULGAR FRACTION THREE EIGHTHS */
+ { 0x215D, "fiveeighths" }, /* VULGAR FRACTION FIVE EIGHTHS */
+ { 0x215E, "seveneighths" }, /* VULGAR FRACTION SEVEN EIGHTHS */
+ { 0x2190, "arrowleft" }, /* LEFTWARDS ARROW */
+ { 0x2191, "arrowup" }, /* UPWARDS ARROW */
+ { 0x2192, "arrowright" }, /* RIGHTWARDS ARROW */
+ { 0x2193, "arrowdown" }, /* DOWNWARDS ARROW */
+ { 0x2194, "arrowboth" }, /* LEFT RIGHT ARROW */
+ { 0x2195, "arrowupdn" }, /* UP DOWN ARROW */
+ { 0x2196, "$arrownorthwest" }, /* NORTH WEST ARROW */
+ { 0x2197, "$arrownortheast" }, /* NORTH EAST ARROW */
+ { 0x2198, "$arrowsoutheast" }, /* SOUTH EAST ARROW */
+ { 0x2199, "$arrowsouthwest" }, /* SOUTH WEST ARROW */
+ { 0x21A8, "arrowupdnbse" }, /* UP DOWN ARROW WITH BASE */
+ { 0x21B5, "carriagereturn" }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS */
+ { 0x21BC, "$harpoonleftbarbup" }, /* LEFTWARDS HARPOON WITH BARB UPWARDS */
+ { 0x21BD, "$harpoonleftbarbdown" }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS */
+ { 0x21C0, "$harpoonrightbarbup" }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS */
+ { 0x21C1, "$harpoonrightbarbdown" }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS */
+ { 0x21D0, "arrowdblleft" }, /* LEFTWARDS DOUBLE ARROW */
+ { 0x21D1, "arrowdblup" }, /* UPWARDS DOUBLE ARROW */
+ { 0x21D2, "arrowdblright" }, /* RIGHTWARDS DOUBLE ARROW */
+ { 0x21D3, "arrowdbldown" }, /* DOWNWARDS DOUBLE ARROW */
+ { 0x21D4, "arrowdblboth" }, /* LEFT RIGHT DOUBLE ARROW */
+ { 0x21D5, "$arrowdblupdn" }, /* UP DOWN DOUBLE ARROW */
+ { 0x2200, "universal" }, /* FOR ALL */
+ { 0x2202, "partialdiff" }, /* PARTIAL DIFFERENTIAL */
+ { 0x2203, "existential" }, /* THERE EXISTS */
+ { 0x2205, "emptyset" }, /* EMPTY SET */
+ { 0x2206, "Delta" }, /* INCREMENT */
+ { 0x2206, "$increment" }, /* INCREMENT; distinguish Adobe duplicates */
+ { 0x2207, "gradient" }, /* NABLA */
+ { 0x2208, "element" }, /* ELEMENT OF */
+ { 0x2209, "notelement" }, /* NOT AN ELEMENT OF */
+ { 0x220B, "suchthat" }, /* CONTAINS AS MEMBER */
+ { 0x220F, "product" }, /* N-ARY PRODUCT */
+ { 0x2210, "$coproduct" }, /* N-ARY COPRODUCT */
+ { 0x2211, "summation" }, /* N-ARY SUMMATION */
+ { 0x2212, "minus" }, /* MINUS SIGN */
+ { 0x2213, "$minusplus" }, /* MINUS-OR-PLUS SIGN */
+ { 0x2215, "$divisionslash" }, /* DIVISION SLASH; distinguish Adobe duplicates */
+ { 0x2217, "asteriskmath" }, /* ASTERISK OPERATOR */
+ { 0x2219, "$bulletmath" }, /* BULLET OPERATOR; distinguish Adobe duplicates */
+ { 0x221A, "radical" }, /* SQUARE ROOT */
+ { 0x221D, "proportional" }, /* PROPORTIONAL TO */
+ { 0x221E, "infinity" }, /* INFINITY */
+ { 0x221F, "orthogonal" }, /* RIGHT ANGLE */
+ { 0x2220, "angle" }, /* ANGLE */
+ { 0x2225, "$parallel" }, /* PARALLEL TO */
+ { 0x2227, "logicaland" }, /* LOGICAL AND */
+ { 0x2228, "logicalor" }, /* LOGICAL OR */
+ { 0x2229, "intersection" }, /* INTERSECTION */
+ { 0x222A, "union" }, /* UNION */
+ { 0x222B, "integral" }, /* INTEGRAL */
+ { 0x222E, "$contintegral" }, /* CONTOUR INTEGRAL */
+ { 0x2234, "therefore" }, /* THEREFORE */
+ { 0x223C, "similar" }, /* TILDE OPERATOR */
+ { 0x2240, "$wreathproduct" }, /* WREATH PRODUCT */
+ { 0x2243, "$similarequal" }, /* ASYMPTOTICALLY EQUAL TO */
+ { 0x2245, "congruent" }, /* APPROXIMATELY EQUAL TO */
+ { 0x2248, "approxequal" }, /* ALMOST EQUAL TO */
+ { 0x224D, "$equivasymptotic" }, /* EQUIVALENT TO */
+ { 0x2260, "notequal" }, /* NOT EQUAL TO */
+ { 0x2261, "equivalence" }, /* IDENTICAL TO */
+ { 0x2264, "lessequal" }, /* LESS-THAN OR EQUAL TO */
+ { 0x2265, "greaterequal" }, /* GREATER-THAN OR EQUAL TO */
+ { 0x226A, "$lessmuch" }, /* MUCH-LESS THAN */
+ { 0x226B, "$greatermuch" }, /* MUCH GREATER-THAN */
+ { 0x227A, "$precedes" }, /* PRECEDES */
+ { 0x227B, "$follows" }, /* SUCCEEDS */
+ { 0x227C, "$precedesequal" }, /* PRECEDES OR EQUAL TO */
+ { 0x227D, "$followsequal" }, /* SUCCEEDS OR EQUAL TO */
+ { 0x2282, "propersubset" }, /* SUBSET OF */
+ { 0x2283, "propersuperset" }, /* SUPERSET OF */
+ { 0x2284, "notsubset" }, /* NOT A SUBSET OF */
+ { 0x2286, "reflexsubset" }, /* SUBSET OF OR EQUAL TO */
+ { 0x2287, "reflexsuperset" }, /* SUPERSET OF OR EQUAL TO */
+ { 0x228E, "$unionmulti" }, /* MULTISET UNION */
+ { 0x2291, "$reflexsubsetsq" }, /* SQUARE IMAGE OF OR EQUAL TO */
+ { 0x2292, "$reflexsupersetsq" }, /* SQUARE ORIGINAL OF OR EQUAL TO */
+ { 0x2293, "$intersectionsq" }, /* SQUARE CAP */
+ { 0x2294, "$unionsq" }, /* SQUARE CUP */
+ { 0x2295, "circleplus" }, /* CIRCLED PLUS */
+ { 0x2296, "$circleminus" }, /* CIRCLED MINUS */
+ { 0x2297, "circlemultiply" }, /* CIRCLED TIMES */
+ { 0x2298, "$circledivide" }, /* CIRCLED DIVISION SLASH */
+ { 0x2299, "$circledot" }, /* CIRCLED DOT OPERATOR */
+ { 0x22A2, "$turnstileleft" }, /* RIGHT TACK */
+ { 0x22A3, "$turnstileright" }, /* LEFT TACK */
+ { 0x22A4, "$latticetop" }, /* DOWN TACK */
+ { 0x22A5, "perpendicular" }, /* UP TACK */
+ { 0x22B2, "$normalin" }, /* NORMAL SUBGROUP OF */
+ { 0x22B3, "$normalizes" }, /* CONTAINS AS NORMAL SUBGROUP */
+ { 0x22B4, "$reflexnormalin" }, /* NORMAL SUBGROUP OF OR EQUAL TO */
+ { 0x22B5, "$reflexnormalizes" }, /* CONTAINS AS NORMAL SUBGROUP OR EQUAL TO */
+ { 0x22C4, "$diamondmath" }, /* DIAMOND OPERATOR */
+ { 0x22C5, "dotmath" }, /* DOT OPERATOR */
+ { 0x22C6, "$starmath" }, /* STAR OPERATOR */
+ { 0x2302, "house" }, /* HOUSE */
+ { 0x2308, "$ceilingleft" }, /* LEFT CEILING */
+ { 0x2309, "$ceilingright" }, /* RIGHT CEILING */
+ { 0x230A, "$floorleft" }, /* LEFT FLOOR */
+ { 0x230B, "$floorright" }, /* RIGHT FLOOR */
+ { 0x2310, "revlogicalnot" }, /* REVERSED NOT SIGN */
+ { 0x2320, "integraltp" }, /* TOP HALF INTEGRAL */
+ { 0x2321, "integralbt" }, /* BOTTOM HALF INTEGRAL */
+ { 0x2322, "$frown" }, /* FROWN */
+ { 0x2323, "$smile" }, /* SMILE */
+ { 0x2329, "angleleft" }, /* LEFT-POINTING ANGLE BRACKET */
+ { 0x232A, "angleright" }, /* RIGHT-POINTING ANGLE BRACKET */
+ { 0x2420, "$spacesymbol" }, /* SYMBOL FOR SPACE */
+ { 0x2500, "SF100000" }, /* BOX DRAWINGS LIGHT HORIZONTAL */
+ { 0x2502, "SF110000" }, /* BOX DRAWINGS LIGHT VERTICAL */
+ { 0x250C, "SF010000" }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */
+ { 0x2510, "SF030000" }, /* BOX DRAWINGS LIGHT DOWN AND LEFT */
+ { 0x2514, "SF020000" }, /* BOX DRAWINGS LIGHT UP AND RIGHT */
+ { 0x2518, "SF040000" }, /* BOX DRAWINGS LIGHT UP AND LEFT */
+ { 0x251C, "SF080000" }, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+ { 0x2524, "SF090000" }, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+ { 0x252C, "SF060000" }, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+ { 0x2534, "SF070000" }, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+ { 0x253C, "SF050000" }, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+ { 0x2550, "SF430000" }, /* BOX DRAWINGS DOUBLE HORIZONTAL */
+ { 0x2551, "SF240000" }, /* BOX DRAWINGS DOUBLE VERTICAL */
+ { 0x2552, "SF510000" }, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */
+ { 0x2553, "SF520000" }, /* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */
+ { 0x2554, "SF390000" }, /* BOX DRAWINGS DOUBLE DOWN AND RIGHT */
+ { 0x2555, "SF220000" }, /* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */
+ { 0x2556, "SF210000" }, /* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */
+ { 0x2557, "SF250000" }, /* BOX DRAWINGS DOUBLE DOWN AND LEFT */
+ { 0x2558, "SF500000" }, /* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */
+ { 0x2559, "SF490000" }, /* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */
+ { 0x255A, "SF380000" }, /* BOX DRAWINGS DOUBLE UP AND RIGHT */
+ { 0x255B, "SF280000" }, /* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */
+ { 0x255C, "SF270000" }, /* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */
+ { 0x255D, "SF260000" }, /* BOX DRAWINGS DOUBLE UP AND LEFT */
+ { 0x255E, "SF360000" }, /* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */
+ { 0x255F, "SF370000" }, /* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */
+ { 0x2560, "SF420000" }, /* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */
+ { 0x2561, "SF190000" }, /* BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE */
+ { 0x2562, "SF200000" }, /* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */
+ { 0x2563, "SF230000" }, /* BOX DRAWINGS DOUBLE VERTICAL AND LEFT */
+ { 0x2564, "SF470000" }, /* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */
+ { 0x2565, "SF480000" }, /* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */
+ { 0x2566, "SF410000" }, /* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */
+ { 0x2567, "SF450000" }, /* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */
+ { 0x2568, "SF460000" }, /* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */
+ { 0x2569, "SF400000" }, /* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */
+ { 0x256A, "SF540000" }, /* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */
+ { 0x256B, "SF530000" }, /* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */
+ { 0x256C, "SF440000" }, /* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */
+ { 0x2580, "upblock" }, /* UPPER HALF BLOCK */
+ { 0x2584, "dnblock" }, /* LOWER HALF BLOCK */
+ { 0x2588, "block" }, /* FULL BLOCK */
+ { 0x258C, "lfblock" }, /* LEFT HALF BLOCK */
+ { 0x2590, "rtblock" }, /* RIGHT HALF BLOCK */
+ { 0x2591, "ltshade" }, /* LIGHT SHADE */
+ { 0x2592, "shade" }, /* MEDIUM SHADE */
+ { 0x2593, "dkshade" }, /* DARK SHADE */
+ { 0x25A0, "filledbox" }, /* BLACK SQUARE */
+ { 0x25A1, "H22073" }, /* WHITE SQUARE */
+ { 0x25AA, "H18543" }, /* BLACK SMALL SQUARE */
+ { 0x25AB, "H18551" }, /* WHITE SMALL SQUARE */
+ { 0x25AC, "filledrect" }, /* BLACK RECTANGLE */
+ { 0x25B2, "triagup" }, /* BLACK UP-POINTING TRIANGLE */
+ { 0x25B3, "$triagwhiteup" }, /* WHITE UP-POINTING TRIANGLE */
+ { 0x25BA, "triagrt" }, /* BLACK RIGHT-POINTING POINTER */
+ { 0x25BC, "triagdn" }, /* BLACK DOWN-POINTING TRIANGLE */
+ { 0x25BD, "$triagwhitedn" }, /* WHITE DOWN-POINTING TRIANGLE */
+ { 0x25C4, "triaglf" }, /* BLACK LEFT-POINTING POINTER */
+ { 0x25CA, "lozenge" }, /* LOZENGE */
+ { 0x25CB, "circle" }, /* WHITE CIRCLE */
+ { 0x25CF, "H18533" }, /* BLACK CIRCLE */
+ { 0x25D8, "invbullet" }, /* INVERSE BULLET */
+ { 0x25D9, "invcircle" }, /* INVERSE WHITE CIRCLE */
+ { 0x25E6, "openbullet" }, /* WHITE BULLET */
+ { 0x25EF, "$circlelarge" }, /* LARGE CIRCLE */
+ { 0x263A, "smileface" }, /* WHITE SMILING FACE */
+ { 0x263B, "invsmileface" }, /* BLACK SMILING FACE */
+ { 0x263C, "sun" }, /* WHITE SUN WITH RAYS */
+ { 0x2640, "female" }, /* FEMALE SIGN */
+ { 0x2642, "male" }, /* MALE SIGN */
+ { 0x2660, "spade" }, /* BLACK SPADE SUIT */
+ { 0x2663, "club" }, /* BLACK CLUB SUIT */
+ { 0x2665, "heart" }, /* BLACK HEART SUIT */
+ { 0x2666, "diamond" }, /* BLACK DIAMOND SUIT */
+ { 0x266A, "musicalnote" }, /* EIGHTH NOTE */
+ { 0x266B, "musicalnotedbl" }, /* BEAMED EIGHTH NOTES */
+ { 0x266D, "$flat" }, /* MUSIC FLAT SIGN */
+ { 0x266E, "$natural" }, /* MUSIC NATURAL SIGN */
+ { 0x266F, "$sharp" }, /* MUSIC SHARP SIGN */
+ { 0xF6BE, "dotlessj" }, /* LATIN SMALL LETTER DOTLESS J */
+ { 0xF6BF, "LL" }, /* LATIN CAPITAL LETTER LL */
+ { 0xF6C0, "ll" }, /* LATIN SMALL LETTER LL */
+ { 0xF6C3, "commaaccent" }, /* COMMA BELOW */
+ { 0xF6C4, "afii10063" }, /* CYRILLIC SMALL LETTER GHE VARIANT */
+ { 0xF6C5, "afii10064" }, /* CYRILLIC SMALL LETTER BE VARIANT */
+ { 0xF6C6, "afii10192" }, /* CYRILLIC SMALL LETTER DE VARIANT */
+ { 0xF6C7, "afii10831" }, /* CYRILLIC SMALL LETTER PE VARIANT */
+ { 0xF6C8, "afii10832" }, /* CYRILLIC SMALL LETTER TE VARIANT */
+ { 0xF6C9, "Acute" }, /* CAPITAL ACUTE ACCENT */
+ { 0xF6CA, "Caron" }, /* CAPITAL CARON */
+ { 0xF6CB, "Dieresis" }, /* CAPITAL DIAERESIS */
+ { 0xF6CC, "DieresisAcute" }, /* CAPITAL DIAERESIS ACUTE ACCENT */
+ { 0xF6CD, "DieresisGrave" }, /* CAPITAL DIAERESIS GRAVE ACCENT */
+ { 0xF6CE, "Grave" }, /* CAPITAL GRAVE ACCENT */
+ { 0xF6CF, "Hungarumlaut" }, /* CAPITAL DOUBLE ACUTE ACCENT */
+ { 0xF6D0, "Macron" }, /* CAPITAL MACRON */
+ { 0xF6D1, "cyrBreve" }, /* CAPITAL CYRILLIC BREVE */
+ { 0xF6D2, "cyrFlex" }, /* CAPITAL CYRILLIC CIRCUMFLEX */
+ { 0xF6D3, "dblGrave" }, /* CAPITAL DOUBLE GRAVE ACCENT */
+ { 0xF6D4, "cyrbreve" }, /* CYRILLIC BREVE */
+ { 0xF6D5, "cyrflex" }, /* CYRILLIC CIRCUMFLEX */
+ { 0xF6D6, "dblgrave" }, /* DOUBLE GRAVE ACCENT */
+ { 0xF6D7, "dieresisacute" }, /* DIAERESIS ACUTE ACCENT */
+ { 0xF6D8, "dieresisgrave" }, /* DIAERESIS GRAVE ACCENT */
+ { 0xF6D9, "copyrightserif" }, /* COPYRIGHT SIGN SERIF */
+ { 0xF6DA, "registerserif" }, /* REGISTERED SIGN SERIF */
+ { 0xF6DB, "trademarkserif" }, /* TRADE MARK SIGN SERIF */
+ { 0xF6DC, "onefitted" }, /* PROPORTIONAL DIGIT ONE */
+ { 0xF6DD, "rupiah" }, /* RUPIAH SIGN */
+ { 0xF6DE, "threequartersemdash" }, /* THREE QUARTERS EM DASH */
+ { 0xF6DF, "centinferior" }, /* SUBSCRIPT CENT SIGN */
+ { 0xF6E0, "centsuperior" }, /* SUPERSCRIPT CENT SIGN */
+ { 0xF6E1, "commainferior" }, /* SUBSCRIPT COMMA */
+ { 0xF6E2, "commasuperior" }, /* SUPERSCRIPT COMMA */
+ { 0xF6E3, "dollarinferior" }, /* SUBSCRIPT DOLLAR SIGN */
+ { 0xF6E4, "dollarsuperior" }, /* SUPERSCRIPT DOLLAR SIGN */
+ { 0xF6E5, "hypheninferior" }, /* SUBSCRIPT HYPHEN-MINUS */
+ { 0xF6E6, "hyphensuperior" }, /* SUPERSCRIPT HYPHEN-MINUS */
+ { 0xF6E7, "periodinferior" }, /* SUBSCRIPT FULL STOP */
+ { 0xF6E8, "periodsuperior" }, /* SUPERSCRIPT FULL STOP */
+ { 0xF6E9, "asuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER A */
+ { 0xF6EA, "bsuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER B */
+ { 0xF6EB, "dsuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER D */
+ { 0xF6EC, "esuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER E */
+ { 0xF6ED, "isuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER I */
+ { 0xF6EE, "lsuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER L */
+ { 0xF6EF, "msuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER M */
+ { 0xF6F0, "osuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER O */
+ { 0xF6F1, "rsuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER R */
+ { 0xF6F2, "ssuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER S */
+ { 0xF6F3, "tsuperior" }, /* SUPERSCRIPT LATIN SMALL LETTER T */
+ { 0xF6F4, "Brevesmall" }, /* SMALL CAPITAL BREVE */
+ { 0xF6F5, "Caronsmall" }, /* SMALL CAPITAL CARON */
+ { 0xF6F6, "Circumflexsmall" }, /* SMALL CAPITAL MODIFIER LETTER CIRCUMFLEX ACCENT */
+ { 0xF6F7, "Dotaccentsmall" }, /* SMALL CAPITAL DOT ABOVE */
+ { 0xF6F8, "Hungarumlautsmall" }, /* SMALL CAPITAL DOUBLE ACUTE ACCENT */
+ { 0xF6F9, "Lslashsmall" }, /* LATIN SMALL CAPITAL LETTER L WITH STROKE */
+ { 0xF6FA, "OEsmall" }, /* LATIN SMALL CAPITAL LIGATURE OE */
+ { 0xF6FB, "Ogoneksmall" }, /* SMALL CAPITAL OGONEK */
+ { 0xF6FC, "Ringsmall" }, /* SMALL CAPITAL RING ABOVE */
+ { 0xF6FD, "Scaronsmall" }, /* LATIN SMALL CAPITAL LETTER S WITH CARON */
+ { 0xF6FE, "Tildesmall" }, /* SMALL CAPITAL SMALL TILDE */
+ { 0xF6FF, "Zcaronsmall" }, /* LATIN SMALL CAPITAL LETTER Z WITH CARON */
+ { 0xF721, "exclamsmall" }, /* SMALL CAPITAL EXCLAMATION MARK */
+ { 0xF724, "dollaroldstyle" }, /* OLDSTYLE DOLLAR SIGN */
+ { 0xF726, "ampersandsmall" }, /* SMALL CAPITAL AMPERSAND */
+ { 0xF730, "zerooldstyle" }, /* OLDSTYLE DIGIT ZERO */
+ { 0xF731, "oneoldstyle" }, /* OLDSTYLE DIGIT ONE */
+ { 0xF732, "twooldstyle" }, /* OLDSTYLE DIGIT TWO */
+ { 0xF733, "threeoldstyle" }, /* OLDSTYLE DIGIT THREE */
+ { 0xF734, "fouroldstyle" }, /* OLDSTYLE DIGIT FOUR */
+ { 0xF735, "fiveoldstyle" }, /* OLDSTYLE DIGIT FIVE */
+ { 0xF736, "sixoldstyle" }, /* OLDSTYLE DIGIT SIX */
+ { 0xF737, "sevenoldstyle" }, /* OLDSTYLE DIGIT SEVEN */
+ { 0xF738, "eightoldstyle" }, /* OLDSTYLE DIGIT EIGHT */
+ { 0xF739, "nineoldstyle" }, /* OLDSTYLE DIGIT NINE */
+ { 0xF73F, "questionsmall" }, /* SMALL CAPITAL QUESTION MARK */
+ { 0xF760, "Gravesmall" }, /* SMALL CAPITAL GRAVE ACCENT */
+ { 0xF761, "Asmall" }, /* LATIN SMALL CAPITAL LETTER A */
+ { 0xF762, "Bsmall" }, /* LATIN SMALL CAPITAL LETTER B */
+ { 0xF763, "Csmall" }, /* LATIN SMALL CAPITAL LETTER C */
+ { 0xF764, "Dsmall" }, /* LATIN SMALL CAPITAL LETTER D */
+ { 0xF765, "Esmall" }, /* LATIN SMALL CAPITAL LETTER E */
+ { 0xF766, "Fsmall" }, /* LATIN SMALL CAPITAL LETTER F */
+ { 0xF767, "Gsmall" }, /* LATIN SMALL CAPITAL LETTER G */
+ { 0xF768, "Hsmall" }, /* LATIN SMALL CAPITAL LETTER H */
+ { 0xF769, "Ismall" }, /* LATIN SMALL CAPITAL LETTER I */
+ { 0xF76A, "Jsmall" }, /* LATIN SMALL CAPITAL LETTER J */
+ { 0xF76B, "Ksmall" }, /* LATIN SMALL CAPITAL LETTER K */
+ { 0xF76C, "Lsmall" }, /* LATIN SMALL CAPITAL LETTER L */
+ { 0xF76D, "Msmall" }, /* LATIN SMALL CAPITAL LETTER M */
+ { 0xF76E, "Nsmall" }, /* LATIN SMALL CAPITAL LETTER N */
+ { 0xF76F, "Osmall" }, /* LATIN SMALL CAPITAL LETTER O */
+ { 0xF770, "Psmall" }, /* LATIN SMALL CAPITAL LETTER P */
+ { 0xF771, "Qsmall" }, /* LATIN SMALL CAPITAL LETTER Q */
+ { 0xF772, "Rsmall" }, /* LATIN SMALL CAPITAL LETTER R */
+ { 0xF773, "Ssmall" }, /* LATIN SMALL CAPITAL LETTER S */
+ { 0xF774, "Tsmall" }, /* LATIN SMALL CAPITAL LETTER T */
+ { 0xF775, "Usmall" }, /* LATIN SMALL CAPITAL LETTER U */
+ { 0xF776, "Vsmall" }, /* LATIN SMALL CAPITAL LETTER V */
+ { 0xF777, "Wsmall" }, /* LATIN SMALL CAPITAL LETTER W */
+ { 0xF778, "Xsmall" }, /* LATIN SMALL CAPITAL LETTER X */
+ { 0xF779, "Ysmall" }, /* LATIN SMALL CAPITAL LETTER Y */
+ { 0xF77A, "Zsmall" }, /* LATIN SMALL CAPITAL LETTER Z */
+ { 0xF7A1, "exclamdownsmall" }, /* SMALL CAPITAL INVERTED EXCLAMATION MARK */
+ { 0xF7A2, "centoldstyle" }, /* OLDSTYLE CENT SIGN */
+ { 0xF7A8, "Dieresissmall" }, /* SMALL CAPITAL DIAERESIS */
+ { 0xF7AF, "Macronsmall" }, /* SMALL CAPITAL MACRON */
+ { 0xF7B4, "Acutesmall" }, /* SMALL CAPITAL ACUTE ACCENT */
+ { 0xF7B8, "Cedillasmall" }, /* SMALL CAPITAL CEDILLA */
+ { 0xF7BF, "questiondownsmall" }, /* SMALL CAPITAL INVERTED QUESTION MARK */
+ { 0xF7E0, "Agravesmall" }, /* LATIN SMALL CAPITAL LETTER A WITH GRAVE */
+ { 0xF7E1, "Aacutesmall" }, /* LATIN SMALL CAPITAL LETTER A WITH ACUTE */
+ { 0xF7E2, "Acircumflexsmall" }, /* LATIN SMALL CAPITAL LETTER A WITH CIRCUMFLEX */
+ { 0xF7E3, "Atildesmall" }, /* LATIN SMALL CAPITAL LETTER A WITH TILDE */
+ { 0xF7E4, "Adieresissmall" }, /* LATIN SMALL CAPITAL LETTER A WITH DIAERESIS */
+ { 0xF7E5, "Aringsmall" }, /* LATIN SMALL CAPITAL LETTER A WITH RING ABOVE */
+ { 0xF7E6, "AEsmall" }, /* LATIN SMALL CAPITAL LETTER AE */
+ { 0xF7E7, "Ccedillasmall" }, /* LATIN SMALL CAPITAL LETTER C WITH CEDILLA */
+ { 0xF7E8, "Egravesmall" }, /* LATIN SMALL CAPITAL LETTER E WITH GRAVE */
+ { 0xF7E9, "Eacutesmall" }, /* LATIN SMALL CAPITAL LETTER E WITH ACUTE */
+ { 0xF7EA, "Ecircumflexsmall" }, /* LATIN SMALL CAPITAL LETTER E WITH CIRCUMFLEX */
+ { 0xF7EB, "Edieresissmall" }, /* LATIN SMALL CAPITAL LETTER E WITH DIAERESIS */
+ { 0xF7EC, "Igravesmall" }, /* LATIN SMALL CAPITAL LETTER I WITH GRAVE */
+ { 0xF7ED, "Iacutesmall" }, /* LATIN SMALL CAPITAL LETTER I WITH ACUTE */
+ { 0xF7EE, "Icircumflexsmall" }, /* LATIN SMALL CAPITAL LETTER I WITH CIRCUMFLEX */
+ { 0xF7EF, "Idieresissmall" }, /* LATIN SMALL CAPITAL LETTER I WITH DIAERESIS */
+ { 0xF7F0, "Ethsmall" }, /* LATIN SMALL CAPITAL LETTER ETH */
+ { 0xF7F1, "Ntildesmall" }, /* LATIN SMALL CAPITAL LETTER N WITH TILDE */
+ { 0xF7F2, "Ogravesmall" }, /* LATIN SMALL CAPITAL LETTER O WITH GRAVE */
+ { 0xF7F3, "Oacutesmall" }, /* LATIN SMALL CAPITAL LETTER O WITH ACUTE */
+ { 0xF7F4, "Ocircumflexsmall" }, /* LATIN SMALL CAPITAL LETTER O WITH CIRCUMFLEX */
+ { 0xF7F5, "Otildesmall" }, /* LATIN SMALL CAPITAL LETTER O WITH TILDE */
+ { 0xF7F6, "Odieresissmall" }, /* LATIN SMALL CAPITAL LETTER O WITH DIAERESIS */
+ { 0xF7F8, "Oslashsmall" }, /* LATIN SMALL CAPITAL LETTER O WITH STROKE */
+ { 0xF7F9, "Ugravesmall" }, /* LATIN SMALL CAPITAL LETTER U WITH GRAVE */
+ { 0xF7FA, "Uacutesmall" }, /* LATIN SMALL CAPITAL LETTER U WITH ACUTE */
+ { 0xF7FB, "Ucircumflexsmall" }, /* LATIN SMALL CAPITAL LETTER U WITH CIRCUMFLEX */
+ { 0xF7FC, "Udieresissmall" }, /* LATIN SMALL CAPITAL LETTER U WITH DIAERESIS */
+ { 0xF7FD, "Yacutesmall" }, /* LATIN SMALL CAPITAL LETTER Y WITH ACUTE */
+ { 0xF7FE, "Thornsmall" }, /* LATIN SMALL CAPITAL LETTER THORN */
+ { 0xF7FF, "Ydieresissmall" }, /* LATIN SMALL CAPITAL LETTER Y WITH DIAERESIS */
+ { 0xF8E5, "radicalex" }, /* RADICAL EXTENDER */
+ { 0xF8E6, "arrowvertex" }, /* VERTICAL ARROW EXTENDER */
+ { 0xF8E7, "arrowhorizex" }, /* HORIZONTAL ARROW EXTENDER */
+ { 0xF8E8, "registersans" }, /* REGISTERED SIGN SANS SERIF */
+ { 0xF8E9, "copyrightsans" }, /* COPYRIGHT SIGN SANS SERIF */
+ { 0xF8EA, "trademarksans" }, /* TRADE MARK SIGN SANS SERIF */
+ { 0xF8EB, "parenlefttp" }, /* LEFT PAREN TOP */
+ { 0xF8EC, "parenleftex" }, /* LEFT PAREN EXTENDER */
+ { 0xF8ED, "parenleftbt" }, /* LEFT PAREN BOTTOM */
+ { 0xF8EE, "bracketlefttp" }, /* LEFT SQUARE BRACKET TOP */
+ { 0xF8EF, "bracketleftex" }, /* LEFT SQUARE BRACKET EXTENDER */
+ { 0xF8F0, "bracketleftbt" }, /* LEFT SQUARE BRACKET BOTTOM */
+ { 0xF8F1, "bracelefttp" }, /* LEFT CURLY BRACKET TOP */
+ { 0xF8F2, "braceleftmid" }, /* LEFT CURLY BRACKET MID */
+ { 0xF8F3, "braceleftbt" }, /* LEFT CURLY BRACKET BOTTOM */
+ { 0xF8F4, "braceex" }, /* CURLY BRACKET EXTENDER */
+ { 0xF8F5, "integralex" }, /* INTEGRAL EXTENDER */
+ { 0xF8F6, "parenrighttp" }, /* RIGHT PAREN TOP */
+ { 0xF8F7, "parenrightex" }, /* RIGHT PAREN EXTENDER */
+ { 0xF8F8, "parenrightbt" }, /* RIGHT PAREN BOTTOM */
+ { 0xF8F9, "bracketrighttp" }, /* RIGHT SQUARE BRACKET TOP */
+ { 0xF8FA, "bracketrightex" }, /* RIGHT SQUARE BRACKET EXTENDER */
+ { 0xF8FB, "bracketrightbt" }, /* RIGHT SQUARE BRACKET BOTTOM */
+ { 0xF8FC, "bracerighttp" }, /* RIGHT CURLY BRACKET TOP */
+ { 0xF8FD, "bracerightmid" }, /* RIGHT CURLY BRACKET MID */
+ { 0xF8FE, "bracerightbt" }, /* RIGHT CURLY BRACKET BOTTOM */
+ { 0xFB00, "ff" }, /* LATIN SMALL LIGATURE FF */
+ { 0xFB01, "fi" }, /* LATIN SMALL LIGATURE FI */
+ { 0xFB02, "fl" }, /* LATIN SMALL LIGATURE FL */
+ { 0xFB03, "ffi" }, /* LATIN SMALL LIGATURE FFI */
+ { 0xFB04, "ffl" }, /* LATIN SMALL LIGATURE FFL */
+ { 0xFB05, "$longst" }, /* LATIN SMALL LIGATURE LONG S T */
+ { 0xFB06, "$st" }, /* LATIN SMALL LIGATURE ST */
+ { 0xFB1F, "afii57705" }, /* HEBREW LIGATURE YIDDISH YOD YOD PATAH */
+ { 0xFB2A, "afii57694" }, /* HEBREW LETTER SHIN WITH SHIN DOT */
+ { 0xFB2B, "afii57695" }, /* HEBREW LETTER SHIN WITH SIN DOT */
+ { 0xFB35, "afii57723" }, /* HEBREW LETTER VAV WITH DAGESH */
+ { 0xFB4B, "afii57700" } /* HEBREW LETTER VAV WITH HOLAM */
+};
+#endif /* 0 */
+
+static int
+adobe_name_cmp(const void *s1, const void *s2)
+{
+ const struct adobe2unicode *a = s1;
+ const struct adobe2unicode *b = s2;
+
+ return strcmp(a->adobe_name, b->adobe_name);
+}
+
+#if 0
+static int
+unicode_id_cmp(const void *s1, const void *s2)
+{
+ const struct unicode2adobe *a = s1;
+ const struct unicode2adobe *b = s2;
+
+ return a->unicode - b->unicode;
+}
+#endif /* 0 */
+
+void
+close_iconv(void)
+{
+#if HAVE_ICONV_H
+ if (m_iconv_gb_ucs4 != (iconv_t)(-1)) {
+ iconv_close(m_iconv_gb_ucs4);
+ m_iconv_gb_ucs4 = (iconv_t)(-1);
+ }
+#endif /* HAVE_ICONV_H */
+}
+
+/* convert a CJK char to unicode (UCS-4) using iconv() */
+static uint32_t
+cjk2unicode(const unsigned char *cjk)
+{
+#if HAVE_ICONV_H
+ uint32_t u = 0;
+ unsigned char unicode[4];
+ size_t from = 2;
+ size_t to = sizeof unicode;
+ static Boolean initialized = False;
+ char *from_ptr = (char *)cjk;
+ char *to_ptr = (char *)unicode;
+
+ if (m_iconv_gb_ucs4 == (iconv_t)(-1)) {
+ if (initialized)
+ return 0;
+ initialized = True;
+ m_iconv_gb_ucs4 = iconv_open(
+#ifdef WORDS_BIGENDIAN
+ "UCS-4BE",
+#else
+ "UCS-4LE",
+#endif
+ "GB18030");
+ if (m_iconv_gb_ucs4 == (iconv_t)(-1)) {
+ XDVI_ERROR((stderr, "cjk2unicode: iconv_open() failed: %s", strerror(errno)));
+ return 0;
+ }
+ }
+ if (iconv(m_iconv_gb_ucs4, (iconv_char_pptrT)&from_ptr, &from, &to_ptr, &to) == (size_t)(-1)) {
+ XDVI_ERROR((stderr, "cjk2unicode: can't convert GBK to unicode: %s", strerror(errno)));
+ return 0;
+ }
+ memcpy(&u, unicode, sizeof unicode);
+ return u;
+#else /* HAVE_ICONV_H */
+ static Boolean warned = False;
+
+ if (!warned) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN, NULL, "This version of xdvi has been compiled without iconv support - "
+ "cannot convert CJK character to UTF-8");
+ warned = True;
+ }
+ return 0;
+#endif /* HAVE_ICONV_H */
+}
+
+/*
+ * Return the unicode ID of adobe_name, or 0 if it isn't found.
+ * Uses the lookup table adobe2unicode_table, or iconv for CJK fonts.
+ */
+uint32_t
+adobe2unicode_name(const char *adobe_name)
+{
+ struct adobe2unicode search_item;
+ struct adobe2unicode *match_item;
+
+ if (memcmp(adobe_name, "cjk", 3) == 0) {
+ /* Special case for CJK fonts (Chinese) - ZLB: the Adobe names in
+ * the Chinese T1 fonts are of the form 'cjkXXXX' where 'XXXX' are
+ * the hex number of the GBK/GB18030 encoding */
+ unsigned char cjk[2], xx[3];
+ xx[0] = adobe_name[3];
+ xx[1] = adobe_name[4];
+ xx[2] = '\0';
+ cjk[0] = strtoul((char *)xx, NULL, 16);
+ xx[0] = adobe_name[5];
+ xx[1] = adobe_name[6];
+ cjk[1] = strtoul((char *)xx, NULL, 16);
+ /* convert GBK ==> unicode */
+ return cjk2unicode(cjk);
+ }
+ else {
+ search_item.adobe_name = adobe_name;
+
+ match_item = bsearch(&search_item, adobe2unicode_table,
+ sizeof adobe2unicode_table / sizeof adobe2unicode_table[0],
+ sizeof adobe2unicode_table[0],
+ adobe_name_cmp);
+ if (match_item != NULL)
+ return match_item->unicode;
+ else
+ return 0;
+ }
+}
+
+#if 0
+/*
+ * Return the adobe_name of unicode ID, or NULL if it isn't found.
+ * Uses the lookup table unicode2adobe_table.
+ */
+const char *
+unicode2adobe_name(uint32_t unicode)
+{
+ struct unicode2adobe search_item;
+ struct unicode2adobe *match_item;
+
+ search_item.unicode = unicode;
+
+ match_item = bsearch(&search_item, unicode2adobe_table,
+ sizeof unicode2adobe_table / sizeof unicode2adobe_table[0],
+ sizeof unicode2adobe_table[0],
+ unicode_id_cmp);
+ if (match_item != NULL)
+ return match_item->adobe_name;
+ else
+ return NULL;
+}
+#endif /* 0 */
+
+
+static uint32_t
+ucs4_lowercase(uint32_t c)
+{
+ /*
+ This table was produced by:
+
+ cat uni2adobe | while read a b; do lc_b=`echo $b | tr 'A-Z' 'a-z'`; \
+ if [ "$lc_b" != "$b" ] ; then res=`egrep " $lc_b\$" uni2adobe` ; \
+ if [ -n "$res" ]; then echo "RES: $a $b -> $res"; fi; fi; done | grep 'RES' > uni2adobe-map
+
+ And then, some Emacs keyboard macros.
+ */
+ switch (c) {
+ case 0x0041: /* A */ return 0x0061; /* a */
+ case 0x0042: /* B */ return 0x0062; /* b */
+ case 0x0043: /* C */ return 0x0063; /* c */
+ case 0x0044: /* D */ return 0x0064; /* d */
+ case 0x0045: /* E */ return 0x0065; /* e */
+ case 0x0046: /* F */ return 0x0066; /* f */
+ case 0x0047: /* G */ return 0x0067; /* g */
+ case 0x0048: /* H */ return 0x0068; /* h */
+ case 0x0049: /* I */ return 0x0069; /* i */
+ case 0x004A: /* J */ return 0x006A; /* j */
+ case 0x004B: /* K */ return 0x006B; /* k */
+ case 0x004C: /* L */ return 0x006C; /* l */
+ case 0x004D: /* M */ return 0x006D; /* m */
+ case 0x004E: /* N */ return 0x006E; /* n */
+ case 0x004F: /* O */ return 0x006F; /* o */
+ case 0x0050: /* P */ return 0x0070; /* p */
+ case 0x0051: /* Q */ return 0x0071; /* q */
+ case 0x0052: /* R */ return 0x0072; /* r */
+ case 0x0053: /* S */ return 0x0073; /* s */
+ case 0x0054: /* T */ return 0x0074; /* t */
+ case 0x0055: /* U */ return 0x0075; /* u */
+ case 0x0056: /* V */ return 0x0076; /* v */
+ case 0x0057: /* W */ return 0x0077; /* w */
+ case 0x0058: /* X */ return 0x0078; /* x */
+ case 0x0059: /* Y */ return 0x0079; /* y */
+ case 0x005A: /* Z */ return 0x007A; /* z */
+ case 0x00C0: /* Agrave */ return 0x00E0; /* agrave */
+ case 0x00C1: /* Aacute */ return 0x00E1; /* aacute */
+ case 0x00C2: /* Acircumflex */ return 0x00E2; /* acircumflex */
+ case 0x00C3: /* Atilde */ return 0x00E3; /* atilde */
+ case 0x00C4: /* Adieresis */ return 0x00E4; /* adieresis */
+ case 0x00C5: /* Aring */ return 0x00E5; /* aring */
+ case 0x00C6: /* AE */ return 0x00E6; /* ae */
+ case 0x00C7: /* Ccedilla */ return 0x00E7; /* ccedilla */
+ case 0x00C8: /* Egrave */ return 0x00E8; /* egrave */
+ case 0x00C9: /* Eacute */ return 0x00E9; /* eacute */
+ case 0x00CA: /* Ecircumflex */ return 0x00EA; /* ecircumflex */
+ case 0x00CB: /* Edieresis */ return 0x00EB; /* edieresis */
+ case 0x00CC: /* Igrave */ return 0x00EC; /* igrave */
+ case 0x00CD: /* Iacute */ return 0x00ED; /* iacute */
+ case 0x00CE: /* Icircumflex */ return 0x00EE; /* icircumflex */
+ case 0x00CF: /* Idieresis */ return 0x00EF; /* idieresis */
+ case 0x00D0: /* Eth */ return 0x00F0; /* eth */
+ case 0x00D1: /* Ntilde */ return 0x00F1; /* ntilde */
+ case 0x00D2: /* Ograve */ return 0x00F2; /* ograve */
+ case 0x00D3: /* Oacute */ return 0x00F3; /* oacute */
+ case 0x00D4: /* Ocircumflex */ return 0x00F4; /* ocircumflex */
+ case 0x00D5: /* Otilde */ return 0x00F5; /* otilde */
+ case 0x00D6: /* Odieresis */ return 0x00F6; /* odieresis */
+ case 0x00D8: /* Oslash */ return 0x00F8; /* oslash */
+ case 0x00D9: /* Ugrave */ return 0x00F9; /* ugrave */
+ case 0x00DA: /* Uacute */ return 0x00FA; /* uacute */
+ case 0x00DB: /* Ucircumflex */ return 0x00FB; /* ucircumflex */
+ case 0x00DC: /* Udieresis */ return 0x00FC; /* udieresis */
+ case 0x00DD: /* Yacute */ return 0x00FD; /* yacute */
+ case 0x00DE: /* Thorn */ return 0x00FE; /* thorn */
+ case 0x0100: /* Amacron */ return 0x0101; /* amacron */
+ case 0x0102: /* Abreve */ return 0x0103; /* abreve */
+ case 0x0104: /* Aogonek */ return 0x0105; /* aogonek */
+ case 0x0106: /* Cacute */ return 0x0107; /* cacute */
+ case 0x0108: /* Ccircumflex */ return 0x0109; /* ccircumflex */
+ case 0x010A: /* Cdotaccent */ return 0x010B; /* cdotaccent */
+ case 0x010C: /* Ccaron */ return 0x010D; /* ccaron */
+ case 0x010E: /* Dcaron */ return 0x010F; /* dcaron */
+ case 0x0110: /* Dcroat */ return 0x0111; /* dcroat */
+ case 0x0112: /* Emacron */ return 0x0113; /* emacron */
+ case 0x0114: /* Ebreve */ return 0x0115; /* ebreve */
+ case 0x0116: /* Edotaccent */ return 0x0117; /* edotaccent */
+ case 0x0118: /* Eogonek */ return 0x0119; /* eogonek */
+ case 0x011A: /* Ecaron */ return 0x011B; /* ecaron */
+ case 0x011C: /* Gcircumflex */ return 0x011D; /* gcircumflex */
+ case 0x011E: /* Gbreve */ return 0x011F; /* gbreve */
+ case 0x0120: /* Gdotaccent */ return 0x0121; /* gdotaccent */
+ case 0x0122: /* Gcommaaccent */ return 0x0123; /* gcommaaccent */
+ case 0x0124: /* Hcircumflex */ return 0x0125; /* hcircumflex */
+ case 0x0126: /* Hbar */ return 0x0127; /* hbar */
+ case 0x0128: /* Itilde */ return 0x0129; /* itilde */
+ case 0x012A: /* Imacron */ return 0x012B; /* imacron */
+ case 0x012C: /* Ibreve */ return 0x012D; /* ibreve */
+ case 0x012E: /* Iogonek */ return 0x012F; /* iogonek */
+ case 0x0132: /* IJ */ return 0x0133; /* ij */
+ case 0x0134: /* Jcircumflex */ return 0x0135; /* jcircumflex */
+ case 0x0136: /* Kcommaaccent */ return 0x0137; /* kcommaaccent */
+ case 0x0139: /* Lacute */ return 0x013A; /* lacute */
+ case 0x013B: /* Lcommaaccent */ return 0x013C; /* lcommaaccent */
+ case 0x013D: /* Lcaron */ return 0x013E; /* lcaron */
+ case 0x013F: /* Ldot */ return 0x0140; /* ldot */
+ case 0x0141: /* Lslash */ return 0x0142; /* lslash */
+ case 0x0143: /* Nacute */ return 0x0144; /* nacute */
+ case 0x0145: /* Ncommaaccent */ return 0x0146; /* ncommaaccent */
+ case 0x0147: /* Ncaron */ return 0x0148; /* ncaron */
+ case 0x014A: /* Eng */ return 0x014B; /* eng */
+ case 0x014C: /* Omacron */ return 0x014D; /* omacron */
+ case 0x014E: /* Obreve */ return 0x014F; /* obreve */
+ case 0x0150: /* Ohungarumlaut */ return 0x0151; /* ohungarumlaut */
+ case 0x0152: /* OE */ return 0x0153; /* oe */
+ case 0x0154: /* Racute */ return 0x0155; /* racute */
+ case 0x0156: /* Rcommaaccent */ return 0x0157; /* rcommaaccent */
+ case 0x0158: /* Rcaron */ return 0x0159; /* rcaron */
+ case 0x015A: /* Sacute */ return 0x015B; /* sacute */
+ case 0x015C: /* Scircumflex */ return 0x015D; /* scircumflex */
+ case 0x015E: /* Scedilla */ return 0x015F; /* scedilla */
+ case 0x0160: /* Scaron */ return 0x0161; /* scaron */
+ case 0x0162: /* Tcommaaccent */ return 0x0163; /* tcommaaccent */
+ case 0x0164: /* Tcaron */ return 0x0165; /* tcaron */
+ case 0x0166: /* Tbar */ return 0x0167; /* tbar */
+ case 0x0168: /* Utilde */ return 0x0169; /* utilde */
+ case 0x016A: /* Umacron */ return 0x016B; /* umacron */
+ case 0x016C: /* Ubreve */ return 0x016D; /* ubreve */
+ case 0x016E: /* Uring */ return 0x016F; /* uring */
+ case 0x0170: /* Uhungarumlaut */ return 0x0171; /* uhungarumlaut */
+ case 0x0172: /* Uogonek */ return 0x0173; /* uogonek */
+ case 0x0174: /* Wcircumflex */ return 0x0175; /* wcircumflex */
+ case 0x0176: /* Ycircumflex */ return 0x0177; /* ycircumflex */
+ case 0x0178: /* Ydieresis */ return 0x00FF; /* ydieresis */
+ case 0x0179: /* Zacute */ return 0x017A; /* zacute */
+ case 0x017B: /* Zdotaccent */ return 0x017C; /* zdotaccent */
+ case 0x017D: /* Zcaron */ return 0x017E; /* zcaron */
+ case 0x01A0: /* Ohorn */ return 0x01A1; /* ohorn */
+ case 0x01AF: /* Uhorn */ return 0x01B0; /* uhorn */
+ case 0x01E6: /* Gcaron */ return 0x01E7; /* gcaron */
+ case 0x01FA: /* Aringacute */ return 0x01FB; /* aringacute */
+ case 0x01FC: /* AEacute */ return 0x01FD; /* aeacute */
+ case 0x01FE: /* Oslashacute */ return 0x01FF; /* oslashacute */
+ case 0x0218: /* Scommaaccent */ return 0x0219; /* scommaaccent */
+ case 0x0386: /* Alphatonos */ return 0x03AC; /* alphatonos */
+ case 0x0388: /* Epsilontonos */ return 0x03AD; /* epsilontonos */
+ case 0x0389: /* Etatonos */ return 0x03AE; /* etatonos */
+ case 0x038A: /* Iotatonos */ return 0x03AF; /* iotatonos */
+ case 0x038C: /* Omicrontonos */ return 0x03CC; /* omicrontonos */
+ case 0x038E: /* Upsilontonos */ return 0x03CD; /* upsilontonos */
+ case 0x038F: /* Omegatonos */ return 0x03CE; /* omegatonos */
+ case 0x0391: /* Alpha */ return 0x03B1; /* alpha */
+ case 0x0392: /* Beta */ return 0x03B2; /* beta */
+ case 0x0393: /* Gamma */ return 0x03B3; /* gamma */
+ case 0x0395: /* Epsilon */ return 0x03B5; /* epsilon */
+ case 0x0396: /* Zeta */ return 0x03B6; /* zeta */
+ case 0x0397: /* Eta */ return 0x03B7; /* eta */
+ case 0x0398: /* Theta */ return 0x03B8; /* theta */
+ case 0x0399: /* Iota */ return 0x03B9; /* iota */
+ case 0x039A: /* Kappa */ return 0x03BA; /* kappa */
+ case 0x039B: /* Lambda */ return 0x03BB; /* lambda */
+ case 0x039C: /* Mu */ return 0x00B5; /* mu */
+ case 0x039D: /* Nu */ return 0x03BD; /* nu */
+ case 0x039E: /* Xi */ return 0x03BE; /* xi */
+ case 0x039F: /* Omicron */ return 0x03BF; /* omicron */
+ case 0x03A0: /* Pi */ return 0x03C0; /* pi */
+ case 0x03A1: /* Rho */ return 0x03C1; /* rho */
+ case 0x03A3: /* Sigma */ return 0x03C3; /* sigma */
+ case 0x03A4: /* Tau */ return 0x03C4; /* tau */
+ case 0x03A5: /* Upsilon */ return 0x03C5; /* upsilon */
+ case 0x03A6: /* Phi */ return 0x03C6; /* phi */
+ case 0x03A7: /* Chi */ return 0x03C7; /* chi */
+ case 0x03A8: /* Psi */ return 0x03C8; /* psi */
+ case 0x03AA: /* Iotadieresis */ return 0x03CA; /* iotadieresis */
+ case 0x03AB: /* Upsilondieresis */ return 0x03CB; /* upsilondieresis */
+ case 0x1E80: /* Wgrave */ return 0x1E81; /* wgrave */
+ case 0x1E82: /* Wacute */ return 0x1E83; /* wacute */
+ case 0x1E84: /* Wdieresis */ return 0x1E85; /* wdieresis */
+ case 0x1EF2: /* Ygrave */ return 0x1EF3; /* ygrave */
+ case 0x2126: /* Omega */ return 0x03C9; /* omega */
+ case 0x2206: /* Delta */ return 0x03B4; /* delta */
+ case 0xF6BF: /* LL */ return 0xF6C0; /* ll */
+ case 0xF6C9: /* Acute */ return 0x00B4; /* acute */
+ case 0xF6CA: /* Caron */ return 0x02C7; /* caron */
+ case 0xF6CB: /* Dieresis */ return 0x00A8; /* dieresis */
+ case 0xF6CC: /* DieresisAcute */ return 0xF6D7; /* dieresisacute */
+ case 0xF6CD: /* DieresisGrave */ return 0xF6D8; /* dieresisgrave */
+ case 0xF6CE: /* Grave */ return 0x0060; /* grave */
+ case 0xF6CF: /* Hungarumlaut */ return 0x02DD; /* hungarumlaut */
+ case 0xF6D0: /* Macron */ return 0x00AF; /* macron */
+ case 0xF6D1: /* cyrBreve */ return 0xF6D4; /* cyrbreve */
+ case 0xF6D2: /* cyrFlex */ return 0xF6D5; /* cyrflex */
+ case 0xF6D3: /* dblGrave */ return 0xF6D6; /* dblgrave */
+ default: return c;
+ }
+}
+
+/*
+ * For the unicode IDs of an accent and a base_glyph, return the
+ * unicode ID of the composed (accented) glyph. If there is no
+ * suitable composed glyph, return 0.
+ */
+uint32_t
+get_accented_glyph(uint32_t accent, uint32_t base_glyph)
+{
+ TRACE_FIND((stderr, "get_accented_glyph: %lu, %lu",
+ (unsigned long)accent, (unsigned long)base_glyph));
+ switch(accent) {
+ case 0x0060: /* grave */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x00C0;
+ case 0x0045: /* E */ return 0x00C8;
+ case 0x0049: /* I */ return 0x00CC;
+ case 0x004F: /* O */ return 0x00D2;
+ case 0x0055: /* U */ return 0x00D9;
+ case 0x0057: /* W */ return 0x1E80;
+ case 0x0059: /* Y */ return 0x1EF2;
+ case 0x0061: /* a */ return 0x00E0;
+ case 0x0065: /* e */ return 0x00E8;
+ case 0x0069: /* i */ return 0x00EC;
+ case 0x006F: /* o */ return 0x00F2;
+ case 0x0075: /* u */ return 0x00F9;
+ case 0x0077: /* w */ return 0x1E81;
+ case 0x0079: /* y */ return 0x1EF3;
+ default: return 0;
+ }
+ case 0x00B4: /* acute */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x00C1;
+ case 0x0043: /* C */ return 0x0106;
+ case 0x0045: /* E */ return 0x00C9;
+ case 0x0049: /* I */ return 0x00CD;
+ case 0x004C: /* L */ return 0x0139;
+ case 0x004E: /* N */ return 0x0143;
+ case 0x004F: /* O */ return 0x00D3;
+ case 0x0052: /* R */ return 0x0154;
+ case 0x0053: /* S */ return 0x015A;
+ case 0x0055: /* U */ return 0x00DA;
+ case 0x0057: /* W */ return 0x1E82;
+ case 0x0059: /* Y */ return 0x00DD;
+ case 0x0060: /* Z */ return 0x0179;
+ case 0x0061: /* a */ return 0x00E1;
+ case 0x0063: /* c */ return 0x0107;
+ case 0x0065: /* e */ return 0x00E9;
+ case 0x0069: /* i */ return 0x00ED;
+ case 0x006C: /* l */ return 0x013A;
+ case 0x006E: /* n */ return 0x0144;
+ case 0x006F: /* o */ return 0x00F3;
+ case 0x0072: /* r */ return 0x0155;
+ case 0x0073: /* s */ return 0x015B;
+ case 0x0075: /* u */ return 0x00FA;
+ case 0x0077: /* w */ return 0x1E83;
+ case 0x0079: /* y */ return 0x00FD;
+ case 0x0080: /* z */ return 0x017A;
+ default: return 0;
+ }
+ case 0x02C6: /* circumflex */
+ case 0x005E: /* asciicircum */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x00C2;
+ case 0x0045: /* E */ return 0x00CA;
+ case 0x0047: /* G */ return 0x011C;
+ case 0x0048: /* H */ return 0x0124;
+ case 0x0049: /* I */ return 0x00CE;
+ case 0x0050: /* H */ return 0x0124;
+ case 0x004F: /* O */ return 0x00D4;
+ case 0x0055: /* U */ return 0x00DB;
+ case 0x0061: /* a */ return 0x00E2;
+ case 0x0065: /* e */ return 0x00EA;
+ case 0x0067: /* g */ return 0x011D;
+ case 0x0068: /* h */ return 0x0125;
+ case 0x0069: /* i */ return 0x00EE;
+ case 0x0070: /* j */ return 0x0135;
+ case 0x006F: /* o */ return 0x00F4;
+ case 0x0075: /* u */ return 0x00FB;
+ default: return 0;
+ }
+ case 0x02DC: /* tilde */
+ case 0x007E: /* asciitilde */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x00C3;
+ case 0x0049: /* I */ return 0x0128;
+ case 0x004E: /* N */ return 0x00D1;
+ case 0x004F: /* O */ return 0x00D5;
+ case 0x0055: /* U */ return 0x0168;
+ case 0x0061: /* a */ return 0x00E3;
+ case 0x0069: /* i */ return 0x0129;
+ case 0x006E: /* n */ return 0x00F1;
+ case 0x006F: /* o */ return 0x00F5;
+ case 0x0075: /* u */ return 0x0169;
+ default: return 0;
+ }
+ case 0x00A8: /* dieresis */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x00C4;
+ case 0x0045: /* E */ return 0x00CB;
+ case 0x0049: /* I */ return 0x00CF;
+ case 0x004F: /* O */ return 0x00D6;
+ case 0x0055: /* U */ return 0x00DC;
+ case 0x0057: /* w */ return 0x1E84;
+ case 0x0061: /* a */ return 0x00E4;
+ case 0x0065: /* e */ return 0x00EB;
+ case 0x0069: /* i */ return 0x00EF;
+ case 0x006F: /* o */ return 0x00F6;
+ case 0x0075: /* u */ return 0x00FC;
+ case 0x0077: /* w */ return 0x1E85;
+ case 0x0079: /* y */ return 0x00FF;
+ default: return 0;
+ }
+ case 0x02DA: /* ring */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x00C5;
+ case 0x0061: /* a */ return 0x00E5;
+ case 0x0055: /* U */ return 0x016E;
+ case 0x0075: /* u */ return 0x016F;
+ default: return 0;
+ }
+ case 0x00B8: /* cedilla */
+ switch (base_glyph) {
+ case 0x0043: /* C */ return 0x00C7;
+ case 0x0063: /* c */ return 0x00E7;
+ case 0x0053: /* S */ return 0x015E;
+ case 0x0073: /* s */ return 0x015F;
+ default: return 0;
+ }
+ case 0x02DB: /* ogonek */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x0104;
+ case 0x0045: /* E */ return 0x0118;
+ case 0x0049: /* I */ return 0x012E;
+ case 0x0055: /* U */ return 0x0172;
+ case 0x0061: /* a */ return 0x0105;
+ case 0x0065: /* e */ return 0x0119;
+ case 0x0069: /* i */ return 0x012F;
+ case 0x006F: /* o */ return 0x02DB;
+ case 0x0075: /* u */ return 0x0173;
+ default: return 0;
+ }
+ case 0x002F: /* solidus */
+ switch (base_glyph) {
+ case 0x004C: /* L */ return 0x0141;
+ case 0x004F: /* O */ return 0x00D8;
+ case 0x006C: /* l */ return 0x0142;
+ case 0x006F: /* o */ return 0x00F8;
+ default: return 0;
+ }
+ case 0x02C7: /* caron */
+ switch (base_glyph) {
+ case 0x0043: /* C */ return 0x010C;
+ case 0x0044: /* D */ return 0x010E;
+ case 0x0045: /* E */ return 0x011A;
+ case 0x0047: /* G */ return 0x01E6;
+ case 0x004C: /* L */ return 0x013D;
+ case 0x004E: /* N */ return 0x0147;
+ case 0x0052: /* R */ return 0x0158;
+ case 0x0053: /* S */ return 0x0160;
+ case 0x0054: /* T */ return 0x0164;
+ case 0x005A: /* Z */ return 0x017D;
+ case 0x0063: /* c */ return 0x010D;
+ case 0x0064: /* d */ return 0x010F;
+ case 0x0065: /* e */ return 0x011B;
+ case 0x0067: /* g */ return 0x01E7;
+ case 0x006C: /* l */ return 0x013E;
+ case 0x006E: /* n */ return 0x0148;
+ case 0x0072: /* r */ return 0x0159;
+ case 0x0073: /* s */ return 0x0161;
+ case 0x0074: /* t */ return 0x0165;
+ case 0x007A: /* z */ return 0x017E;
+ default: return 0;
+ }
+ case 0x02D8: /* breve */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x0102;
+ case 0x0045: /* E */ return 0x0114;
+ case 0x0047: /* G */ return 0x011E;
+ case 0x0049: /* I */ return 0x012C;
+ case 0x004F: /* O */ return 0x014E;
+ case 0x0055: /* U */ return 0x016C;
+ case 0x0061: /* a */ return 0x0103;
+ case 0x0065: /* e */ return 0x0115;
+ case 0x0067: /* g */ return 0x011F;
+ case 0x0069: /* i */ return 0x012D;
+ case 0x006F: /* o */ return 0x014F;
+ case 0x0075: /* u */ return 0x016D;
+ default: return 0;
+ }
+ case 0x02DD: /* hungarumlaut */
+ switch (base_glyph) {
+ case 0x004F: /* O */ return 0x0150;
+ case 0x0055: /* U */ return 0x0170;
+ case 0x006F: /* o */ return 0x0151;
+ case 0x0075: /* u */ return 0x0171;
+ default: return 0;
+ }
+ case 0x00AF: /* macron */
+ switch (base_glyph) {
+ case 0x0041: /* A */ return 0x0100;
+ case 0x0045: /* E */ return 0x0112;
+ case 0x0049: /* I */ return 0x012A;
+ case 0x004F: /* O */ return 0x014C;
+ case 0x0055: /* U */ return 0x016A;
+ case 0x0061: /* a */ return 0x0101;
+ case 0x0065: /* e */ return 0x0113;
+ case 0x0069: /* i */ return 0x012B;
+ case 0x006D: /* m */ return 0x00AF;
+ case 0x006F: /* o */ return 0x014D;
+ case 0x0075: /* u */ return 0x016B;
+ default: return 0;
+ }
+ /* special cases: accent - char inverted */
+ case 0x0043: /* C; special case: cedilla is set after C in OT1 */
+ switch (base_glyph) {
+ case 0x00B8: /* cedilla */ return 0x00C7;
+ default: return 0;
+ }
+ case 0x0063: /* c; see above */
+ switch (base_glyph) {
+ case 0x00B8: /* cedilla */ return 0x00E7;
+ default: return 0;
+ }
+ case 0x0053: /* S; see above */
+ switch (base_glyph) {
+ case 0x00B8: /* cedilla */ return 0x015E;
+ default: return 0;
+ }
+ case 0x0073: /* s; see above */
+ switch (base_glyph) {
+ case 0x00B8: /* cedilla */ return 0x015F;
+ default: return 0;
+ }
+ }
+ return 0;
+}
+
+uint32_t
+guess_encoding(wide_ubyte ch, const char *fontname, char *retbuf)
+{
+ uint32_t i;
+ static hashTableT unknown_font_hash;
+ static Boolean hash_initialized = False;
+ size_t dummy = 0;
+
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: |%s|, char 0x%.4X", fontname, ch));
+
+ /* our encoding vectors only have size 256 */
+ if (ch > 255) {
+ XDVI_WARNING((stderr, "guess_encoding: font index %lu too large", (unsigned long)ch));
+ return 0;
+ }
+
+ if (memcmp(fontname, "gbk", 3) == 0
+ && isdigit((int)fontname[(i=strlen(fontname))-1])
+ && isdigit((int)fontname[i-2])) {
+ unsigned char cjk[2];
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: CJK fonts (GBK encoding)"));
+ i = atoi(fontname + i - 2); /* font no */
+ i = (i - 1) * 256 + (uint32_t)ch; /* char index */
+ cjk[0] = i / 190 + 129;
+ cjk[1] = i % 190 + 64;
+ if (cjk[1] >= 128)
+ cjk[1]++;
+ return cjk2unicode(cjk);
+ }
+
+ if (memcmp(fontname, "cmsy", 4) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_cm_symbol", fontname));
+ return m_cm_symbol_encoding[ch];
+ }
+ if (memcmp(fontname, "cmmi", 4) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_cm_math_italics", fontname));
+ return m_cm_math_italics_encoding[ch];
+ }
+ if (memcmp(fontname, "cmex", 4) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_cm_math_extended", fontname));
+ return m_cm_math_extended_encoding[ch];
+ }
+ if (memcmp(fontname, "cmtt", 4) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_cm_typewriter", fontname));
+ return m_cm_typewriter_encoding[ch];
+ }
+ /* following to cover cmsl, cmb, cmbx, cmti, cmdunghill, whatever ...
+ hope it doesn't overgenerate ;-) */
+ if (memcmp(fontname, "cm", 2) == 0
+ || memcmp(fontname, "lcmss", strlen("lcmss")) == 0 /* lcmss8 etc. */
+ || memcmp(fontname, "ygoth", strlen("ygoth")) == 0
+ || memcmp(fontname, "yinit", strlen("yinit")) == 0
+ || memcmp(fontname, "logo", strlen("logo")) == 0
+ || memcmp(fontname, "rsfs", strlen("rsfs")) == 0
+ ) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_ot1", fontname));
+ return m_ot1_encoding[ch];
+ }
+ /* cyrillic fonts */
+ if (memcmp(fontname, "la", 2) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_t2", fontname));
+ return m_t2_encoding[ch];
+ }
+ if (memcmp(fontname, "ec", 2) == 0
+ || memcmp(fontname, "eb", 2) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_cork", fontname));
+ /* FIXME: why cork and not EC? What font actually uses EC?
+ The only difference seems that dvips' EC.enc has `ldot' at 0xb8,
+ whereas cork.enc has `ydieresis' there. A document with
+ \usepackage[T1]{fontenc}
+ also produces a ydieresis.
+ */
+ return m_cork_encoding[ch];
+ }
+ if (memcmp(fontname, "tc", 2) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_ts1", fontname));
+ return m_ts1_encoding[ch];
+ }
+ /* blackletter fonts with funny encoding */
+ if (memcmp(fontname, "ysmfrak", 7) == 0
+ || memcmp(fontname, "yswab", 5) == 0) {
+ TRACE_FIND_VERBOSE((stderr, "guess_encoding: %s => m_yfrak", fontname));
+ /* special cases for ligatures */
+ switch (ch) {
+ case 0x85: strcpy(retbuf, "ch"); return 0;
+ case 0x86: strcpy(retbuf, "ck"); return 0;
+ case 0xA7: strcpy(retbuf, "sz"); return 0;
+ default: return m_yfrak_encoding[ch];
+ }
+ }
+
+ /* euler mathematical */
+ if (memcmp(fontname, "eufm", strlen("eufm")) == 0
+ || memcmp(fontname, "eusm", strlen("eufm")) == 0
+ ) {
+ switch (ch) {
+ case 0x0: case 0x1: return 'd'; break;
+ case 0x2: case 0x3: return 'f'; break;
+ case 0x4: return 'g'; break;
+ case 0x5: return 'k'; break;
+ case 0x6: return 't'; break;
+ case 0x7: return 'u'; break;
+ default: return m_ot1_encoding[ch];
+ }
+ }
+
+
+ /* stuff that doesn't have a good ASCII representation */
+ if (memcmp(fontname, "lcircle", strlen("lcircle")) == 0
+ || memcmp(fontname, "line", strlen("line")) == 0
+ || memcmp(fontname, "fmvr8x", strlen("fmvr8x")) == 0
+ || memcmp(fontname, "feymr", strlen("feymr")) == 0
+ || memcmp(fontname, "msbm", strlen("msbm")) == 0
+ || memcmp(fontname, "msam", strlen("msam")) == 0
+ || memcmp(fontname, "wasy", strlen("wasy")) == 0
+ || memcmp(fontname, "txsy", strlen("txsy")) == 0
+ ) {
+ return 0;
+ }
+
+ /* TODO:
+ txfonts
+ */
+
+ /* default: assume cork encoding, and print out a warning for each font */
+ if (!hash_initialized) {
+ unknown_font_hash = hash_create(1031);
+ hash_initialized = True;
+ }
+ if (!find_str_int_hash(&unknown_font_hash, fontname, &dummy)) {
+ XDVI_WARNING((stderr,
+ "guess_encoding(): nothing suitable for \"%s\", assuming Cork encoding.\n"
+ "(Please tell us about this at "
+ "http://sourceforge.net/tracker/?group_id=23164&atid=377580)", fontname));
+ put_str_int_hash(&unknown_font_hash, fontname, dummy);
+ }
+ return m_cork_encoding[ch];
+}
+
+/*
+ Mapping of unicode glyphs to ASCII `equivalents'
+ that are useful when searching for text.
+*/
+const char *
+search_normalize_chars(uint32_t unicode)
+{
+ const char *ret = NULL;
+ switch(unicode) {
+ case 0x2212: ret = "-"; break;
+ case 0x2022: ret = "\xb7"; break; /* middle dot */
+ default: ret = NULL; break;
+ }
+ if (ret != NULL) {
+ TRACE_FIND((stderr, "expand_searchchars: 0x%X --> `%s'",
+ (unsigned int)unicode, ret));
+ }
+ return ret;
+}
+
+/*
+ Expand a unicode ligature character consisting of several
+ `ordinary' characters to a string of those characters, and
+ map some unicode glyphs to ASCII `equivalents'.
+
+ TODO: move the more ambiguous replacements (e.g.
+ guilsinglleft vs. angleleft) into a user-defined table?
+*/
+const char *
+expand_ligature(uint32_t unicode)
+{
+ const char *ret = NULL;
+ switch(unicode) {
+ case 0xFB00: ret = "ff"; break;
+ case 0xFB01: ret = "fi"; break;
+ case 0xFB02: ret = "fl"; break;
+ case 0xFB03: ret = "ffi"; break;
+ case 0xFB04: ret = "ffl"; break;
+ case 0xFB06: ret = "st"; break;
+ case 0x0133: ret = "ij"; break;
+ case 0x2013: ret = "--"; break;
+ case 0x2014: ret = "---"; break;
+ case 0x2039:
+ case 0x2329: ret = "<"; break;
+ case 0x203A:
+ case 0x232A: ret = ">"; break;
+ case 0x2018: ret = "`"; break;
+ case 0x2019: ret = "'"; break;
+ case 0x201C: ret = "``"; break;
+ case 0x201D: ret = "''"; break;
+ case 0x2026: ret = "..."; break;
+ case 0x10ff28: ret = "{"; break;
+ case 0x10ff29: ret = "}"; break;
+ default: ret = NULL; break;
+ }
+ if (ret != NULL) {
+ TRACE_FIND((stderr, "expand_ligature: 0x%X --> `%s'",
+ (unsigned int)unicode, ret));
+ }
+ return ret;
+}
+
+/*
+ * Convert the utf8-string passed as argument to lowercase, by
+ * first converting to UCS4, then converting back, lowercasing the
+ * UCS4 characters as we go (it's easier like that).
+ */
+Boolean
+utf8_lowercase(char *utf8)
+{
+ size_t utf8_len = strlen(utf8) + 1; /* also convert terminating byte (acutally not needed ...) */
+ size_t ucs4_len = utf8_len * 6; /* ample ... */
+ int i = 0;
+ uint32_t *ucs4 = xmalloc(ucs4_len);
+ uint32_t *ucs4_start = ucs4; /* save for free()ing */
+ for (; *utf8 != '\0'; ucs4++, utf8 += i) {
+ size_t conv_len;
+ if ((i = utf8_to_ucs4(utf8, ucs4, 6 /* don't care about character len */)) < 0) {
+ XDVI_ERROR((stderr, "Error in utf8_lowercase: Illegal UTF-8 sequence"));
+ free(ucs4_start);
+ return False;
+ }
+ ucs4_to_utf8(*ucs4, utf8, &conv_len, True); /* lowercases it */
+ if ((int)conv_len != i) {
+ XDVI_ERROR((stderr, "Error in utf8_lowercase: length after UCS4 conversion (%lu)\n"
+ "differs from length after utf8 conversion(%lu) (string: %s)\n",
+ (unsigned long)conv_len, (unsigned long)i, utf8));
+ free(ucs4_start);
+ return False;
+ }
+ }
+ free(ucs4_start);
+ return True;
+}
+
+/*
+ * Adapted from iconv's utf8_wctomb in lib/utf8.h
+ * Converts the character sequence pointed to by utf8 of maximum length `len'
+ * into an UCS4 character pointed to by ucs4.
+ * TODO: maybe implement this as a macro??
+ */
+int
+utf8_to_ucs4(const char *utf8, uint32_t *ucs4, size_t len)
+{
+ const unsigned char *str = (const unsigned char *)utf8;
+ unsigned char c = *str;
+
+ if (c < 0x80) {
+ *ucs4 = c;
+ return 1;
+ }
+ else if (c < 0xc2) {
+ return -1; /* illegal UTF8; shouldn't happen */
+ }
+ else if (c < 0xe0) {
+ if (len < 2)
+ return -1; /* len too short */
+ if (!((str[1] ^ 0x80) < 0x40)) {
+ return -1; /* illegal UTF8; shouldn't happen */
+ }
+ *ucs4 = ((uint32_t) (c & 0x1f) << 6)
+ | (uint32_t) (str[1] ^ 0x80);
+ return 2;
+ }
+ else if (c < 0xf0) {
+ if (len < 3)
+ return -1; /* len too short */
+ if (!((str[1] ^ 0x80) < 0x40
+ && (str[2] ^ 0x80) < 0x40
+ && (c >= 0xe1 || str[1] >= 0xa0))) {
+ return -1; /* illegal UTF8; shouldn't happen */
+ }
+ *ucs4 = ((uint32_t) (c & 0x0f) << 12)
+ | ((uint32_t) (str[1] ^ 0x80) << 6)
+ | (uint32_t) (str[2] ^ 0x80);
+ return 3;
+ }
+ else if (c < 0xf8 && sizeof(uint32_t) * 8 >= 32) {
+ if (len < 4)
+ return -1; /* len too short */
+ if (!((str[1] ^ 0x80) < 0x40
+ && (str[2] ^ 0x80) < 0x40
+ && (str[3] ^ 0x80) < 0x40
+ && (c >= 0xf1 || str[1] >= 0x90))) {
+ return -1; /* illegal UTF8; shouldn't happen */
+ }
+ *ucs4 = ((uint32_t) (c & 0x07) << 18)
+ | ((uint32_t) (str[1] ^ 0x80) << 12)
+ | ((uint32_t) (str[2] ^ 0x80) << 6)
+ | (uint32_t) (str[3] ^ 0x80);
+ return 4;
+ }
+ else if (c < 0xfc && sizeof(uint32_t)*8 >= 32) {
+ if (len < 5)
+ return -1; /* len too short */
+ if (!((str[1] ^ 0x80) < 0x40
+ && (str[2] ^ 0x80) < 0x40
+ && (str[3] ^ 0x80) < 0x40
+ && (str[4] ^ 0x80) < 0x40
+ && (c >= 0xf9 || str[1] >= 0x88))) {
+ return -1; /* illegal UTF8; shouldn't happen */
+ }
+ *ucs4 = ((uint32_t) (c & 0x03) << 24)
+ | ((uint32_t) (str[1] ^ 0x80) << 18)
+ | ((uint32_t) (str[2] ^ 0x80) << 12)
+ | ((uint32_t) (str[3] ^ 0x80) << 6)
+ | (uint32_t) (str[4] ^ 0x80);
+ return 5;
+ }
+ else if (c < 0xfe && sizeof(uint32_t)*8 >= 32) {
+ if (len < 6)
+ return -1; /* len too short */
+ if (!((str[1] ^ 0x80) < 0x40
+ && (str[2] ^ 0x80) < 0x40
+ && (str[3] ^ 0x80) < 0x40
+ && (str[4] ^ 0x80) < 0x40
+ && (str[5] ^ 0x80) < 0x40
+ && (c >= 0xfd || str[1] >= 0x84))) {
+ return -1; /* illegal UTF8; shouldn't happen */
+ }
+ *ucs4 = ((uint32_t) (c & 0x01) << 30)
+ | ((uint32_t) (str[1] ^ 0x80) << 24)
+ | ((uint32_t) (str[2] ^ 0x80) << 18)
+ | ((uint32_t) (str[3] ^ 0x80) << 12)
+ | ((uint32_t) (str[4] ^ 0x80) << 6)
+ | (uint32_t) (str[5] ^ 0x80);
+ return 6;
+ }
+ else {
+ return -1; /* illegal UTF8 */
+ }
+}
+
+/* adapted from iconv's utf8_wctomb in lib/utf8.h */
+/* TODO: maybe implement this as a macro?? */
+void
+ucs4_to_utf8(uint32_t ucs4, char *utf8, size_t *len, Boolean do_lowercase)
+{
+ if (do_lowercase)
+ ucs4 = ucs4_lowercase(ucs4);
+
+ if (ucs4 < 0x80)
+ *len = 1;
+ else if (ucs4 < 0x800)
+ *len = 2;
+ else if (ucs4 < 0x10000)
+ *len = 3;
+ else if (ucs4 < 0x200000)
+ *len = 4;
+ else if (ucs4 < 0x4000000)
+ *len = 5;
+ else if (ucs4 <= 0x7fffffff)
+ *len = 6;
+
+ switch(*len) { /* note: code falls through cases! */
+ case 6: utf8[5] = 0x80 | (ucs4 & 0x3f); ucs4 = ucs4 >> 6; ucs4 |= 0x4000000;
+ case 5: utf8[4] = 0x80 | (ucs4 & 0x3f); ucs4 = ucs4 >> 6; ucs4 |= 0x200000;
+ case 4: utf8[3] = 0x80 | (ucs4 & 0x3f); ucs4 = ucs4 >> 6; ucs4 |= 0x10000;
+ case 3: utf8[2] = 0x80 | (ucs4 & 0x3f); ucs4 = ucs4 >> 6; ucs4 |= 0x800;
+ case 2: utf8[1] = 0x80 | (ucs4 & 0x3f); ucs4 = ucs4 >> 6; ucs4 |= 0xc0;
+ case 1: utf8[0] = ucs4;
+ }
+}
+
+
+
+/*
+ * (Lossy) conversion of utf8 sequence to an iso-latin1; produces
+ * `?' if the character is not representable in iso-latin1.
+ * Returns the number of converted characters in `len'.
+ */
+unsigned char
+utf8_to_iso_8859_1(const char *utf8, size_t *len)
+{
+ unsigned char c = *utf8;
+ uint32_t wc;
+
+ if (c < 0x80) {
+ *len = 1;
+ return c;
+ }
+ else if (c < 0xe0) {
+ *len = 2;
+ wc = ((unsigned char)(c & 0x1f) << 6) | (unsigned char)(utf8[1] ^ 0x80);
+ if (wc <= 0xff)
+ return (unsigned char)wc;
+ else
+ return '?';
+ }
+ else if (c < 0xf0) {
+ *len = 3;
+ return '?';
+ }
+ else if (c < 0xf8) {
+ *len = 4;
+ return '?';
+ }
+ else if (c < 0xfc) {
+ *len = 5;
+ return '?';
+ }
+ else if (c < 0xfe) {
+ *len = 6;
+ return '?';
+ }
+ else
+ return '?';
+}
+
+/* convert an iso_8859_1 character to utf8, writing the result
+ to the buffer `utf8' (which should have at least length 2),
+ and storing the length of the converted utf-8 sequence in *len.
+*/
+void
+iso_8859_1_to_utf8(unsigned char c, char *utf8, size_t *len)
+{
+ if (c < 0x80) {
+ *len = 1;
+ utf8[0] = c;
+ }
+ else {
+ *len = 2;
+ utf8[1] = 0x80 | (c & 0x3f);
+ c >>= 6;
+ utf8[0] = 0xc0 | (c & 0x1f);
+ }
+}
+
+/* Convert an iso_latin-1 string to a UTF-8 string (including the
+ terminating `\0'), not writing more than `len' characters to
+ `utf8'. Returns the number of written characters, or -1 if len was
+ too small to convert the entire input string.
+*/
+int
+str_iso_8859_1_to_utf8(const char *latin1, char *utf8, size_t len)
+{
+ size_t i = 0;
+
+ while (i < len && *latin1 != '\0') {
+ char tmpbuf[2];
+ size_t tmp_len = 0;
+ iso_8859_1_to_utf8((unsigned char)*latin1, tmpbuf, &tmp_len);
+ if (i + tmp_len >= len)
+ return -1;
+ memcpy(utf8 + i, tmpbuf, tmp_len);
+ i += tmp_len;
+ latin1++;
+ }
+ /* terminate utf8 */
+ if (i < len)
+ utf8[i++] = '\0';
+ else
+ return -1;
+
+ return i;
+}
+
+Boolean
+is_hyphenchar(uint32_t u)
+{
+ if (u == 0x002D || u == 0x00AD)
+ return True;
+ return False;
+}
+
+/*
+ * Determine ideographic property according to
+ * http://www.unicode.org/Public/UNIDATA/PropList.txt:
+ *
+ * 3006 ; Ideographic # Lo IDEOGRAPHIC CLOSING MARK
+ * 3007 ; Ideographic # Nl IDEOGRAPHIC NUMBER ZERO
+ * 3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+ * 3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+ * 3400..4DB5 ; Ideographic # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+ * 4E00..9FA5 ; Ideographic # Lo [20902] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FA5
+ * F900..FA2D ; Ideographic # Lo [302] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA2D
+ * 20000..2A6D6 ; Ideographic # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+ * 2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+ *
+ * # Total code points: 71053
+ *
+ * plus space, comma and full stop.
+ *
+ */
+Boolean
+is_ideograph(uint32_t u)
+{
+ return (u >= 0x3000 && u <= 0x3002) || /* IDEOGRAPHIC SPACE, COMMA, FULL STOP */
+ u == 0xFF61 || /* HALFWIDTH IDEOGRAPHIC FULL STOP */
+ u == 0xFF64 || /* HALFWIDTH IDEOGRAPHIC COMMA */
+ (u >= 0x3006 && u <= 0x3007) ||
+ (u >= 0x3021 && u <= 0x3029) ||
+ (u >= 0x3038 && u <= 0x303A) ||
+ (u >= 0x3400 && u <= 0x4DB5) ||
+ (u >= 0x4E00 && u <= 0x9FA5) ||
+ (u >= 0xF900 && u <= 0xFA2D) ||
+ (u >= 0x20000 && u <= 0x2A6D6) ||
+ (u >= 0x2F800 && u <= 0x2FA1D);
+}
+
+char *
+str_utf8_to_iso_8859_1(const char *utf8)
+{
+ size_t utf8_len = strlen(utf8), i = 0, offset = 0;
+ char *buf = xmalloc(4 * utf8_len + 1); /* worst case of non-printables */
+
+ while (i < utf8_len) {
+ uint32_t ucs4;
+ const char *ret;
+
+ /* fprintf(stderr, "offset: %d\n", (int)offset); */
+ /* first apply normalization heurisitcs also used by search */
+ size_t len = utf8_to_ucs4(utf8 + i, &ucs4, utf8_len + 1);
+ if ((ret = search_normalize_chars(ucs4)) != NULL) {
+ size_t len_ret = strlen(ret);
+ memcpy(buf + offset, ret, len_ret);
+ offset += len_ret;
+ }
+ else if (ucs4 <= 0xff) { /* in iso-latin1 range */
+ buf[offset++] = (unsigned char)ucs4;
+ }
+ else {
+ sprintf(buf + offset, "\\%.4lX", (unsigned long)ucs4);
+ offset += 4;
+ }
+ i += len;
+ }
+ buf[offset] = '\0';
+
+ return buf;
+}
diff --git a/Build/source/texk/xdvik/encodings.h b/Build/source/texk/xdvik/encodings.h
new file mode 100644
index 00000000000..180692c6690
--- /dev/null
+++ b/Build/source/texk/xdvik/encodings.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef ENCODINGS_H_
+#define ENCODINGS_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+struct adobe2unicode {
+ const char *adobe_name;
+ uint32_t unicode;
+};
+
+struct unicode2adobe {
+ uint32_t unicode;
+ const char *adobe_name;
+};
+
+extern uint32_t get_accented_glyph(uint32_t accent, uint32_t base_glyph);
+extern const char *unicode2adobe_name(uint32_t unicode);
+extern uint32_t adobe2unicode_name(const char *adobe_name);
+extern uint32_t guess_encoding(wide_ubyte ch, const char *fontname, char *retbuf);
+extern const char *expand_ligature(uint32_t unicode);
+extern const char *search_normalize_chars(uint32_t unicode);
+
+extern Boolean utf8_lowercase(char *utf8);
+extern int utf8_to_ucs4(const char *utf8, uint32_t *ucs4, size_t len);
+extern void ucs4_to_utf8(uint32_t ucs4, char *utf8, size_t *len, Boolean do_lowercase);
+extern unsigned char utf8_to_iso_8859_1(const char *utf8, size_t *len);
+extern char *str_utf8_to_iso_8859_1(const char *utf8);
+extern void iso_8859_1_to_utf8(unsigned char iso_8859_1, char *utf8, size_t *len);
+extern int str_iso_8859_1_to_utf8(const char *latin1, char *utf8, size_t len);
+extern Boolean is_hyphenchar(uint32_t unicode);
+extern Boolean is_ideograph(uint32_t unicode);
+extern void close_iconv(void);
+
+#endif /* ENCODINGS_H_ */
+
diff --git a/Build/source/texk/xdvik/events.c b/Build/source/texk/xdvik/events.c
new file mode 100644
index 00000000000..417e09d4b18
--- /dev/null
+++ b/Build/source/texk/xdvik/events.c
@@ -0,0 +1,5645 @@
+/*======================================================================*\
+
+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
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi-config.h"
+
+#ifdef STDC_HEADERS
+# include <unistd.h>
+# include <fcntl.h>
+#endif
+#include <signal.h>
+#include <sys/file.h> /* this defines FASYNC */
+#ifdef HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h> /* Or this might define FASYNC */
+#endif
+#include <sys/ioctl.h> /* this defines SIOCSPGRP and FIOASYNC */
+#include <sys/wait.h> /* ignore HAVE_SYS_WAIT_H -- we always need WNOHANG */
+
+#include "xdvi.h" /* this includes Xlib and Xutil are already included */
+#include "xdvi-debug.h"
+
+
+#ifndef MOTIF
+#include <X11/Xaw/Form.h> /* for XtNresizable */
+#endif
+
+#include <setjmp.h>
+#include <sys/time.h> /* for gettimeofday */
+
+#include <X11/IntrinsicP.h>
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h> /* needed for def. of XtNiconX(??) */
+
+#include "pagesel.h"
+#include "filehist.h"
+#include "special.h"
+#include "psgs.h"
+
+
+#include <errno.h>
+
+#include <ctype.h>
+
+#include "util.h"
+#include "x_util.h"
+#include "string-utils.h"
+#include "print-dialog.h"
+#include "search-dialog.h"
+#include "sfSelFile.h"
+#include "mag.h"
+#include "help-window.h"
+#include "message-window.h"
+#include "dvi-draw.h"
+#include "statusline.h"
+#include "hypertex.h"
+#include "dvi-init.h"
+#include "Tip.h"
+#include "browser.h"
+#include "search-internal.h"
+#include "my-snprintf.h"
+
+#include "events.h"
+#include "selection.h"
+#include "encodings.h"
+#include "pagehist.h"
+#include "xm_colorsel.h"
+#include "xm_toolbar.h"
+#include "xaw_menu.h"
+#include "xm_menu.h"
+#include "xm_prefs.h"
+
+#include "xm_prefs_appearance.h" /* for update_preferences_expert() */
+#include "xm_prefs_fonts.h" /* for update_preferences_color() */
+#include "xm_prefs_page.h" /* for update_preferences_shrink() */
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif /* X_NOT_STDC_ENV */
+
+/* Linux prefers O_ASYNC over FASYNC; SGI IRIX does the opposite. */
+#if !defined(FASYNC) && defined(O_ASYNC)
+# define FASYNC O_ASYNC
+#endif
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+# if !defined(SIOCSPGRP) || !defined(FIOASYNC)
+# define FLAKY_SIGPOLL 1
+# endif
+#endif
+
+#ifndef FLAKY_SIGPOLL
+
+# ifndef SIGPOLL
+# define SIGPOLL SIGIO
+# endif
+
+# ifndef SA_RESTART
+# define SA_RESTART 0
+# endif
+
+# if HAVE_STREAMS
+# include <stropts.h>
+
+# ifndef S_RDNORM
+# define S_RDNORM S_INPUT
+# endif
+
+# ifndef S_RDBAND
+# define S_RDBAND 0
+# endif
+
+# ifndef S_HANGUP
+# define S_HANGUP 0
+# endif
+
+# ifndef S_WRNORM
+# define S_WRNORM S_OUTPUT
+# endif
+# endif /* HAVE_STREAMS */
+
+#endif /* not FLAKY_SIGPOLL */
+
+#if HAVE_SIGACTION && !defined SA_RESETHAND
+# ifdef SA_ONESHOT
+# define SA_RESETHAND SA_ONESHOT
+# else
+# undef HAVE_SIGACTION /* Needed for Mac OS X < 10.2 (9/2002) */
+# endif
+#endif
+
+#if HAVE_POLL
+# include <poll.h>
+#else
+# if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# else
+# if HAVE_SELECT_H
+# include <select.h>
+# endif
+# endif
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif /* HAVE_POLL */
+
+static sigset_t all_signals;
+
+/*
+ * Interrupt system for receiving events. The program sets a flag
+ * whenever an event comes in, so that at the proper time (i.e., when
+ * reading a new dvi item), we can check incoming events to see if we
+ * still want to go on printing this page. This way, one can stop
+ * displaying a page if it is about to be erased anyway. We try to read
+ * as many events as possible before doing anything and base the next
+ * action on all events read.
+ * Note that the Xlib and Xt routines are not reentrant, so the most we
+ * can do is set a flag in the interrupt routine and check it later.
+ * Also, sometimes the interrupts are not generated (some systems only
+ * guarantee that SIGIO is generated for terminal files, and on the system
+ * I use, the interrupts are not generated if I use "(xdvi foo &)" instead
+ * of "xdvi foo"). Therefore, there is also a mechanism to check the
+ * event queue every 70 drawing operations or so. This mechanism is
+ * disabled if it turns out that the interrupts do work.
+ * For a fuller discussion of some of the above, see xlife in
+ * comp.sources.x.
+ */
+
+/*
+ * Signal flags
+ */
+
+/* This could be static volatile, but we want to avoid any optimizer bugs. */
+VOLATILE unsigned int sig_flags = 0;
+
+#define SF_USR 1
+#define SF_ALRM 2
+#define SF_POLL 4
+#define SF_CHLD 8
+#define SF_TERM 16
+#define SF_SEGV 32
+
+static void do_sigusr(void);
+static void do_sigalrm(void);
+static void do_sigpoll(void);
+static void do_sigchld(void);
+static void do_sigterm(void);
+static void do_sigsegv(void);
+
+/* these must be in the same order as SF_*.
+ The higher flags have higher priority, since these are
+ checked first when resolving flags_to_sigproc[sig_flags].
+
+ Example: flag := SF_TERM | SF_CHLD = 24
+
+ flags_to_sigproc[24] =>
+ do_sigterm, which sets flag to 24 & ~SF_TERM == 8
+ then, in next check:
+ flags_to_sigproc[8] =>
+ do_sigchld, which sets flag 8 & ~SF_CHLD == 0.
+ */
+#define SP0 do_sigusr
+#define SP1 do_sigalrm
+#define SP2 do_sigpoll
+#define SP3 do_sigchld
+#define SP4 do_sigterm
+#define SP5 do_sigsegv
+
+typedef void (*signalproc)(void);
+
+static const signalproc flags_to_sigproc[64] = {
+ NULL,
+ /* 1 */
+ SP0,
+ /* 2 - 3 */
+ SP1, SP1,
+ /* 4 - 7 */
+ SP2, SP2, SP2, SP2,
+ /* 8 - 15 */
+ SP3, SP3, SP3, SP3, SP3, SP3, SP3, SP3,
+ /* 16 - 31 */
+ SP4, SP4, SP4, SP4, SP4, SP4, SP4, SP4,
+ SP4, SP4, SP4, SP4, SP4, SP4, SP4, SP4,
+ /* 32 - 63 */
+ SP5, SP5, SP5, SP5, SP5, SP5, SP5, SP5,
+ SP5, SP5, SP5, SP5, SP5, SP5, SP5, SP5,
+ SP5, SP5, SP5, SP5, SP5, SP5, SP5, SP5,
+ SP5, SP5, SP5, SP5, SP5, SP5, SP5, SP5
+};
+
+#undef SP0
+#undef SP2
+#undef SP3
+#undef SP4
+#undef SP5
+
+/* file-static variables for prefix argument mechanism */
+static Boolean m_have_arg = False; /* flag whether we have a possible prefix arg */
+static int m_number = 0; /* prefix arg value, without the sign */
+static int m_sign = 1; /* is prefix arg negative? */
+
+
+/* to remember the scrollbar positions so that we can restore them
+ when `keep position' is active and window is resized to full size
+ (removing scrollbars) and then back (#810501) */
+static int m_x_scroll = 0, m_y_scroll = 0;
+
+static int source_reverse_x, source_reverse_y;
+static int source_show_all;
+
+/* globals for color stuff */
+Pixel plane_masks[4];
+XColor color_data[2];
+struct pagecolor_info page_colors = { 0, NULL };
+
+struct rgb *color_bottom;
+unsigned int color_bot_size; /* number of entries */
+struct colorframe *rcs_top;
+struct rgb fg_initial; /* Initial fg (from command line) */
+struct rgb bg_initial; /* Initial bg */
+struct bgrec *bg_head = NULL; /* head of list */
+struct bgrec *bg_current = NULL; /* current bg value */
+struct fgrec *fg_current; /* current fg value */
+struct fgrec *fg_active = NULL; /* where the GCs are */
+Pixel *color_list; /* list of colors */
+unsigned int color_list_len = 0; /* current len of list*/
+unsigned int color_list_max = 0; /* allocated size */
+Boolean color_warned = False;
+/*
+ FIXME: the following file-static flag is used to control whether
+ a mouse-related Act_* should block further actions that have
+ been registered for the same event.
+
+ It is used for the Act_href_* routines.
+
+ This used to be a
+ longjmp(somewehre_in_the_event_loop);
+ but that was pretty dreadful as well. Surely there must
+ be some other (X(t)-specific?) way to do this?? (Apart from
+ de-registering the action and re-registering it again.)
+*/
+static Boolean m_block_mouse_event = False;
+
+/* for calling it from mag.c */
+void
+block_next_mouse_event(void) {
+ m_block_mouse_event = True;
+}
+
+Boolean
+block_this_mouse_event(void) {
+ if (m_block_mouse_event == True) {
+ m_block_mouse_event = False;
+ return True;
+ }
+ return False;
+}
+
+
+void null_mouse(XEvent *event)
+{
+ UNUSED(event);
+}
+
+mouse_proc mouse_motion = null_mouse;
+mouse_proc mouse_release = null_mouse;
+
+static void Act_digit(Widget, XEvent *, String *, Cardinal *);
+static void Act_find(Widget, XEvent *, String *, Cardinal *);
+static void Act_find_next(Widget, XEvent *, String *, Cardinal *);
+static void Act_minus(Widget, XEvent *, String *, Cardinal *);
+static void Act_quit(Widget, XEvent *, String *, Cardinal *);
+static void Act_quit_confirm(Widget, XEvent *, String *, Cardinal *);
+static void Act_print(Widget, XEvent *, String *, Cardinal *);
+static void Act_save(Widget, XEvent *, String *, Cardinal *);
+static void Act_help(Widget, XEvent *, String *, Cardinal *);
+static void Act_goto_page(Widget, XEvent *, String *, Cardinal *);
+static void Act_declare_page_number(Widget, XEvent *, String *, Cardinal *);
+static void Act_toggle_mark(Widget, XEvent *, String *, Cardinal *);
+static void Act_home(Widget, XEvent *, String *, Cardinal *);
+static void Act_home_or_top(Widget, XEvent *, String *, Cardinal *);
+static void Act_end_or_bottom(Widget, XEvent *, String *, Cardinal *);
+static void Act_center(Widget, XEvent *, String *, Cardinal *);
+static void Act_left(Widget, XEvent *, String *, Cardinal *);
+static void Act_right(Widget, XEvent *, String *, Cardinal *);
+static void Act_up(Widget, XEvent *, String *, Cardinal *);
+static void Act_down(Widget, XEvent *, String *, Cardinal *);
+static void Act_up_or_previous(Widget, XEvent *, String *, Cardinal *);
+static void Act_down_or_next(Widget, XEvent *, String *, Cardinal *);
+static void Act_set_margins(Widget, XEvent *, String *, Cardinal *);
+static void Act_show_display_attributes(Widget, XEvent *, String *, Cardinal *);
+static void Act_set_density(Widget, XEvent *, String *, Cardinal *);
+static void Act_change_density(Widget, XEvent *, String *, Cardinal *);
+static void Act_fullscreen(Widget, XEvent *, String *, Cardinal *);
+#ifdef GREY
+static void Act_set_greyscaling(Widget, XEvent *, String *, Cardinal *);
+#endif
+#if COLOR
+static void Act_set_color(Widget, XEvent *, String *, Cardinal *);
+#endif
+
+static void Act_htex_anchorinfo(Widget, XEvent *, String *, Cardinal *);
+
+static void Act_reread_dvi_file(Widget, XEvent *, String *, Cardinal *);
+static void Act_select_dvi_file(Widget, XEvent *, String *, Cardinal *);
+static void Act_discard_number(Widget, XEvent *, String *, Cardinal *);
+static void Act_drag(Widget, XEvent *, String *, Cardinal *);
+static void Act_wheel(Widget, XEvent *, String *, Cardinal *);
+static void Act_motion(Widget, XEvent *, String *, Cardinal *);
+static void Act_release(Widget, XEvent *, String *, Cardinal *);
+static void Act_source_special(Widget, XEvent *, String *, Cardinal *);
+static void Act_show_source_specials(Widget, XEvent *, String *, Cardinal *);
+static void Act_source_what_special(Widget, XEvent *, String *, Cardinal *);
+static void Act_unpause_or_next(Widget, XEvent *, String *, Cardinal *);
+static void Act_ruler_snap_origin(Widget w, XEvent *event, String *params, Cardinal *num_params);
+static void Act_text_mode(Widget w, XEvent *event, String *params, Cardinal *num_params);
+static void Act_load_url(Widget w, XEvent *event, String *params, Cardinal *num_params);
+#ifdef MOTIF
+static void Act_prefs_dialog(Widget w, XEvent *event, String *params, Cardinal *num_params);
+#endif
+
+static XtActionsRec m_actions[] = {
+ {"digit", Act_digit},
+ {"switch-mode", Act_switch_mode},
+ {"ruler-mode", Act_ruler_mode},
+ {"text-mode", Act_text_mode},
+ {"minus", Act_minus},
+ {"recent-files", Act_recent_files},
+ {"quit", Act_quit},
+ {"quit-confirm", Act_quit_confirm},
+ {"print", Act_print},
+ {"save", Act_save},
+ {"find", Act_find},
+ {"find-next", Act_find_next},
+ {"help", Act_help},
+ {"goto-page", Act_goto_page},
+ {"use-tex-pages", Act_use_tex_pages},
+ {"forward-page", Act_forward_page},
+ {"back-page", Act_back_page},
+ {"toggle-mark", Act_toggle_mark},
+ {"declare-page-number", Act_declare_page_number},
+ {"home", Act_home},
+ {"home-or-top", Act_home_or_top},
+ {"end-or-bottom", Act_end_or_bottom},
+ {"center", Act_center},
+ {"set-keep-flag", Act_set_keep_flag},
+ {"ruler-snap-origin", Act_ruler_snap_origin},
+ {"left", Act_left},
+ {"right", Act_right},
+ {"up", Act_up},
+ {"down", Act_down},
+ {"up-or-previous", Act_up_or_previous},
+ {"down-or-next", Act_down_or_next},
+ {"set-margins", Act_set_margins},
+ {"show-display-attributes", Act_show_display_attributes},
+ {"set-shrink-factor", Act_set_shrink_factor},
+ {"shrink-to-dpi", Act_shrink_to_dpi},
+ {"set-density", Act_set_density},
+ {"change-density", Act_change_density},
+ {"fullscreen", Act_fullscreen},
+#ifdef GREY
+ {"set-greyscaling", Act_set_greyscaling},
+#endif
+#if COLOR
+ {"set-color", Act_set_color},
+#endif
+#ifdef PS
+ {"set-ps", Act_set_ps},
+#endif
+ {"htex-back", Act_htex_back},
+ {"htex-forward", Act_htex_forward},
+ {"htex-anchorinfo", Act_htex_anchorinfo},
+#ifdef PS_GS
+ {"set-gs-alpha", Act_set_gs_alpha},
+#endif
+ {"set-expert-mode", Act_set_expert_mode},
+ {"reread-dvi-file", Act_reread_dvi_file},
+ {"select-dvi-file", Act_select_dvi_file},
+ {"discard-number", Act_discard_number},
+ {"drag", Act_drag},
+ {"wheel", Act_wheel},
+ {"motion", Act_motion},
+ {"release", Act_release},
+ {"source-special", Act_source_special},
+ {"show-source-specials", Act_show_source_specials},
+ {"source-what-special", Act_source_what_special},
+ {"unpause-or-next", Act_unpause_or_next},
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ {"set-papersize", Act_set_papersize},
+ {"set-paper-landscape", Act_set_paper_landscape},
+#endif /* NEW_MENU_CREATION */
+ {"load-url", Act_load_url},
+ {"pagehistory-clear", Act_pagehistory_clear},
+ {"pagehistory-back", Act_pagehistory_back},
+ {"pagehistory-forward", Act_pagehistory_forward},
+ {"pagehistory-delete-backward", Act_pagehistory_delete_backward},
+ {"pagehistory-delete-forward", Act_pagehistory_delete_forward},
+#ifdef MOTIF
+ {"prefs-dialog", Act_prefs_dialog},
+#endif
+};
+
+/*
+ * Access to m_actions
+ */
+int get_num_actions(void)
+{
+ return XtNumber(m_actions);
+}
+
+XtActionsRec *get_actions(void)
+{
+ return m_actions;
+}
+
+/*
+ * Data for buffered events.
+ */
+
+#ifndef FLAKY_SIGPOLL
+static VOLATILE int event_freq = 70;
+#else
+#define event_freq 70
+#endif
+
+static void can_exposures(struct WindowRec *windowrec);
+
+
+/*
+ * Set the flag so that termination occurs, via the above routine.
+ * This should be used in place of xdvi_exit() when there may be a
+ * non-killable process running (e.g., anytime within read_events()).
+ */
+
+static void
+xdvi_normal_exit(void)
+{
+ sig_flags |= SF_TERM;
+}
+
+static void
+xdvi_normal_exit_cb(XtPointer arg)
+{
+ UNUSED(arg);
+ sig_flags |= SF_TERM;
+}
+
+void
+xdvi_exit_callback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ sig_flags |= SF_TERM;
+}
+
+/*
+ * Event-handling routines.
+ */
+
+
+void
+expose(struct WindowRec *windowrec,
+ int x, int y,
+ unsigned int w, unsigned int h)
+{
+ if (windowrec->min_x > x)
+ windowrec->min_x = x;
+ if (windowrec->max_x < (int)(x + w))
+ windowrec->max_x = x + w;
+ if (windowrec->min_y > y)
+ windowrec->min_y = y;
+ if (windowrec->max_y < (int)(y + h))
+ windowrec->max_y = y + h;
+
+ globals.ev.flags |= EV_EXPOSE;
+}
+
+void
+clearexpose(struct WindowRec *windowrec,
+ int x, int y,
+ unsigned w, unsigned h)
+{
+ XClearArea(DISP, windowrec->win, x, y, w, h, False);
+ expose(windowrec, x, y, w, h);
+}
+
+/*
+ * Routines for X11 toolkit.
+ */
+
+static Position window_x, window_y;
+static Arg arg_xy[] = {
+ {XtNx, (XtArgVal) &window_x},
+ {XtNy, (XtArgVal) &window_y},
+};
+
+#define get_xy() XtGetValues(globals.widgets.draw_widget, arg_xy, XtNumber(arg_xy))
+
+
+static void
+warn_num_params(const char *act_name, String *params, int num_params, int max_params)
+{
+ if (num_params > max_params) {
+ XDVI_WARNING((stderr, "Too many parameters (%d) for action \"%s\", ignoring all after \"%s\"",
+ num_params, act_name, params[max_params - 1]));
+ }
+}
+
+
+struct xdvi_action *
+compile_action(const char *str)
+{
+ const char *p, *p1, *p2;
+ XtActionsRec *actp;
+ struct xdvi_action *ap;
+
+ while (*str == ' ' || *str == '\t')
+ ++str;
+
+ if (*str == '\0' || *str == '\n')
+ return NULL;
+
+ p = str;
+
+ /* find end of command name */
+ while (isalnum((int)*p) || *p == '-' || *p == '_')
+ ++p;
+
+ for (actp = m_actions; ; ++actp) {
+ if (actp >= m_actions + XtNumber(m_actions)) {
+ const char *tmp = strchr(str, '\0');
+ if (tmp == NULL) {
+ tmp = p;
+ }
+ XDVI_WARNING((stderr, "Cannot compile action \"%.*s\".", (int)(tmp - str), str));
+
+ return NULL;
+ }
+ if (memcmp(str, actp->string, p - str) == 0 && actp->string[p - str] == '\0')
+ break;
+ }
+
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ if (*p != '(') {
+ while (*p != '\0' && *p != '\n')
+ ++p;
+ XDVI_WARNING((stderr, "Syntax error in action %.*s.", (int)(p - str), str));
+
+ return NULL;
+ }
+ ++p;
+ while (*p == ' ' || *p == '\t')
+ ++p;
+ for (p1 = p;; ++p1) {
+ if (*p1 == '\0' || *p1 == '\n') {
+ XDVI_WARNING((stderr, "Syntax error in action %.*s.", (int)(p1 - str), str));
+ return NULL;
+ }
+ if (*p1 == ')')
+ break;
+ }
+
+ ap = xmalloc(sizeof *ap);
+ ap->proc = actp->proc;
+ for (p2 = p1;; --p2) {
+ if (p2 <= p) { /* if no args */
+ ap->num_params = 0;
+ ap->param = NULL;
+ break;
+ }
+ else if (p2[-1] != ' ' && p2[-1] != '\t') {
+ char *arg;
+
+ arg = xmalloc(p2 - p + 1);
+ memcpy(arg, p, p2 - p);
+ arg[p2 - p] = '\0';
+ ap->num_params = 1;
+ ap->param = arg;
+ break;
+ }
+ }
+
+ ap->next = compile_action(p1 + 1);
+
+ return ap;
+}
+
+void
+handle_command(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct xdvi_action *actp;
+
+ UNUSED(call_data);
+
+ /* call all actions registered for this event */
+ for (actp = (struct xdvi_action *)client_data; actp != NULL; actp = actp->next) {
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "calling action with param: %s\n", actp->param);
+ (actp->proc) (widget, NULL, &actp->param, &actp->num_params);
+ }
+}
+
+#ifdef MOTIF
+int
+set_bar_value(Widget bar, int value, int max)
+{
+ XmScrollBarCallbackStruct call_data;
+
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "set_bar_value: val %d, max %d\n", value, max);
+#endif
+ if (value > max)
+ value = max;
+ if (value < 0)
+ value = 0;
+ call_data.value = value;
+ XtVaSetValues(bar, XmNvalue, value, NULL);
+ XtCallCallbacks(bar, XmNvalueChangedCallback, &call_data);
+ return value;
+}
+#endif
+
+void
+home(wide_bool scrl)
+{
+ if (!scrl)
+ XUnmapWindow(DISP, mane.win);
+# ifdef MOTIF
+ {
+ int value;
+
+ value = (globals.page.w - mane.width) / 2;
+ if (value > resource.sidemargin_int / mane.shrinkfactor)
+ value = resource.sidemargin_int / mane.shrinkfactor;
+ (void)set_bar_value(globals.widgets.x_bar, value, (int)(globals.page.w - mane.width));
+
+ value = (globals.page.h - mane.height) / 2;
+ if (value > resource.topmargin_int / mane.shrinkfactor)
+ value = resource.topmargin_int / mane.shrinkfactor;
+ (void)set_bar_value(globals.widgets.y_bar, value, (int)(globals.page.h - mane.height));
+ }
+# else
+ get_xy();
+ if (globals.widgets.x_bar != NULL) {
+ int coord = (globals.page.w - mane.width) / 2;
+
+ if (coord > resource.sidemargin_int / mane.shrinkfactor)
+ coord = resource.sidemargin_int / mane.shrinkfactor;
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer) (window_x + coord));
+ }
+ if (globals.widgets.y_bar != NULL) {
+ int coord = (globals.page.h - mane.height) / 2;
+
+ if (coord > resource.topmargin_int / mane.shrinkfactor)
+ coord = resource.topmargin_int / mane.shrinkfactor;
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer) (window_y + coord));
+ }
+# endif /* MOTIF */
+ if (!scrl) {
+ XMapWindow(DISP, mane.win);
+ /* Wait for the server to catch up---this eliminates flicker. */
+ XSync(DISP, False);
+ }
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+/*
+ * Same as home(), except move to the bottom of the page.
+ */
+
+static void
+home_bottom(wide_bool scrl)
+{
+ UNUSED(scrl);
+ XUnmapWindow(DISP, mane.win);
+#ifdef MOTIF
+ {
+ int value;
+
+ value = (globals.page.w - mane.width) / 2;
+ if (value > resource.sidemargin_int / mane.shrinkfactor)
+ value = resource.sidemargin_int / mane.shrinkfactor;
+ (void)set_bar_value(globals.widgets.x_bar, value, (int)(globals.page.w - mane.width));
+
+ (void)set_bar_value(globals.widgets.y_bar, (int)(globals.page.h - mane.height), (int)(globals.page.h - mane.height));
+ }
+#else /* MOTIF */
+ get_xy();
+ if (globals.widgets.x_bar != NULL) {
+ int coord = (globals.page.w - mane.width) / 2;
+
+ if (coord > resource.sidemargin_int / mane.shrinkfactor)
+ coord = resource.sidemargin_int / mane.shrinkfactor;
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer) (window_x + coord));
+ }
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer)(window_y + (globals.page.h - mane.height)));
+#endif /* MOTIF */
+ XMapWindow(DISP, mane.win);
+ /* Wait for the server to catch up---this eliminates flicker. */
+ XSync(DISP, False);
+
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+
+#ifndef MOTIF
+static void
+handle_destroy_bar(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(call_data);
+ *(Widget *) client_data = NULL;
+}
+#endif
+
+static Boolean resized = False;
+
+static void
+get_geom(void)
+{
+ static Dimension new_clip_w, new_clip_h;
+
+ static Arg arg_wh_clip[] = {
+ {XtNwidth, (XtArgVal) &new_clip_w},
+ {XtNheight, (XtArgVal) &new_clip_h},
+ };
+
+ static Dimension window_w, window_h;
+
+ static Arg arg_wh[] = {
+ {XtNwidth, (XtArgVal) &window_w},
+ {XtNheight, (XtArgVal) &window_h},
+ };
+
+
+ int old_clip_w;
+
+#ifdef MOTIF
+ /* event handlers for Motif scrollbars have already been added
+ in create_initialize_widgets(), xdvi.c */
+ XtGetValues(globals.widgets.main_window, arg_wh, XtNumber(arg_wh));
+#else
+ XtGetValues(globals.widgets.vport_widget, arg_wh, XtNumber(arg_wh));
+ /* Note: widgets may be destroyed but not forgotten */
+ if (globals.widgets.x_bar == NULL) {
+ globals.widgets.x_bar = XtNameToWidget(globals.widgets.vport_widget, "horizontal");
+ if (globals.widgets.x_bar != NULL) {
+ XtAddCallback(globals.widgets.x_bar, XtNdestroyCallback, handle_destroy_bar,
+ (XtPointer)&globals.widgets.x_bar);
+ XtAddEventHandler(globals.widgets.x_bar, ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
+ False, handle_x_scroll, NULL);
+ }
+ }
+ if (globals.widgets.y_bar == NULL) {
+ globals.widgets.y_bar = XtNameToWidget(globals.widgets.vport_widget, "vertical");
+ if (globals.widgets.y_bar != NULL) {
+ XtAddCallback(globals.widgets.y_bar, XtNdestroyCallback, handle_destroy_bar,
+ (XtPointer)&globals.widgets.y_bar);
+ XtAddEventHandler(globals.widgets.y_bar, ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
+ False, handle_y_scroll, NULL);
+ }
+ }
+#endif
+ XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
+
+ old_clip_w = mane.width;
+
+ /* we need to do this because
+ sizeof(Dimension) != sizeof(int)
+ */
+ mane.width = new_clip_w;
+ mane.height = new_clip_h;
+ if (old_clip_w == 0) {
+ globals.ev.flags |= EV_NEWPAGE;
+ }
+
+ if (resource.keep_flag) {
+#ifndef MOTIF
+ Dimension d;
+ int curr_scroll;
+ if ((globals.widgets.x_bar != NULL && m_x_scroll != 0) || (globals.widgets.y_bar != NULL && m_y_scroll != 0)) {
+ get_xy();
+ }
+#endif
+ if (globals.widgets.x_bar != NULL && m_x_scroll != 0) {
+#ifdef MOTIF
+ if (m_x_scroll > 0)
+ (void)set_bar_value(globals.widgets.x_bar, m_x_scroll, (int)(globals.page.w - mane.width));
+#else
+ XtVaGetValues(globals.widgets.clip_widget, XtNy, &d, NULL);
+ curr_scroll = d - window_x;
+ if (m_x_scroll > curr_scroll) {
+ TRACE_GUI((stderr, "======== diff: %d", m_x_scroll - curr_scroll));
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)(m_x_scroll - curr_scroll));
+ }
+#endif
+ }
+ if (globals.widgets.y_bar != NULL && m_y_scroll != 0) {
+#ifdef MOTIF
+ if (m_y_scroll > 0)
+ (void)set_bar_value(globals.widgets.y_bar, m_y_scroll, (int)(globals.page.h - mane.height));
+#else
+ XtVaGetValues(globals.widgets.clip_widget, XtNy, &d, NULL);
+ curr_scroll = d - window_y;
+ if (m_y_scroll > curr_scroll) {
+ TRACE_GUI((stderr, "======== diff: %d", m_y_scroll - curr_scroll));
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer)(m_y_scroll - curr_scroll));
+ }
+#endif
+ }
+ }
+ /* home(False); */
+ resized = False;
+}
+
+/*
+ * Callback routines
+ */
+
+void
+handle_resize(Widget widget, XtPointer junk, XEvent *event, Boolean *cont)
+{
+ UNUSED(widget);
+ UNUSED(junk);
+ UNUSED(event);
+ UNUSED(cont);
+
+ resized = True;
+#ifndef MOTIF
+ handle_statusline_resize();
+ handle_pagelist_resize();
+#endif
+}
+
+void
+reconfig(void)
+{
+/* Dimension x, y; */
+
+ if (globals.dvi_file.bak_fp == NULL)
+ return;
+
+#ifndef MOTIF
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)False, NULL);
+#endif
+ TRACE_GUI((stderr, "globals.widgets.draw_widget: w %d, h %d", globals.page.w, globals.page.h));
+ XtVaSetValues(globals.widgets.draw_widget, XtNwidth, (XtArgVal)globals.page.w, XtNheight, (XtArgVal)globals.page.h, NULL);
+
+#ifdef TEST_SCROLLING
+/* XtVaSetValues(globals.widgets.draw_background, XtNwidth, (XtArgVal)globals.page.w, XtNheight, (XtArgVal)globals.page.h, NULL); */
+#endif
+
+#ifndef MOTIF
+ handle_statusline_resize(); /* without this, statusline will disappear */
+ /* following not needed? */
+ /* handle_pagelist_resize(); */
+#endif
+
+ get_geom();
+
+/* set_windowsize(&x, &y */
+/* #ifndef MOTIF */
+/* , get_panel_width() */
+/* #endif */
+/* ); */
+/* XResizeWindow(DISP, XtWindow(globals.widgets.top_level), x, y); */
+/* reconfigure_window(False, x, y, True); */
+/* reconfig_window(); */
+}
+
+
+int
+check_goto_page(int pageno)
+{
+ int retval;
+ if (pageno < 0) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Can't go to page %d, going to first page instead", pageno + 1);
+ retval = 0;
+ }
+ else if (pageno >= total_pages) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT,
+ "Can't go to page %d, going to last page (%d) instead",
+ pageno + 1, total_pages);
+ retval = total_pages - 1;
+ }
+ else
+ retval = pageno;
+
+ page_history_insert(retval);
+ return retval;
+}
+
+
+static int
+check_goto_tex_page(int pageno)
+{
+ /*
+ Translate from TeX page number to `real' page number if
+ needed. Note that pageno is a C-style 0-based number, hence we
+ add 1 for the argument of pageinfo_get_index_of_number().
+ */
+ int retval;
+ if (resource.use_tex_pages) {
+ int res = pageinfo_get_index_of_number(pageno + 1);
+ if (res >= 0)
+ retval = res;
+ else {
+ XBell(DISP, 0);
+ if (pageno < 1) {
+ statusline_print(STATUS_SHORT, "Can't go to page %d, going to first page instead", pageno + 1);
+ retval = 0;
+ }
+ else {
+ /* there is no quick way to determine the last page number in the TeX page index */
+ statusline_print(STATUS_SHORT,
+ "Can't go to page %d, going to last page instead",
+ pageno + 1);
+ retval = total_pages - 1;
+ }
+ }
+ page_history_insert(retval);
+ }
+ else {
+ retval = check_goto_page(pageno);
+ }
+ return retval;
+}
+
+/* |||
+ * Currently the event handler does not coordinate XCopyArea requests
+ * with GraphicsExpose events. This can lead to problems if the window
+ * is partially obscured and one, for example, drags a scrollbar.
+ */
+
+/*
+ * Actions for the translation mechanism.
+ */
+
+/* if there are global prefixes, return them in res and reset them to defaults */
+static Boolean
+get_prefix_arg(int *res)
+{
+ Boolean ret;
+
+ *res = m_sign * m_number;
+ ret = m_have_arg;
+ /* reset global flags */
+ m_have_arg = False;
+ m_number = 0;
+ m_sign = 1;
+ return ret;
+}
+
+Boolean
+get_int_arg(String *param, Cardinal *num_params, int *res)
+{
+ if (*num_params > 0) {
+ *res = atoi(*param);
+ return True;
+ }
+ else {
+ if (get_prefix_arg(res)) { /* prefix argument? */
+ return True;
+ }
+ }
+ return False;
+}
+
+
+Boolean
+toggle_arg(int arg, String *param, Cardinal *num_params)
+{
+ if (*num_params > 0) {
+ if (**param != 't' && (atoi(*param) != 0) == arg)
+ return False;
+ }
+ else {
+ if (m_have_arg) {
+ int tmparg = m_number;
+
+ m_have_arg = False;
+ m_number = 0;
+ m_sign = 1;
+
+ if ((tmparg != 0) == arg)
+ return False;
+ }
+ }
+ return True;
+}
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+Boolean
+check_resource_expert(void *val, const char *param)
+{
+ int j = strtol(param, (char **)NULL, 10);
+ /* check if the j-1th bit is set: */
+ return (*(int *)val >> (j - 1)) & 1;
+}
+
+Boolean
+check_papersize(void *val, const char *param)
+{
+ UNUSED(val);
+ UNUSED(param);
+ return False; /* TODO */
+}
+
+Boolean
+check_paper_landscape(void *val, const char *param)
+{
+ UNUSED(val);
+ UNUSED(param);
+ return False; /* TODO */
+}
+
+/* comparison functions for the menu setting code */
+Boolean
+check_toggle(void *val, const char *param)
+{
+ Boolean *on = val;
+ if (strcmp(param, "toggle") == 0) {
+ return *on;
+ }
+ else {
+ fprintf(stderr, "TODO: check_toggle: arg |%s|, curr: %d\n", param, *(int *)val);
+ return *on;
+ }
+}
+
+Boolean
+check_int(void *val, const char *param)
+{
+ int i = strtol(param, (char **)NULL, 10);
+ return i == *(int *)val;
+}
+#endif /* NEW_MENU_CREATION */
+
+
+static void
+Act_digit(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int digit;
+ /* for overflow checks */
+ static const int MAXINT_QUOT = INT_MAX / 10;
+ static const int MAXINT_MOD = INT_MAX % 10;
+
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (*num_params != 1 || (digit = **params - '0') > 9) {
+ XBell(DISP, 0);
+ return;
+ }
+ m_have_arg = True;
+
+ /* don't increment m_number if it would overflow */
+ if (m_number < MAXINT_QUOT || (m_number == MAXINT_QUOT && digit <= MAXINT_MOD)) {
+ m_number = m_number * 10 + digit;
+ if (resource.expert_mode & XPRT_SHOW_STATUSLINE) /* too distracting for stdout */
+ statusline_print(STATUS_SHORT, "numerical prefix: %s%d", m_sign < 0 ? "-" : "", m_number);
+ }
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "numerical prefix: %s%d: no larger value possible", m_sign < 0 ? "-" : "", m_number);
+ }
+}
+
+static void
+Act_minus(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ m_have_arg = True;
+ m_sign = -m_sign;
+ if (m_number > 0) {
+ if (resource.expert_mode & XPRT_SHOW_STATUSLINE) /* too distracting for stdout */
+ statusline_print(STATUS_SHORT, "numerical prefix: %s%d", m_sign < 0 ? "-" : "", m_number);
+ }
+ else {
+ if (resource.expert_mode & XPRT_SHOW_STATUSLINE) /* too distracting for stdout */
+ statusline_print(STATUS_SHORT, "numerical prefix: %s", m_sign < 0 ? "-" : "");
+ }
+}
+
+static void
+Act_quit(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+#ifndef FLAKY_SIGPOLL
+ if (globals.debug & DBG_EVENT)
+ puts(event_freq < 0
+ ? "SIGPOLL is working"
+ : "no SIGPOLL signals received");
+#endif
+ xdvi_normal_exit();
+}
+
+static void
+Act_quit_confirm(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ static Widget dialog = 0;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+#ifndef FLAKY_SIGPOLL
+ if (globals.debug & DBG_EVENT)
+ puts(event_freq < 0
+ ? "SIGPOLL is working"
+ : "no SIGPOLL signals received");
+#endif
+
+ /* already a quit dialog open? */
+ if (dialog != 0) {
+ /* HACK ALERT: use brute force, since tests for XtIsRealized()
+ or XtIsMapped() don't work?? Grabbing the server apparently
+ has problems with Xaw, and it's not a nice solution anyway ... */
+ if (kill_message_window(dialog))
+ XBell(DISP, 0);
+ }
+
+ dialog = choice_dialog_sized(globals.widgets.top_level,
+ MSG_QUESTION,
+ SIZE_SMALL,
+ NULL,
+#ifndef MOTIF
+ "quit",
+#endif
+ NULL, NULL, /* no pre_callbacks */
+ "OK", xdvi_normal_exit_cb, NULL,
+ "Cancel", NULL, NULL,
+ "Really quit xdvi?");
+}
+
+static void
+Act_load_url(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(num_params);
+ launch_browser(*params);
+}
+
+static void
+Act_print(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ static struct save_or_print_info info;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ info.act = FILE_PRINT;
+
+ save_or_print_callback(&info);
+}
+
+static void
+Act_save(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ static struct save_or_print_info info;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ info.act = FILE_SAVE;
+
+ save_or_print_callback(&info);
+}
+
+static void
+Act_find(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+ dvi_find_string(NULL, False);
+}
+
+static void
+Act_find_next(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+ dvi_find_string(NULL, True);
+}
+
+static void
+Act_help(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ char *arg = NULL;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (*num_params > 0)
+ arg = *params;
+
+ show_help(globals.widgets.top_level, arg);
+}
+
+static home_proc home_action = NULL;
+
+void
+goto_page(int new_page, home_proc proc, Boolean force)
+{
+ /* SU: added clearing the window here, else old window content
+ will survive switching pages as long as globals.pausing.flag is active
+ (i.e. when inadvertedly changing page instead of unpausing)
+ */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ if (globals.dvi_file.bak_fp == NULL) {
+ current_page = new_page; /* so that xdvi gets the page change */
+ return;
+ }
+
+ ASSERT(new_page >= 0 && new_page < total_pages, "new_page in goto_page() out of range");
+ if (current_page != new_page || force) {
+ globals.cursor.flags &= ~CURSOR_LINK; /* disable link cursor if needed */
+
+ current_page = new_page;
+ home_action = proc;
+ globals.warn_spec_now = resource.warn_spec;
+ /* this seems unneccessary */
+/* if (!resource.keep_flag) */
+/* home(False); */
+#if defined(MOTIF) && HAVE_XPM
+ tb_check_navigation_sensitivity(current_page);
+/* page_history_update_toolbar_navigation(); */
+#endif
+ maybe_scroll_pagelist(current_page, False);
+
+ if (globals.pausing.num_save)
+ globals.pausing.num = globals.pausing.num_save[new_page];
+ else
+ globals.pausing.num = 0;
+ /* Control-L (and changing the page) clears this box */
+ globals.src.fwd_box_page = -1;
+
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ }
+}
+
+
+static void
+Act_goto_page(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ Boolean clear_statusline = False;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ warn_num_params("goto-page()", params, *num_params, 1);
+
+ if (*num_params > 0) {
+ if (**params == 'e') {
+ arg = total_pages - 1;
+ }
+ else
+ arg = atoi(*params) - globals.pageno_correct;
+ }
+ else {
+ if (get_prefix_arg(&arg)) {
+ clear_statusline = True;
+ arg -= globals.pageno_correct;
+ }
+ else {
+ arg = total_pages - 1;
+ }
+ }
+ if (arg == total_pages - 1) {
+ /* with TeX numbers, total_pages - 1 might not be found in the page list,
+ so don't use check_goto_tex_page() in this case */
+ goto_page(check_goto_page(arg), resource.keep_flag ? NULL : home, False);
+ }
+ else {
+ goto_page(check_goto_tex_page(arg), resource.keep_flag ? NULL : home, False);
+ }
+ search_signal_page_changed();
+ if (clear_statusline)
+ statusline_clear();
+}
+
+void
+Act_recent_files(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+}
+
+void
+Act_use_tex_pages(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (*num_params == 0) {
+ if (m_have_arg) {
+ resource.use_tex_pages = (m_number != 0);
+ m_have_arg = False;
+ m_number = 0;
+ m_sign = 1;
+ }
+ else {
+ resource.use_tex_pages = !resource.use_tex_pages;
+ }
+ }
+ else
+ resource.use_tex_pages = (**params == 't' ? !resource.use_tex_pages : atoi(*params));
+
+ if (resource.use_tex_pages) {
+ statusline_print(STATUS_SHORT, "Using TeX page numbers for \"g\", goto-page()");
+ }
+ else {
+ statusline_print(STATUS_SHORT, "Using physical page numbers for \"g\", goto-page()");
+ }
+
+ store_preference(NULL, "useTeXPages", "%s", resource.use_tex_pages ? "True" : "False");
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.use_tex_pages, Act_use_tex_pages, check_toggle);
+#else
+#ifdef MOTIF
+ set_use_tex_option();
+#else
+ toggle_menu(resource.use_tex_pages, Act_use_tex_pages);
+#endif
+#endif /* NEW_MENU_CREATION */
+ refresh_pagelist(total_pages, current_page);
+}
+
+void
+Act_forward_page(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ Boolean clear_statusline = False;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg))
+ arg = 1;
+ else
+ clear_statusline = True;
+
+ arg += current_page;
+
+ if (arg == current_page) { /* zero argument -> redraw page */
+ globals.src.fwd_box_page = -1;
+ search_reset_info();
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ statusline_print(STATUS_SHORT, "Page redrawn.");
+ return;
+ }
+ else if (current_page >= total_pages - 1) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Last page of DVI file");
+ return;
+ }
+
+ goto_page(check_goto_page(arg), resource.keep_flag ? NULL : home, False);
+ if (clear_statusline)
+ statusline_clear();
+ search_signal_page_changed();
+}
+
+void
+Act_back_page(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ Boolean clear_statusline = False;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg))
+ arg = 1;
+ else
+ clear_statusline = True;
+
+ arg = current_page - arg;
+
+ if (current_page == 0) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "First page of DVI file");
+ return;
+ }
+
+ goto_page(check_goto_page(arg), resource.keep_flag ? NULL : home, False);
+ if (clear_statusline)
+ statusline_clear();
+ search_signal_page_changed();
+}
+
+static void
+Act_declare_page_number(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE) {
+ show_distance_from_ruler(event, True);
+ return;
+ }
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ arg = 0;
+ }
+ globals.pageno_correct = arg - current_page;
+ statusline_print(STATUS_SHORT, "Current page number set to %d", arg);
+}
+
+static void
+Act_toggle_mark(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (globals.dvi_file.bak_fp == NULL)
+ return;
+
+ if (
+#ifdef MOTIF
+ (resource.expert_mode & XPRT_SHOW_PAGELIST) == 0
+#else
+ (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0
+#endif
+ )
+ return;
+
+ if (*num_params > 0) {
+ arg = atoi(*params);
+ if (arg < -1 || arg > 2) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT,
+ "Possible arguments: none (toggle current), "
+ "-1 (mark all), 0 (unmark all), 1 (toggle odd), 2 (toggle even)");
+ }
+ list_toggle_marks(arg);
+ }
+ else if (get_prefix_arg(&arg)) {
+ list_toggle_marks(arg);
+ statusline_clear();
+ }
+ else {
+ arg = current_page;
+ list_toggle_current(arg);
+ }
+}
+
+static void
+Act_home(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ home(True);
+}
+
+static void
+Act_home_or_top(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (resource.keep_flag) {
+ String args[1];
+ args[0] = "10"; /* should be large enough ... */
+ XtCallActionProc(globals.widgets.top_level, "up", NULL, args, 1);
+ }
+ else {
+ home(True);
+ }
+}
+
+static void
+Act_end_or_bottom(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ String args[1];
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ args[0] = "10"; /* should be large enough ... */
+ XtCallActionProc(globals.widgets.top_level, "down", NULL, args, 1);
+
+ if (!resource.keep_flag
+#ifndef MOTIF
+ && globals.widgets.x_bar != NULL
+#endif
+ ) {
+ XtCallActionProc(globals.widgets.top_level, "right", NULL, args, 1);
+ }
+}
+
+static void
+Act_center(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int x, y;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+#ifdef MOTIF
+ /* The clip widget gives a more exact value. */
+ x = event->xkey.x - mane.width / 2;
+ y = event->xkey.y - mane.height / 2;
+
+ x = set_bar_value(globals.widgets.x_bar, x, (int)(globals.page.w - mane.width));
+ y = set_bar_value(globals.widgets.y_bar, y, (int)(globals.page.h - mane.height));
+ get_xy();
+ XWarpPointer(DISP, None, None, 0, 0, 0, 0, -x - window_x, -y - window_y);
+#else
+
+ if (event == NULL)
+ return; /* button actions do not provide events */
+
+ x = event->xkey.x - mane.width / 2;
+ y = event->xkey.y - mane.height / 2;
+ /* The clip widget gives a more exact value. */
+ if (globals.widgets.x_bar != NULL)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer) x);
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer) y);
+ XWarpPointer(DISP, None, None, 0, 0, 0, 0, -x, -y);
+#endif
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+void
+Act_ruler_snap_origin(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE)
+ ruler_snap_origin(event);
+}
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+void
+Act_set_papersize(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(num_params);
+
+ fprintf(stderr, "set_paperformat: %s\n", *params);
+ resource.paper = *params;
+ set_menu((void *)resource.paper, Act_set_papersize, check_papersize);
+}
+
+void
+Act_set_paper_landscape(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(num_params);
+
+ resource.paper_landscape = !resource.paper_landscape;
+ fprintf(stderr, "set_paper_landscape: %s\n", *params);
+
+ set_menu((char *)resource.paper, Act_set_paper_landscape, check_paper_landscape);
+}
+#endif /* NEW_MENU_CREATION */
+
+void
+Act_set_keep_flag(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(event);
+ UNUSED(w);
+
+ if (*num_params == 0) {
+ if (m_have_arg) {
+ resource.keep_flag = (m_number != 0);
+ m_have_arg = False;
+ m_number = 0;
+ m_sign = 1;
+ }
+ else {
+ resource.keep_flag = !resource.keep_flag;
+ }
+ }
+ else
+ resource.keep_flag = (**params == 't'
+ ? !resource.keep_flag : atoi(*params));
+ if (resource.keep_flag) {
+ statusline_print(STATUS_SHORT, "Keeping position when switching pages");
+ }
+ else {
+ statusline_print(STATUS_SHORT,
+ "Not keeping position when switching pages");
+ }
+
+ store_preference(NULL, "keepPosition", "%s", resource.keep_flag ? "True" : "False");
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.keep_flag, Act_set_keep_flag, check_toggle);
+#else
+ toggle_menu(resource.keep_flag, Act_set_keep_flag);
+#endif /* NEW_MENU_CREATION */
+}
+
+static void
+Act_left(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ do_autoscroll = False;
+
+ warn_num_params("left()", params, *num_params, 1);
+
+#ifdef MOTIF
+ get_xy();
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "left for %p\n", (void *)w);
+ fprintf(stderr, "window x: %d, y: %d\n", window_x, window_y);
+#endif
+
+ (void)set_bar_value(globals.widgets.x_bar, (*num_params == 0 ? (-2 * (int)mane.width / 3)
+ : (int)(-my_atof(*params) * mane.width)) - window_x,
+ (int)(globals.page.w - mane.width));
+#else
+ if (globals.widgets.x_bar != NULL)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (-2 * (int)mane.width / 3)
+ : (int)(-my_atof(*params) * mane.width)));
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Horizontal scrolling not possible");
+ }
+#endif
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+}
+
+static void
+Act_right(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ do_autoscroll = False;
+
+ warn_num_params("right()", params, *num_params, 1);
+
+#ifdef MOTIF
+ get_xy();
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "right for %p\n", (void *)w);
+ fprintf(stderr, "window x: %d, y: %d\n", window_x, window_y);
+#endif
+
+ (void)set_bar_value(globals.widgets.x_bar, (*num_params == 0 ? (2 * (int)mane.width / 3)
+ : (int)(my_atof(*params) * mane.width)) - window_x,
+ (int)(globals.page.w - mane.width));
+#else
+ if (globals.widgets.x_bar != NULL)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (2 * (int)mane.width / 3)
+ : (int)(my_atof(*params) * mane.width)));
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Horizontal scrolling not possible");
+ }
+#endif
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+}
+
+static void
+Act_up(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ do_autoscroll = False;
+
+ warn_num_params("up()", params, *num_params, 1);
+
+#ifdef MOTIF
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "up for %p\n", (void *)w);
+#endif
+ get_xy();
+ (void)set_bar_value(globals.widgets.y_bar, (*num_params == 0 ? (-2 * (int)mane.height / 3)
+ : (int)(-my_atof(*params) * mane.height)) - window_y,
+ (int)(globals.page.h - mane.height));
+#else
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (-2 * (int)mane.height / 3)
+ : (int)(-my_atof(*params) * mane.height)));
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Vertical scrolling not possible");
+ }
+#endif
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+static void
+Act_down(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ do_autoscroll = False;
+
+ warn_num_params("down()", params, *num_params, 1);
+
+#ifdef MOTIF
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "down for %p\n", (void *)w);
+#endif
+ get_xy();
+ (void)set_bar_value(globals.widgets.y_bar, (*num_params == 0 ? (2 * (int)mane.height / 3)
+ : (int)(my_atof(*params) * mane.height)) - window_y,
+ (int)(globals.page.h - mane.height));
+#else
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc,
+ (XtPointer) (*num_params == 0 ? (2 * (int)mane.height / 3)
+ : (int)(my_atof(*params) * mane.height)));
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Vertical scrolling not possible");
+ }
+#endif
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+static void
+Act_down_or_next(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ do_autoscroll = False;
+
+ warn_num_params("down-or-next()", params, *num_params, 1);
+
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "down-or-next for %p\n", (void *)w);
+#endif
+
+#ifdef MOTIF
+ get_xy();
+ if (window_y > (int)mane.height - (int)globals.page.h) {
+ (void)set_bar_value(globals.widgets.y_bar, (*num_params == 0 ? (2 * (int)mane.height / 3)
+ : (int)(my_atof(*params) * mane.height)) -
+ window_y, (int)(globals.page.h - mane.height));
+ return;
+ }
+#else
+ if (globals.widgets.y_bar != NULL) {
+ get_xy();
+ if (window_y > (int)mane.height - (int)globals.page.h) {
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc,
+ (XtPointer) (*num_params ==
+ 0 ? (2 * (int)mane.height / 3)
+ : (int)(my_atof(*params) * mane.height)));
+ return;
+ }
+ }
+#endif
+
+ if (current_page < total_pages - 1) {
+ goto_page(current_page + 1, home, False);
+ search_signal_page_changed();
+ }
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "At bottom of last page");
+ }
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+
+static void
+Act_up_or_previous(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ do_autoscroll = False;
+
+ warn_num_params("up-or-previous()", params, *num_params, 1);
+
+#ifdef TEST_SCROLLING
+ fprintf(stderr, "up-or-previous for %p\n", (void *)w);
+#endif
+#ifdef MOTIF
+ get_xy();
+ if (window_y < 0) {
+ (void)set_bar_value(globals.widgets.y_bar,
+ (*num_params == 0 ? (-2 * (int)mane.height / 3)
+ : (int)(-my_atof(*params) * mane.height)) - window_y,
+ (int)(globals.page.h - mane.height));
+ return;
+ }
+#else
+ if (globals.widgets.y_bar != NULL) {
+ get_xy();
+ if (window_y < 0) {
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc,
+ (XtPointer) (*num_params ==
+ 0 ? (-2 * (int)mane.height / 3)
+ : (int)(-my_atof(*params) * mane.height)));
+ return;
+ }
+ }
+#endif
+
+ if (current_page > 0) {
+ goto_page(current_page - 1, home_bottom, False);
+ search_signal_page_changed();
+ }
+ else {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "At top of first page");
+ }
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+
+static void
+Act_set_margins(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Window dummy;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+#ifndef MOTIF
+ if (event == NULL)
+ return; /* button actions do not provide events */
+#endif
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &resource.sidemargin_int, &resource.topmargin_int, &dummy); /* throw away last argument */
+ statusline_print(STATUS_SHORT, "Margins set to cursor position (%d, %d)", resource.sidemargin_int, resource.topmargin_int);
+ resource.sidemargin_int *= mane.shrinkfactor;
+ resource.topmargin_int *= mane.shrinkfactor;
+}
+
+static void
+Act_show_display_attributes(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ statusline_print(STATUS_SHORT, "Unit = %d, bitord = %d, byteord = %d",
+ BitmapUnit(DISP), BitmapBitOrder(DISP),
+ ImageByteOrder(DISP));
+}
+
+int
+shrink_to_fit(void)
+{
+ int value1;
+ int value2;
+ static Dimension window_w;
+#ifndef MOTIF
+ static Dimension window_h;
+#endif
+
+ static Arg arg_wh[] = {
+ {XtNwidth, (XtArgVal) &window_w}
+#ifndef MOTIF
+ , {XtNheight, (XtArgVal) &window_h}
+#endif
+ };
+
+
+#ifdef MOTIF
+ XtGetValues(globals.widgets.main_window, arg_wh, XtNumber(arg_wh));
+#else
+ XtGetValues(globals.widgets.vport_widget, arg_wh, XtNumber(arg_wh));
+#endif
+
+ value1 = ROUNDUP(globals.page.unshrunk_w, window_w - 2);
+
+#ifdef MOTIF
+ { /* account for menubar */
+ static Dimension new_h;
+
+ /* get rid of scrollbar */
+ XtVaSetValues(globals.widgets.draw_widget, XtNwidth, (XtArgVal)1, XtNheight, (XtArgVal)1, NULL);
+ XtVaGetValues(globals.widgets.clip_widget, XtNheight, &new_h, NULL);
+ value2 = ROUNDUP(globals.page.unshrunk_h, new_h - 2);
+ }
+#else
+ /* FIXME: value seems too small here! */
+ value2 = ROUNDUP(globals.page.unshrunk_h, window_h - 2);
+#endif
+
+ return value1 > value2 ? value1 : value2;
+}
+
+void
+do_set_shrinkfactor(int arg, Boolean set_resource)
+{
+ static int shrink_bak = -1;
+
+ /* We don't store this as preference since it may affect initial window geometry. */
+ /* store_preference(NULL, "shrinkFactor", "%d", arg); */
+
+ if (resource.mouse_mode == MOUSE_TEXT_MODE) {
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+ }
+
+ mane.shrinkfactor = arg;
+ if (set_resource)
+ resource.shrinkfactor = mane.shrinkfactor;
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&arg, Act_set_shrink_factor, check_int);
+#if HAVE_XMP
+ tb_set_zoom_sensitivity(arg != 1);
+#endif
+#else
+ toggle_menu(arg, Act_set_shrink_factor);
+#endif /* NEW_MENU_CREATION */
+ if (arg != 1 && arg != shrink_bak) {
+ shrink_bak = arg;
+#if GREY
+#if COLOR
+ if (resource.use_grey)
+ fg_active = NULL;
+#else
+ if (resource.use_grey)
+ init_pix();
+#endif
+#endif /* GREY */
+ reset_fonts();
+ }
+ init_page();
+ reconfig();
+
+ htex_resize_page();
+
+ /* this seems unneccessary */
+/* if (!resource.keep_flag) */
+/* home(False); */
+
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+void
+Act_set_shrink_factor(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ /* Set a limit to the shrink factors allowed; otherwise xdvi may
+ consume a lot of memory (even run out of memory in malloc) in
+ the allocation for the subpixel lookup table pixeltbl,
+ dvi-draw.c. The `correct' solution would be to recognize that at a
+ certain shrink, the only pixel for a character will be always
+ set to `on' anyway, so that we could do without the lookup table for
+ very large shrink factors ... */
+ static const int SHRINK_MAX = 999;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ warn_num_params("set-shrink-factor()", params, *num_params, 1);
+
+ if (*num_params > 0) {
+ if (**params == 'a')
+ arg = shrink_to_fit();
+ else if (**params == '-')
+ arg = mane.shrinkfactor + 1;
+ else if (**params == '+')
+ arg = mane.shrinkfactor - 1;
+ else
+ arg = atoi(*params);
+ }
+ else if (!get_prefix_arg(&arg)) {
+ arg = shrink_to_fit();
+ }
+
+ if (arg <= 0) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT,
+ "No more enlarging possible");
+ return;
+ }
+
+ if (arg > SHRINK_MAX) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT,
+ "Shrink factor %d too large (maximum: %d)", arg, SHRINK_MAX);
+ return;
+ }
+
+ /* SU: added clearing the window here, else old window content
+ will survive changing shrink
+ */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ statusline_print(STATUS_SHORT, "shrink factor: %d", arg);
+#if 0
+ /* Uncommented this, otherwise selecting `shrink to fit' with same value as
+ current mane.shrinkfactor will clear the canvas (only fixed by changing shrink
+ factor again). That bug is also present in xdvik-22.48-alpha3. */
+ if (arg == mane.shrinkfactor) {
+ return;
+ }
+#endif
+
+ do_set_shrinkfactor(arg, True);
+
+#if MOTIF
+ /* note: mustn't do that inside do_set_shrinkfactor(),
+ or we get into an endless loop! */
+ update_preferences_shrink();
+#endif
+}
+
+void
+Act_shrink_to_dpi(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg, arg_bak;
+ Boolean clear_statusline = False;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ warn_num_params("shrink-to-dpi()", params, *num_params, 1);
+
+ if (!get_int_arg(params, num_params, &arg))
+ arg = 0;
+ else
+ clear_statusline = True;
+
+ arg_bak = arg;
+
+ if (arg > 0)
+ arg = (double)resource.pixels_per_inch / arg + 0.5;
+
+ if (arg <= 0) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT,
+ "shrink-to-dpi requires a positive argument");
+ return;
+ }
+
+ /* like elsewhere */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+#if 0
+ /* Uncommented this, otherwise selecting `shrink to fit' with same value as
+ current mane.shrinkfactor will clear the canvas (only fixed by changing shrink
+ factor again). That bug is also present in xdvik-22.48-alpha3. */
+ if (arg == mane.shrinkfactor)
+ return;
+#endif
+ do_set_shrinkfactor(arg, True);
+
+#if MOTIF
+ /* note: mustn't do that inside do_set_shrinkfactor(),
+ or we get into an endless loop! */
+ update_preferences_shrink();
+#endif
+}
+
+void
+do_set_density(double newgamma, Boolean force, Boolean update_resource)
+{
+
+ /* like elsewhere */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+#ifdef GREY
+ if (resource.use_grey) {
+ if (newgamma == resource.gamma && !force) {
+ statusline_print(STATUS_SHORT, "density value: %.3f", newgamma);
+ return;
+ }
+ resource.gamma = newgamma;
+ if (update_resource)
+ globals.curr_gamma = resource.gamma;
+
+#if COLOR
+ fg_active = NULL;
+ reset_colors();
+#else
+ init_pix();
+ if (G_visual->class != TrueColor) {
+ return;
+ }
+ reset_fonts();
+#endif /* COLOR */
+ statusline_print(STATUS_SHORT, "density value: %.3f", newgamma);
+ } else
+#endif /* GREY */
+ {
+ reset_fonts();
+ if (mane.shrinkfactor == 1) {
+ statusline_print(STATUS_SHORT,
+ "set-density ignored at magnification 1");
+ return;
+ }
+ statusline_print(STATUS_SHORT, "density value: %.3f", newgamma);
+ }
+
+ store_preference(NULL, "gamma", "%f", resource.gamma);
+
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+static void
+Act_set_density(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ warn_num_params("set-density()", params, *num_params, 1);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ XBell(DISP, 0);
+ return;
+ }
+/* if (arg < 0) { */
+/* XBell(DISP, 0); */
+/* statusline_print(STATUS_SHORT, */
+/* "set-density requires a positive value"); */
+/* return; */
+/* } */
+ do_set_density(arg != 0 ? arg / 100.0 : 1.0, False, True);
+#if MOTIF
+ update_preferences_darkness();
+#else
+ store_preference(NULL, "gamma", "%f", resource.gamma);
+#endif
+}
+
+
+static void
+Act_change_density(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ double diff;
+ double oldgamma = resource.gamma;
+ UNUSED(w);
+ UNUSED(event);
+
+ if (block_this_mouse_event())
+ return;
+
+ warn_num_params("change-density()", params, *num_params, 1);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ XBell(DISP, 0);
+ return;
+ }
+ diff = oldgamma / arg;
+ if (oldgamma + diff <= 0.0)
+ oldgamma = 0.0;
+ else
+ oldgamma += diff;
+ do_set_density(oldgamma, False, True);
+#if MOTIF
+ update_preferences_darkness();
+#endif
+}
+
+static void
+Act_fullscreen(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Dimension main_win_w, main_win_h;
+ static int orig_x = 0, orig_y = 0;
+#ifndef MOTIF
+ static Dimension get_x, get_y;
+#endif
+ static Dimension old_w = 0, old_h = 0;
+ Dimension panel_width = 0;
+#if 0
+ static Dimension w_old = 0, h_old = 0;
+#endif
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!toggle_arg(resource.fullscreen, params, num_params)) {
+ return;
+ }
+
+ resource.fullscreen = !resource.fullscreen;
+
+#ifndef MOTIF
+ panel_width = get_panel_width();
+#endif
+
+ if (resource.fullscreen) {
+ /* when toggling to fullscreen, save current scrollbar values
+ and window geometry */
+ XtVaGetValues(globals.widgets.top_level, XtNwidth, &old_w, XtNheight, &old_h, NULL);
+ /* fprintf(stderr, "saved geometry: %dx%d\n", old_w, old_h); */
+#ifdef MOTIF
+ if (globals.widgets.x_bar != NULL)
+ XtVaGetValues(globals.widgets.x_bar, XmNvalue, &orig_x, NULL);
+ if (globals.widgets.y_bar != NULL)
+ XtVaGetValues(globals.widgets.y_bar, XmNvalue, &orig_y, NULL);
+#else
+ get_xy();
+ if (globals.widgets.x_bar != NULL)
+ XtVaGetValues(globals.widgets.clip_widget, XtNx, &get_x, NULL);
+ if (globals.widgets.y_bar != NULL)
+ XtVaGetValues(globals.widgets.clip_widget, XtNy, &get_y, NULL);
+ orig_x = -(get_x - window_x);
+ orig_y = -(get_y - window_y);
+#endif /* MOTIF */
+ /* fprintf(stderr, "Current offsets: %d, %d, %d, %d\n", orig_x, window_x, orig_y, window_y); */
+ }
+#if 0 /* TODO: don't hardcode w/h values -
+ what's wrong with the set_windowsize() call below? */
+ if (resource.fullscreen) {
+ XWindowAttributes attr;
+ if (XGetWindowAttributes(DISP, XtWindow(globals.widgets.top_level), &attr)) {
+ w_old = attr.width;
+ h_old = attr.height;
+ }
+ main_win_w = WidthOfScreen(SCRN);
+ main_win_h = HeightOfScreen(SCRN);
+ }
+ else if (w_old > 0 && h_old > 0) {
+ main_win_w = w_old;
+ main_win_h = h_old;
+ }
+ else {
+ main_win_w = 800;
+ main_win_h = 600;
+ }
+#else
+ if (resource.fullscreen) {
+ set_windowsize(&main_win_w, &main_win_h, panel_width, 0, False);
+ }
+ else { /* re-use old window sizes, or initialize them if started in fullscreen mode */
+ if (old_w == 0 || old_h == 0) /* started in fullscreen mode */
+ set_windowsize(&old_w, &old_h, panel_width, 0, False);
+ else
+ set_windowsize(&old_w, &old_h, panel_width, 0, True);
+ }
+#endif
+
+/* fprintf(stderr, "reconfigure window!\n"); */
+ if (resource.fullscreen)
+ reconfigure_window(resource.fullscreen, main_win_w, main_win_h, True);
+ else {
+ reconfigure_window(resource.fullscreen, old_w, old_h, True);
+ }
+
+ /* fprintf(stderr, "orig values: %d, %d\n", orig_x, orig_y); */
+ /* restore horizontal scroll position */
+ if (resource.keep_flag && orig_x != 0 && globals.widgets.x_bar != NULL) {
+#ifdef MOTIF
+ if (!resource.fullscreen) {
+ /* only scroll back in non-fullscreen mode. This was:
+ if (resource.fullscreen)
+ (void)set_bar_value(globals.widgets.y_bar, orig_y, (int)(globals.page.h - mane.height));
+ else ...
+ but that was broken (bogus values in globals.page.h - mane.height).
+ */
+ (void)set_bar_value(globals.widgets.x_bar, orig_x, INT_MAX);
+ }
+#else
+ int curr_x;
+ get_xy();
+ XtVaGetValues(globals.widgets.clip_widget, XtNx, &get_x, NULL);
+ curr_x = -(get_x - window_x);
+ if (curr_x - orig_x > 0)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)(curr_x - orig_x));
+#endif /* MOTIF */
+ }
+
+ /* restore vertical scroll position */
+ if (resource.keep_flag && orig_y != 0 && globals.widgets.y_bar != NULL) {
+#ifdef MOTIF
+ if (!resource.fullscreen) {
+ /* only scroll back in non-fullscreen mode. This was:
+ if (resource.fullscreen)
+ (void)set_bar_value(globals.widgets.y_bar, orig_y, (int)(globals.page.h - mane.height));
+ else ...
+ but that was broken (bogus values in globals.page.h - mane.height).
+ */
+ (void)set_bar_value(globals.widgets.y_bar, orig_y, INT_MAX);
+ }
+#else
+ int curr_y;
+ get_xy();
+ XtVaGetValues(globals.widgets.clip_widget, XtNy, &get_y, NULL);
+ curr_y = -(get_y - window_y);
+ if (curr_y - orig_y > 0)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)(curr_y - orig_y));
+#endif /* MOTIF */
+ }
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+#ifdef GREY
+
+static void
+Act_set_greyscaling(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ warn_num_params("set-greyscaling()", params, *num_params, 1);
+
+ if (!get_int_arg(params, num_params, &arg)) { /* no arg, toggle */
+ if (!toggle_arg(resource.use_grey, params, num_params)) {
+ return;
+ }
+ resource.use_grey = !resource.use_grey;
+ if (resource.use_grey) {
+ statusline_print(STATUS_SHORT, "greyscaling on");
+ }
+ else {
+ statusline_print(STATUS_SHORT, "greyscaling off");
+ }
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ return;
+ }
+
+ switch (arg) {
+ case 0:
+ resource.use_grey = False;
+ statusline_print(STATUS_SHORT, "greyscaling off");
+ break;
+ case 1:
+ resource.use_grey = True;
+ statusline_print(STATUS_SHORT, "greyscaling on");
+ break;
+ default:
+ {
+ float newgamma = arg != 0 ? arg / 100.0 : 1.0;
+ resource.use_grey = newgamma;
+ statusline_print(STATUS_SHORT, "greyscale value: %.1f", newgamma);
+ }
+ }
+
+ /* like elsewhere */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ if (resource.use_grey) {
+ if (G_visual->class != TrueColor)
+ init_plane_masks();
+#if COLOR
+ fg_active = NULL;
+#else
+ init_pix();
+#endif
+ }
+ reset_fonts();
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+#endif
+
+#if COLOR
+
+void
+do_toggle_color(Boolean update_resource)
+{
+ if (resource.use_color) {
+ resource.use_color = False;
+ full_reset_colors();
+ scanned_page_color = total_pages;
+#if PS
+ if (ignore_papersize_specials || scanned_page_ps <= total_pages) {
+ scanned_page = scanned_page_ps;
+ }
+#endif
+ statusline_print(STATUS_SHORT, "color specials off");
+ }
+ else {
+ resource.use_color = True;
+ scanned_page = scanned_page_color = scanned_page_reset;
+ statusline_print(STATUS_SHORT, "color specials on");
+ }
+ if (update_resource)
+ globals.curr_use_color = resource.use_color;
+
+#ifdef MOTIF
+ update_preferences_color();
+#endif
+ globals.ev.flags |= EV_NEWPAGE;
+}
+
+static void
+Act_set_color(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (!toggle_arg(resource.use_color, params, num_params)) {
+ return;
+ };
+
+ /* like elsewhere */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ do_toggle_color(True);
+}
+
+#endif /* COLOR */
+
+#if PS
+
+void
+Act_set_ps(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(event);
+ UNUSED(w);
+
+ if (!get_int_arg(params, num_params, &arg))
+ resource.postscript++;
+ else
+ resource.postscript = arg;
+
+ if (resource.postscript > 2)
+ resource.postscript = 0;
+
+#ifdef PS_GS
+ if (!resource.useGS) {
+ if (resource.postscript > 0) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ "This version of xdvi depends on ghostscript for rendering Postscript images. "
+ "Postscript rendering cannot be activated if the option ``-noghostscript'' is used "
+ "or if the resource ``Ghostscript'' is set to false.",
+ /* message */
+ "Option ``-noghostscript'' is active; "
+ "cannot enable Postscript rendering without ghostscript.");
+ }
+ resource.postscript = 0;
+ }
+#endif
+ if (resource.postscript > 0) {
+ scanned_page_ps = scanned_page_ps_bak;
+ if (scanned_page > scanned_page_ps)
+ scanned_page = scanned_page_ps;
+ if (resource.postscript == 1) {
+ statusline_print(STATUS_SHORT, "Postscript rendering on");
+ }
+ else {
+ statusline_print(STATUS_SHORT, "Postscript rendering on (with bounding box)");
+ }
+ }
+ else {
+ scanned_page_ps_bak = scanned_page_ps;
+ scanned_page_ps = total_pages;
+#if COLOR
+ if (ignore_papersize_specials || scanned_page_color <= total_pages) {
+ scanned_page = scanned_page_color;
+ }
+#endif
+ statusline_print(STATUS_SHORT, "Postscript rendering off; displaying bounding box instead");
+ }
+
+ store_preference(NULL, "postscript", "%d", resource.postscript);
+
+ psp.toggle(resource.postscript);
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.postscript, Act_set_ps, check_int);
+#else
+ toggle_menu(resource.postscript, Act_set_ps);
+#endif /* NEW_MENU_CREATION */
+ /* like elsewhere */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ globals.ev.flags |= EV_PS_TOGGLE;
+ XFlush(DISP);
+}
+
+#endif /* PS */
+
+void
+Act_htex_back(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ htex_back();
+}
+
+void
+Act_htex_forward(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ htex_forward();
+}
+
+static void
+Act_htex_anchorinfo(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int x, y;
+ Window dummy;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &x, &y, &dummy);
+ htex_displayanchor(x, y);
+}
+
+#ifdef PS_GS
+void
+Act_set_gs_alpha(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (!toggle_arg(resource.gs_alpha, params, num_params)) {
+ return;
+ }
+ resource.gs_alpha = !resource.gs_alpha;
+
+ if (resource.gs_alpha) {
+ statusline_print(STATUS_SHORT, "ghostscript alpha active");
+ }
+ else {
+ statusline_print(STATUS_SHORT, "ghostscript alpha inactive");
+ }
+
+ store_preference(NULL, "gsAlpha", "%s", resource.gs_alpha ? "True" : "False");
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.gs_alpha, Act_set_gs_alpha, check_toggle);
+#else
+ toggle_menu(resource.gs_alpha, Act_set_gs_alpha);
+#endif /* NEW_MENU_CREATION */
+#if GS_PIXMAP_CLEARING_HACK
+ had_ps_specials = False; /* else infinite loop and/or crash in redraw! */
+#endif
+ /* like elsewhere */
+ if (globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ globals.ev.flags |= EV_PS_TOGGLE;
+ XFlush(DISP);
+}
+#endif
+
+static void
+Act_reread_dvi_file(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+/* fprintf(stderr, "reread file!\n"); */
+ globals.ev.flags |= EV_RELOAD;
+}
+
+static void
+Act_discard_number(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ m_have_arg = False;
+ m_number = 0;
+ m_sign = 1;
+ if (resource.expert_mode & XPRT_SHOW_STATUSLINE) /* too distracting for stdout */
+ statusline_print(STATUS_SHORT, "numerical prefix discarded");
+}
+
+/*
+ * Actions to support dragging the image.
+ */
+
+static int drag_last_x, drag_last_y; /* last position of cursor */
+
+static int text_last_x = -1;
+static int text_last_y = -1;
+static int text_last_page = -1;
+
+static void drag_motion(XEvent *);
+static void drag_release(XEvent *);
+
+/* access for hyperref.c */
+Boolean dragging_text_selection(void)
+{
+ MYTRACE((stderr, "dragging selection? %d", mouse_motion == text_motion));
+ return mouse_motion == text_motion;
+}
+
+static void
+text_release(XEvent * event)
+{
+ int ulx, uly, w, h;
+ static char *text;
+ int text_len = 0;
+
+ UNUSED(event);
+
+ MYTRACE((stderr, "text_release!"));
+
+ if (mouse_motion == null_mouse)
+ return;
+ mouse_motion = mouse_release = null_mouse;
+
+ w = text_last_x - drag_last_x;
+ h = text_last_y - drag_last_y;
+
+ if (w == 0 || h == 0) {
+ text_last_x = text_last_y = -1;
+ drag_last_x = drag_last_y = -1;
+ text_last_page = -1;
+ return;
+ }
+
+ if (w < 0) {
+ ulx = drag_last_x + w;
+ w = -w;
+ }
+ else
+ ulx = drag_last_x;
+
+ if (h < 0) {
+ uly = drag_last_y + h;
+ h = -h;
+ }
+ else
+ uly = drag_last_y;
+
+ free(text);
+ /* this allocates text */
+ text = get_text_selection(&text_len,
+ ulx * currwin.shrinkfactor,
+ uly * currwin.shrinkfactor,
+ (ulx + w) * currwin.shrinkfactor,
+ (uly + h) * currwin.shrinkfactor);
+ if (text[0] == '\0') {
+ /* fprintf(stdout, "Text selection empty.\n"); */
+ return;
+ }
+
+ TRACE_GUI((stderr, "Selected `%s'", text));
+
+ if (text_len > 4 * XMaxRequestSize(DISP) - 32) {
+ MYTRACE((stderr, "selection too large: %d bytes", text_len));
+ XBell(DISP, 10);
+ statusline_print(STATUS_MEDIUM, "Selection too large (%d bytes, maximum %d bytes)",
+ text_len, 4 * XMaxRequestSize(DISP) - 32);
+ MYTRACE((stderr, "after statusline_print1"));
+ return;
+ }
+
+ if (!set_selection(text, globals.widgets.top_level)) {
+ MYTRACE((stderr, "setting selection failed"));
+ XBell(DISP, 10);
+ statusline_print(STATUS_MEDIUM, "Could not set primary selection!");
+ MYTRACE((stderr, "after statusline_print2"));
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+ MYTRACE((stderr, "after text_change_region"));
+ }
+ MYTRACE((stderr, "End of text_release"));
+}
+
+void
+text_motion(XEvent *event)
+{
+ text_change_region(TEXT_SEL_MOVE, event);
+}
+
+static void
+get_rectangle(XRectangle *rect, int x, int y, int last_x, int last_y)
+{
+ rect->width = ABS(x - last_x);
+ rect->height = ABS(y - last_y);
+ rect->x = (x < last_x) ? x : last_x;
+ rect->y = (y < last_y) ? y : last_y;
+}
+
+static void
+crop_to_window(int *x, int *y)
+{
+ if (*x < -currwin.base_x + 1)
+ *x = -currwin.base_x + 1;
+ else if (*x > -currwin.base_x + (int)ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 1)
+ *x = -currwin.base_x + ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 1;
+
+ if (*y < -currwin.base_y + 1)
+ *y = -currwin.base_y + 1;
+ else if (*y > -currwin.base_y + (int)ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 1)
+ *y = -currwin.base_y + (int)ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 1;
+}
+
+void
+text_change_region(textSelectionT mode, XEvent *event)
+{
+ static GC bboxGC = 0;
+ static GC redrawGC = 0; /* needed since bboxGC is clipped to diff of old and new region */
+
+ MYTRACE((stderr, "text_change_region: %d", mode));
+
+ if (bboxGC == 0) {
+ XGCValues values;
+ unsigned long valuemask;
+
+ values.function = GXinvert; /* as in search code */
+ if (values.function == GXinvert) {
+ valuemask = GCFunction;
+ }
+ else {
+ values.foreground = WhitePixelOfScreen(SCRN) ^ BlackPixelOfScreen(SCRN);
+ /* fprintf(stderr, "foreground: 0x%lx, white pixel: 0x%lx, black pixel: 0x%lx\n", */
+ /* values.foreground, WhitePixelOfScreen(SCRN), BlackPixelOfScreen(SCRN)); */
+ valuemask = GCFunction | GCForeground;
+ }
+ values.line_width = 1;
+ valuemask |= GCLineWidth;
+ bboxGC = XCreateGC(DISP, XtWindow(globals.widgets.top_level), valuemask, &values);
+ redrawGC = XCreateGC(DISP, XtWindow(globals.widgets.top_level), valuemask, &values);
+ }
+
+ MYTRACE((stderr, "text_change_region: after bboxGC"));
+ switch (mode) {
+ case TEXT_SEL_MOVE:
+ {
+ int x, y;
+
+ Window dummy;
+
+ XRectangle redraw = { -1, -1, 0, 0 };
+
+ ASSERT(event != NULL, "event in text_change_region() musn't be NULL for TEXT_SEL_MOVE");
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y,
+ &x, &y,
+ &dummy);
+
+ crop_to_window(&x, &y);
+
+ get_rectangle(&redraw, x, y, drag_last_x, drag_last_y);
+
+ /*
+ * If we have an old region, we want to clip the GC to the area:
+ *
+ * (clip \cup redraw) - (clip \cap redraw)
+ *
+ * and redraw both rectangle areas; otherwise, just draw the redraw area.
+ */
+
+ if (text_last_x != -1 && text_last_y != -1) {
+
+ XRectangle clip = { -1, -1, 0, 0 };
+
+ Region clip_region = XCreateRegion();
+ Region redraw_region = XCreateRegion();
+ Region union_region = XCreateRegion();
+ Region intersect_region = XCreateRegion();
+
+ get_rectangle(&clip, text_last_x, text_last_y, drag_last_x, drag_last_y);
+
+ XUnionRectWithRegion(&clip, clip_region, clip_region);
+ XUnionRectWithRegion(&redraw, redraw_region, redraw_region);
+
+ XUnionRegion(clip_region, redraw_region, union_region);
+ XIntersectRegion(clip_region, redraw_region, intersect_region);
+
+ XSubtractRegion(union_region, intersect_region, redraw_region);
+
+ XSetRegion(DISP, bboxGC, redraw_region);
+
+ XDestroyRegion(clip_region);
+ XDestroyRegion(redraw_region);
+ XDestroyRegion(union_region);
+ XDestroyRegion(intersect_region);
+
+ XFillRectangle(DISP, mane.win, bboxGC, clip.x, clip.y, clip.width, clip.height);
+ }
+
+ XFillRectangle(DISP, mane.win, bboxGC, redraw.x, redraw.y, redraw.width, redraw.height);
+
+ text_last_x = x;
+ text_last_y = y;
+ text_last_page = current_page;
+ }
+ break;
+ case TEXT_SEL_CLEAR:
+ unset_selection(globals.widgets.top_level);
+ case TEXT_SEL_ERASE:
+ case TEXT_SEL_REDRAW:
+ if (text_last_page == current_page
+ && text_last_x != -1 && text_last_y != -1
+ && drag_last_x != -1 && drag_last_y != -1) {
+
+ XRectangle clear = { -1, -1, 0, 0 };
+
+ get_rectangle(&clear, text_last_x, text_last_y, drag_last_x, drag_last_y);
+
+ if (mode == TEXT_SEL_CLEAR) {
+ text_last_x = text_last_y = drag_last_x = drag_last_y = -1;
+ text_last_page = -1;
+ /* Note ZLB: the region is erased instead of inverted to avoid
+ * multiple inverting problem. An exposure is generated to
+ * make the region redrawn */
+ clearexpose(&mane, clear.x, clear.y, clear.width, clear.height);
+ }
+ else if (clip_region_to_rect(&clear)) {
+ if (mode == TEXT_SEL_ERASE) {
+ /* If width or height are 0, XClearArea will clear entire window
+ * from coordinates x, y, so check for that: */
+ if (clear.width > 0 && clear.height > 0)
+ XClearArea(DISP, mane.win, clear.x, clear.y, clear.width, clear.height, False);
+ }
+ else
+ XFillRectangle(DISP, mane.win, redrawGC, clear.x, clear.y, clear.width, clear.height);
+ }
+ }
+ break;
+ }
+ MYTRACE((stderr, "text_change_region: done"));
+}
+
+void
+text_selection_start(XEvent *event)
+{
+ int x, y;
+ Window dummy;
+
+ /* erase existing region */
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y,
+ &x, &y,
+ &dummy); /* throw away last argument */
+
+ crop_to_window(&x, &y);
+
+ drag_last_x = x;
+ drag_last_y = y;
+
+ text_last_x = text_last_y = -1;
+
+ MYTRACE((stderr, "selection start; mouse_release: %p; null: %p!",
+ (void *)mouse_release, (void *)null_mouse));
+ if (mouse_release == null_mouse) {
+ MYTRACE((stderr, "init text_motion!"));
+ mouse_motion = text_motion;
+ mouse_release = text_release;
+ }
+}
+
+/*
+ * If action list for <Btn1Down> does NOT contain a magnifier() binding,
+ * return that action list; else return NULL.
+ */
+static char *
+btn1_no_magnifier_binding(void)
+{
+ static Boolean initialized = False;
+ static char *btn1_binding = NULL;
+
+ if (!initialized) { /* cache value of previous calls */
+ if (resource.main_translations != NULL) {
+ if ((btn1_binding = strstr(resource.main_translations, "<Btn1Down>")) != NULL) {
+ char *eol, *test;
+ btn1_binding = strchr(btn1_binding, ':');
+ if (btn1_binding != NULL)
+ btn1_binding++;
+ while (isspace((int)*btn1_binding))
+ btn1_binding++;
+ eol = strchr(btn1_binding, '\n');
+ if (eol == NULL)
+ eol = btn1_binding + strlen(btn1_binding);
+ if ((test = strstr(btn1_binding, "magnifier(")) == NULL || test > eol) {
+ /* binding not found */
+ return btn1_binding;
+ }
+ }
+ }
+/* fprintf(stderr, "MAG: %d\n", btn1_has_magnifier); */
+ initialized = True;
+ }
+ return btn1_binding;
+}
+
+void
+Act_switch_mode(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ mouseModeT prev_mode = resource.mouse_mode;
+ int arg = -1;
+ char *ptr;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+
+ if ((ptr = btn1_no_magnifier_binding()) != NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_MEDIUM,
+ "Cannot switch modes: Action list for Btn1Down (%s) "
+ "does not contain magnifier() action.", ptr);
+ return;
+ }
+
+/* fprintf(stderr, "prev mode: %d\n", prev_mode); */
+
+ if (get_int_arg(params, num_params, &arg)) {
+ if (arg < MOUSE_MAGNIFIER_MODE || arg >= MOUSE_MAX_MODE) {
+ statusline_print(STATUS_SHORT, "Argument for Act_switch_mode outside of range from %d to %d",
+ MOUSE_MAGNIFIER_MODE, MOUSE_MAX_MODE - 1);
+ resource.mouse_mode++;
+ }
+ else
+ resource.mouse_mode = (mouseModeT)arg;
+ }
+ else
+ resource.mouse_mode++;
+
+ /* check if wrapped */
+ if (resource.mouse_mode >= MOUSE_MAX_MODE)
+ resource.mouse_mode = MOUSE_MAGNIFIER_MODE;
+
+ /* undo effects of previous mode */
+ switch (prev_mode) {
+ case MOUSE_RULER_MODE:
+ clear_ruler();
+ mouse_motion = mouse_release = null_mouse;
+ break;
+ case MOUSE_TEXT_MODE:
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+ mouse_motion = mouse_release = null_mouse;
+ break;
+ default: /* magnifier, nothing to do */
+ break;
+ }
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE) {
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.rule);
+ statusline_print(STATUS_SHORT, "Ruler mode; click Mouse-1 to set ruler");
+ show_ruler(event);
+ show_distance_from_ruler(event, False);
+ }
+ else if (resource.mouse_mode == MOUSE_TEXT_MODE) {
+ statusline_print(STATUS_SHORT, "Text selection mode; click and drag Mouse-1 to select a region");
+ }
+ else { /* default: MOUSE_MAGNIFIER_MODE */
+ statusline_print(STATUS_SHORT, "Magnifier mode; click Mouse-1 to magnify text");
+ mouse_motion = mouse_release = null_mouse;
+ }
+
+ globals.ev.flags |= EV_CURSOR;
+ XFlush(DISP);
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.mouse_mode, Act_switch_mode, check_int);
+#else
+ toggle_menu(resource.mouse_mode, Act_switch_mode);
+#endif /* NEW_MENU_CREATION */
+ store_preference(NULL, "mouseMode", "%d", resource.mouse_mode);
+}
+
+static void
+Act_text_mode(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ char *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ if ((ptr = btn1_no_magnifier_binding()) != NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_MEDIUM,
+ "Cannot switch modes: Action list for Btn1Down (%s) "
+ "does not contain magnifier() action.", ptr);
+ return;
+ }
+
+ if (resource.mouse_mode == MOUSE_TEXT_MODE) {
+ resource.mouse_mode++;
+ if (resource.mouse_mode >= MOUSE_MAX_MODE)
+ resource.mouse_mode = MOUSE_MAGNIFIER_MODE;
+ }
+ else
+ resource.mouse_mode = MOUSE_TEXT_MODE;
+
+ if (resource.mouse_mode == MOUSE_TEXT_MODE) {
+ if (mouse_release != null_mouse && mouse_release != text_release)
+ return;
+
+ globals.ev.flags |= EV_CURSOR;
+
+ XFlush(DISP);
+ }
+ else {
+ mouse_motion = mouse_release = null_mouse;
+ globals.ev.flags |= EV_CURSOR;
+
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+
+ XFlush(DISP);
+ }
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.mouse_mode, Act_switch_mode, check_int);
+#else
+ toggle_menu(resource.mouse_mode, Act_switch_mode);
+#endif /* NEW_MENU_CREATION || MOTIF */
+}
+
+static void
+Act_drag(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (mouse_release != null_mouse && mouse_release != drag_release)
+ return;
+
+ if (resource.mouse_mode == MOUSE_TEXT_MODE && text_last_page != -1
+ /* this was:
+ && (text_last_x != drag_last_x || text_last_y != drag_last_y)
+ but that isn't restrictive enough */
+ ) { /* dragging would mess up region drawing */
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Dragging page not possible while selection is active");
+ return;
+ }
+
+ if (*num_params != 1) {
+ XDVI_WARNING((stderr, "drag() requires 1 argument (got %d)", *num_params));
+ return;
+ }
+ switch (**params) {
+ case '|':
+ globals.cursor.flags |= CURSOR_DRAG_V;
+ break;
+ case '-':
+ globals.cursor.flags |= CURSOR_DRAG_H;
+ break;
+ case '+':
+ globals.cursor.flags |= CURSOR_DRAG_A;
+ break;
+ default:
+ XDVI_WARNING((stderr, "drag(): Valid arguments are `+', `|' or `-'"));
+ }
+
+ globals.ev.flags |= EV_CURSOR;
+
+ if (mouse_release == null_mouse) {
+ mouse_motion = drag_motion;
+ mouse_release = drag_release;
+ drag_last_x = event->xbutton.x_root;
+ drag_last_y = event->xbutton.y_root;
+ }
+ else
+ drag_motion(event);
+
+ XFlush(DISP);
+}
+
+
+static void
+drag_motion(XEvent * event)
+{
+#ifdef MOTIF
+ get_xy();
+#endif
+
+ if (globals.cursor.flags & (CURSOR_DRAG_H | CURSOR_DRAG_A)) { /* horizontal motion */
+#ifdef MOTIF
+ (void)set_bar_value(globals.widgets.x_bar,
+ drag_last_x - event->xbutton.x_root - window_x,
+ (int)(globals.page.w - mane.width));
+#else
+ if (globals.widgets.x_bar != NULL) {
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc,
+ (XtPointer) (drag_last_x - event->xbutton.x_root));
+ }
+#endif
+ drag_last_x = event->xbutton.x_root;
+ }
+
+ if (globals.cursor.flags & (CURSOR_DRAG_V | CURSOR_DRAG_A)) { /* vertical motion */
+#ifdef MOTIF
+ (void)set_bar_value(globals.widgets.y_bar,
+ drag_last_y - event->xbutton.y_root - window_y,
+ (int)(globals.page.h - mane.height));
+#else
+ if (globals.widgets.y_bar != NULL) {
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc,
+ (XtPointer) (drag_last_y - event->xbutton.y_root));
+ }
+#endif
+ drag_last_y = event->xbutton.y_root;
+ }
+ handle_x_scroll(NULL, NULL, NULL, NULL);
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+
+static void
+drag_release(XEvent * event)
+{
+ drag_motion(event);
+ mouse_motion = mouse_release = null_mouse;
+
+ globals.cursor.flags &= ~(CURSOR_DRAG_H | CURSOR_DRAG_V | CURSOR_DRAG_A);
+ globals.ev.flags |= EV_CURSOR;
+ XFlush(DISP);
+}
+
+
+
+/* Wheel mouse support. */
+
+static int wheel_button = -1;
+
+static void
+Act_wheel(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int dist;
+
+ UNUSED(w);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (*num_params != 1) {
+ XDVI_WARNING((stderr, "wheel() requires 1 argument (got %d)", *num_params));
+ return;
+ }
+ dist = (strchr(*params, '.') == NULL) ? atoi(*params)
+ : (int)(my_atof(*params) * resource.wheel_unit);
+#ifdef MOTIF
+ get_xy();
+ set_bar_value(globals.widgets.y_bar, dist - window_y, (int)(globals.page.h - mane.height));
+#else
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer) dist);
+#endif
+
+ wheel_button = event->xbutton.button;
+
+ handle_y_scroll(NULL, NULL, NULL, NULL);
+}
+
+
+/* Internal mouse actions. */
+
+static void
+Act_motion(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ /* remember last position, to do this only when pointer is actually moved */
+ static int old_x = -1, old_y = -1;
+ int x, y;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event()) {
+ MYTRACE((stderr, "returning!"));
+ return;
+ }
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE) {
+ show_distance_from_ruler(event, False);
+ }
+ /* This used to be:
+ (abs(x - old_x) > x_threshold || abs(y - old_y) > y_threshold))
+ but that didn't work too well either. Just change it whenever user
+ moves the mouse. */
+ if (!MAGNIFIER_ACTIVE && resource.mouse_mode != MOUSE_RULER_MODE
+ && pointerlocate(&x, &y) && (x != old_x || y != old_y)) {
+ htex_displayanchor(x, y);
+ old_x = x;
+ old_y = y;
+ }
+
+ if ((int)(event->xbutton.button) != wheel_button) {
+ mouse_motion(event);
+ }
+}
+
+
+static void
+Act_release(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ if ((int)(event->xbutton.button) == wheel_button) {
+ wheel_button = -1;
+ return;
+ }
+
+ mouse_release(event);
+}
+
+void
+Act_ruler_mode(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ char *ptr;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ if ((ptr = btn1_no_magnifier_binding()) != NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_MEDIUM,
+ "Cannot switch modes: Action list for Btn1Down (%s) "
+ "does not contain magnifier() action.", ptr);
+ return;
+ }
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE) {
+ resource.mouse_mode++;
+ if (resource.mouse_mode >= MOUSE_MAX_MODE)
+ resource.mouse_mode = MOUSE_MAGNIFIER_MODE;
+ }
+ else
+ resource.mouse_mode = MOUSE_RULER_MODE;
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE) {
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.rule);
+ statusline_print(STATUS_SHORT, "Ruler mode on; use Mouse-1 to set/drag ruler");
+ show_ruler(event);
+ show_distance_from_ruler(event, False);
+ }
+ else {
+ if (globals.cursor.flags & CURSOR_LINK) {
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.link);
+ }
+ else {
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.ready);
+ }
+ statusline_print(STATUS_SHORT, "Ruler mode off");
+ clear_ruler();
+ mouse_motion = mouse_release = null_mouse;
+ }
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.mouse_mode, Act_switch_mode, check_int);
+#else
+ toggle_menu(resource.mouse_mode, Act_switch_mode);
+#endif /* NEW_MENU_CREATION || MOTIF */
+}
+
+
+/* Actions for source specials. */
+
+void
+Act_source_special(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Window dummy;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ if ((event->type == ButtonPress && mouse_release != null_mouse)
+ || MAGNIFIER_ACTIVE) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ source_reverse_x = event->xbutton.x;
+ source_reverse_y = event->xbutton.y;
+ if (event->xbutton.window != mane.win)
+ (void)XTranslateCoordinates(DISP,
+ RootWindowOfScreen(SCRN), mane.win,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ &source_reverse_x,
+ &source_reverse_y,
+ &dummy); /* throw away last argument */
+
+ source_reverse_x = (source_reverse_x + mane_base_x) * mane.shrinkfactor;
+ source_reverse_y = (source_reverse_y + mane_base_y) * mane.shrinkfactor;
+
+ globals.ev.flags |= EV_SRC;
+}
+
+void
+Act_show_source_specials(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ Boolean clear_statusline = False;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+
+ if (!get_int_arg(params, num_params, &arg))
+ arg = -1;
+ else
+ clear_statusline = True;
+
+ if ((event->type == ButtonPress && mouse_release != null_mouse)
+ || magnifier.win != (Window) 0) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ if (!(globals.ev.flags & EV_SRC)) {
+ source_reverse_x = -1;
+ source_show_all = (arg == 1 ? True : False);
+
+ globals.ev.flags |= EV_SRC;
+ }
+ if (clear_statusline)
+ statusline_clear();
+}
+
+void
+Act_source_what_special(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int my_x, my_y;
+ Window dummy;
+
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &my_x, &my_y, &dummy); /* throw away last argument */
+ my_x = (my_x + mane_base_x) * mane.shrinkfactor;
+ my_y = (my_y + mane_base_y) * mane.shrinkfactor;
+ source_reverse_search(my_x, my_y, False);
+}
+
+static void
+select_cb(const char *filename, void *data)
+{
+ UNUSED(data);
+ if (filename != NULL) {
+ TRACE_FILES((stderr, "new filename: |%s|", filename));
+
+ set_dvi_name_expand(filename);
+ current_page = 0; /* switch to first page */
+ close_old_filep();
+ globals.ev.flags |= EV_NEWDOC;
+ globals.ev.flags |= EV_PAGEHIST_INSERT;
+ }
+}
+
+static void
+Act_select_dvi_file(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ static struct filesel_callback cb; /* static so that we can pass its address */
+ int arg = -1;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (block_this_mouse_event())
+ return;
+
+ if (get_int_arg(params, num_params, &arg)) { /* try item from file history */
+ char *fname;
+ int dummy_page;
+
+ if (arg < 1) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_MEDIUM, "Error: File history number must be >= 1");
+ }
+ else if ((fname = file_history_get_elem(arg - 1, &dummy_page)) == NULL) {
+ statusline_print(STATUS_MEDIUM, "No file number %d in history (history size: %lu)",
+ arg, (unsigned long)file_history_size());
+ }
+ else {
+ file_history_open(fname);
+ }
+ return;
+ }
+
+ 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 = False;
+ cb.func_ptr = select_cb;
+ cb.data = NULL;
+
+ file_history_set_page(current_page);
+
+ XsraSelFile(globals.widgets.top_level, &cb);
+}
+
+/*
+ * If all GUI elements have been turned on/off, make this synonymous
+ * with expert mode off/on, so that next `x' keystroke does something
+ * reasonable.
+ */
+void
+update_expert_mode(void)
+{
+ if ((resource.expert_mode & (XPRT_SHOW_STATUSLINE | XPRT_SHOW_SCROLLBARS
+#ifdef MOTIF
+ | XPRT_SHOW_PAGELIST | XPRT_SHOW_TOOLBAR | XPRT_SHOW_MENUBAR
+#else
+ | XPRT_SHOW_BUTTONS
+#endif
+ )) == XPRT_SHOW_ALL) {
+ resource.expert = False;
+ }
+ else if ((resource.expert_mode & (XPRT_SHOW_STATUSLINE
+#ifdef MOTIF
+ | XPRT_SHOW_SCROLLBARS | XPRT_SHOW_PAGELIST
+ | XPRT_SHOW_TOOLBAR | XPRT_SHOW_MENUBAR
+#else
+ | BROKEN_RECONFIG ? 0 : XPRT_SHOW_SCROLLBARS | XPRT_SHOW_BUTTONS
+#endif
+ )) == XPRT_SHOW_NONE) {
+ resource.expert = True;
+ }
+}
+
+void
+Act_set_expert_mode(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int arg;
+ Boolean clear_statusline = False;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg))
+ arg = -1;
+ else
+ clear_statusline = True;
+
+ switch(arg) {
+ case 1:
+ resource.expert_mode ^= XPRT_SHOW_STATUSLINE;
+ toggle_statusline();
+ update_expert_mode();
+ break;
+ case 2:
+#ifndef MOTIF
+ /* show this warning only when not toggling global expert mode
+ (that's why it can't be inside toggle_scrollbars) */
+ if (BROKEN_RECONFIG) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ "Sorry - cannot toggle scrollbars with this X Version.\n"
+ "This version of XFree has a broken implementation of the viewportWidget, "
+ "which would break the layout if the scrollbars are toggled. "
+ "Versions that are known to work have a VendorRelease version below 4000 or above 4002. "
+ "You will need to update your XFree server to fix this.");
+ return;
+ }
+#endif
+ resource.expert_mode ^= XPRT_SHOW_SCROLLBARS;
+ toggle_scrollbars();
+ update_expert_mode();
+ break;
+
+#ifdef MOTIF
+ case 3:
+ resource.expert_mode ^= XPRT_SHOW_PAGELIST;
+ toggle_pagelist();
+ update_expert_mode();
+ break;
+
+ case 4: /* toolbar */
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ toggle_toolbar();
+ update_expert_mode();
+ break;
+
+ case 5:
+ resource.expert_mode ^= XPRT_SHOW_MENUBAR;
+ toggle_menubar();
+ update_expert_mode();
+ break;
+#else
+ case 3:
+/* fprintf(stderr, "sidebar\n"); */
+ resource.expert_mode ^= XPRT_SHOW_BUTTONS;
+ toggle_buttons();
+ update_expert_mode();
+ break;
+#endif
+ default:
+ /* warn 'em */
+ if (
+#ifdef MOTIF
+ arg > 5
+#else
+ arg > 3
+#endif
+ ) {
+ statusline_print(STATUS_SHORT, "Number %d too large for `set-expert-mode', using 0 (= toggle) instead.",
+ arg);
+ }
+ /* toggle all items */
+ resource.expert = !resource.expert;
+ if (resource.expert)
+ resource.expert_mode = XPRT_SHOW_NONE;
+ else
+ resource.expert_mode = XPRT_SHOW_ALL;
+
+ toggle_statusline();
+#ifndef MOTIF
+ if (!BROKEN_RECONFIG)
+ toggle_scrollbars();
+#else
+ toggle_scrollbars();
+#endif
+
+#ifdef MOTIF
+ toggle_pagelist();
+ toggle_toolbar();
+ toggle_menubar();
+#else
+ toggle_buttons();
+#endif
+ }
+
+#ifdef MOTIF
+ update_preferences_expert();
+#endif
+
+ store_preference(NULL, "expertMode", "%d", resource.expert_mode);
+
+ if (clear_statusline)
+ statusline_clear();
+}
+
+Boolean have_src_specials = False;
+static Boolean do_update_property = False;
+
+void
+handle_x_scroll(Widget w, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+#ifndef MOTIF
+ Dimension get_x = 0;
+#endif
+
+ UNUSED(w);
+ UNUSED(closure);
+ UNUSED(ev);
+ UNUSED(cont);
+
+ if (/* !resource.keep_flag || */ globals.widgets.x_bar == NULL)
+ return;
+
+#ifdef MOTIF
+ XtVaGetValues(globals.widgets.x_bar, XmNvalue, &m_x_scroll, NULL);
+#else
+ get_xy();
+ XtVaGetValues(globals.widgets.clip_widget, XtNx, &get_x, NULL);
+ m_x_scroll = get_x - window_x;
+ scroll_x_panner(m_x_scroll);
+#endif
+}
+
+void
+handle_y_scroll(Widget w, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+#ifndef MOTIF
+ Dimension get_y = 0;
+#endif
+
+ UNUSED(w);
+ UNUSED(closure);
+ UNUSED(ev);
+ UNUSED(cont);
+
+ if (/* !resource.keep_flag || */ globals.widgets.y_bar == NULL)
+ return;
+
+#ifdef MOTIF
+ XtVaGetValues(globals.widgets.y_bar, XmNvalue, &m_y_scroll, NULL);
+#else
+ get_xy();
+ XtVaGetValues(globals.widgets.clip_widget, XtNy, &get_y, NULL);
+ m_y_scroll = get_y - window_y;
+ scroll_y_panner(m_y_scroll);
+#endif
+}
+
+void
+handle_expose(Widget w, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+ struct WindowRec *windowrec = (struct WindowRec *)closure;
+
+ UNUSED(w);
+ UNUSED(cont);
+
+ if (windowrec == &magnifier) {
+ if (magnifier_stat < 0) { /* destroy upon exposure */
+ magnifier_stat = 0;
+ mag_release(ev);
+ return;
+ }
+ else
+ magnifier_stat = 0;
+ }
+
+ do_update_property = False;
+
+ if (have_src_specials && !MAGNIFIER_ACTIVE) {
+ do_update_property = True;
+ }
+
+ MYTRACE((stderr, "Expose!"));
+ expose(windowrec, (&(ev->xexpose))->x, (&(ev->xexpose))->y,
+ (unsigned int)(&(ev->xexpose))->width, (unsigned int)(&(ev->xexpose))->height);
+}
+
+
+void
+handle_property_change(Widget w, XtPointer junk,
+ XEvent *ev, Boolean *cont)
+{
+ char *prop_ret;
+ size_t prop_len;
+
+ UNUSED(w);
+ UNUSED(junk);
+ UNUSED(cont);
+
+ if ((&(ev->xproperty))->window != XtWindow(globals.widgets.top_level)) /* if spurious event */
+ return;
+
+ if ((&(ev->xproperty))->atom == atom_src_goto()) {
+ /* forward search requested */
+ if ((prop_len = property_get_data(XtWindow(globals.widgets.top_level), atom_src_goto(),
+ &prop_ret,
+ XGetWindowProperty)) == 0) {
+ TRACE_CLIENT((stderr, "property_get_data() failed for atom_src_goto()!"));
+ return;
+ }
+ TRACE_CLIENT((stderr, "got back atom_src_goto: |%s|", prop_ret));
+ globals.src.fwd_string = prop_ret;
+ globals.ev.flags |= EV_SRC;
+ }
+ else if ((&(ev->xproperty))->atom == atom_find_string()) {
+ /* string search requested */
+ if ((prop_len = property_get_data(XtWindow(globals.widgets.top_level), atom_find_string(),
+ &prop_ret,
+ XGetWindowProperty)) == 0) {
+ TRACE_CLIENT((stderr, "property_get_data() failed for atom_find_string()!"));
+ return;
+ }
+ TRACE_FIND((stderr, "got back atom_find_string: |%s|", prop_ret));
+ resource.find_string = prop_ret;
+ globals.ev.flags |= EV_FIND;
+ }
+ else if ((&(ev->xproperty))->atom == atom_reload()) {
+ /* like do_sigusr(); there's no data in this case. */
+ TRACE_CLIENT((stderr, "atom_reload()"));
+ globals.ev.flags |= EV_RELOAD;
+ }
+ else if ((&(ev->xproperty))->atom == atom_newdoc()) {
+ /* loading a new file */
+ FILE *new_fp;
+ if ((prop_len = property_get_data(XtWindow(globals.widgets.top_level), atom_newdoc(),
+ &prop_ret,
+ XGetWindowProperty)) == 0) {
+ TRACE_CLIENT((stderr, "property_get_data() returned zero length for atom_newdoc()"));
+ /* just raise it in this case */
+ XMapRaised(XtDisplay(globals.widgets.top_level), XtWindow(globals.widgets.top_level));
+ raise_message_windows();
+ return;
+ }
+ TRACE_CLIENT((stderr, "got back atom_newdoc: |%s|", prop_ret));
+ if ((new_fp = XFOPEN(prop_ret, "r")) == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL, "Loading %s failed: %s",
+ prop_ret, strerror(errno));
+ return;
+ }
+ set_dvi_name_expand(prop_ret);
+ /*FIXME: Here we would like to insert the first page of the new file
+ into the page history:
+
+ page_history_insert(0);
+
+ However, if the commandline had been:
+ xdvi -unique +5 file.dvi
+ then the following property change will change to page 5 and insert
+ page 5, so in this case two pages will be inserted by the xdvi invocation.
+ I guess to fix this we'd need a bitmask instead of 2 atoms to set both
+ features at the same time ...
+ */
+ globals.ev.flags |= EV_NEWDOC;
+ }
+ else if ((&(ev->xproperty))->atom == atom_newpage()) {
+ /* jumping to a different page */
+ int newpage;
+ char *testptr;
+ if ((prop_len = property_get_data(XtWindow(globals.widgets.top_level), atom_newpage(),
+ &prop_ret,
+ XGetWindowProperty)) == 0) {
+ TRACE_CLIENT((stderr, "property_get_data() failed for atom_newpage(): |%s|", prop_ret));
+ return;
+ }
+ TRACE_CLIENT((stderr, "got back atom_newpage: |%s|", prop_ret));
+ if (strcmp(prop_ret, "+") == 0) { /* special case: treat `+' as last page */
+ newpage = total_pages - 1;
+ }
+ else {
+ newpage = strtol(prop_ret, &testptr, 10) - 1;
+ if (*testptr != '\0') {
+ XDVI_FATAL((stderr, "Invalid page number: `%s'.", prop_ret));
+ }
+ }
+
+ if (newpage == total_pages - 1) { /* as in Act_goto_page() */
+ goto_page(check_goto_page(newpage), resource.keep_flag ? NULL : home, False);
+ search_signal_page_changed();
+ }
+ else {
+ goto_page(check_goto_tex_page(newpage), resource.keep_flag ? NULL : home, False);
+ search_signal_page_changed();
+ }
+ }
+ else if ((&(ev->xproperty))->atom == atom_raise()) {
+ XMapRaised(XtDisplay(globals.widgets.top_level), XtWindow(globals.widgets.top_level));
+ raise_message_windows();
+ }
+ else if ((&(ev->xproperty))->atom == atom_reread_prefs()) {
+ read_user_preferences(globals.widgets.top_level, ".xdvirc.tmp");
+ }
+}
+
+
+/*
+ * Signal routines. At the signal level, all we do is set flags.
+ */
+
+#ifndef FLAKY_SIGPOLL
+static RETSIGTYPE
+handle_sigpoll(int signo)
+{
+ UNUSED(signo);
+
+ globals.ev.ctr = 1;
+ event_freq = -1; /* forget Plan B */
+ sig_flags |= SF_POLL;
+# ifndef HAVE_SIGACTION
+ (void) signal(SIGPOLL, handle_sigpoll); /* reset the signal */
+# endif
+}
+#endif
+
+static RETSIGTYPE
+handle_sigterm(int signo)
+{
+ UNUSED(signo);
+
+ sig_flags |= SF_TERM;
+}
+
+static RETSIGTYPE
+handle_sigchld(int signo)
+{
+ UNUSED(signo);
+
+ sig_flags |= SF_CHLD;
+}
+
+static RETSIGTYPE
+handle_sigalrm(int signo)
+{
+ UNUSED(signo);
+
+ sig_flags |= SF_ALRM;
+}
+
+static RETSIGTYPE
+handle_sigusr(int signo)
+{
+ UNUSED(signo);
+
+ globals.ev.ctr = 1;
+ sig_flags |= SF_USR;
+}
+
+static RETSIGTYPE
+handle_sigsegv(int signo)
+{
+ UNUSED(signo);
+
+ XDVI_ABORT((stderr, "Segmentation fault - trying to clean up and aborting ..."));
+}
+
+static Boolean sigalarm_initialized = False;
+
+void
+setup_sigalarm(void)
+{
+#if HAVE_SIGACTION
+ struct sigaction a;
+
+ a.sa_handler = handle_sigalrm;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGALRM);
+ a.sa_flags = 0;
+ sigaction(SIGALRM, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGALRM, handle_sigalrm);
+#endif /* not HAVE_SIGACTION */
+
+ sigalarm_initialized = True;
+}
+
+/*
+ * Called from main to set up the signal handlers.
+ */
+void
+setup_signal_handlers(void)
+{
+#ifndef FLAKY_SIGPOLL
+ int sock_fd = ConnectionNumber(DISP);
+#endif
+#if HAVE_SIGACTION
+ struct sigaction a;
+#endif
+
+#ifndef FLAKY_SIGPOLL
+#if HAVE_SIGACTION
+ /* Subprocess handling, e.g., MakeTeXPK, fails on the Alpha without
+ this, because SIGPOLL interrupts the call of system(3), since OSF/1
+ doesn't retry interrupted wait calls by default. From code by
+ maj@cl.cam.ac.uk. */
+ a.sa_handler = handle_sigpoll;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGPOLL);
+ a.sa_flags = SA_RESTART;
+ sigaction(SIGPOLL, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGPOLL, handle_sigpoll);
+#endif /* not HAVE_SIGACTION */
+
+ prep_fd(sock_fd, False);
+#endif /* not FLAKY_SIGPOLL */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigterm;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGINT);
+ (void) sigaddset(&a.sa_mask, SIGQUIT);
+ (void) sigaddset(&a.sa_mask, SIGTERM);
+ (void) sigaddset(&a.sa_mask, SIGHUP);
+ a.sa_flags = SA_RESETHAND;
+ sigaction(SIGINT, &a, NULL);
+ sigaction(SIGQUIT, &a, NULL);
+ sigaction(SIGTERM, &a, NULL);
+ sigaction(SIGHUP, &a, NULL);
+ a.sa_handler = handle_sigsegv;
+ (void)sigemptyset(&a.sa_mask);
+ (void)sigaddset(&a.sa_mask, SIGSEGV);
+ a.sa_flags = 0;
+ sigaction(SIGSEGV, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGINT, handle_sigterm);
+ (void) signal(SIGQUIT, handle_sigterm);
+ (void) signal(SIGTERM, handle_sigterm);
+ (void) signal(SIGHUP, handle_sigterm);
+ (void)signal(SIGSEGV, handle_sigsegv);
+#endif /* not HAVE_SIGACTION */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigchld;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGCHLD);
+ a.sa_flags = 0;
+ sigaction(SIGCHLD, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGCHLD, handle_sigchld);
+#endif /* not HAVE_SIGACTION */
+
+#if HAVE_SIGACTION
+ a.sa_handler = handle_sigusr;
+ (void) sigemptyset(&a.sa_mask);
+ (void) sigaddset(&a.sa_mask, SIGUSR1);
+ a.sa_flags = 0;
+ sigaction(SIGUSR1, &a, NULL);
+#else /* not HAVE_SIGACTION */
+ (void) signal(SIGUSR1, handle_sigusr);
+#endif /* not HAVE_SIGACTION */
+
+ (void)sigemptyset(&all_signals);
+ (void)sigaddset(&all_signals, SIGPOLL);
+ (void)sigaddset(&all_signals, SIGINT);
+ (void)sigaddset(&all_signals, SIGQUIT);
+ (void)sigaddset(&all_signals, SIGTERM);
+ (void)sigaddset(&all_signals, SIGHUP);
+ (void)sigaddset(&all_signals, SIGCHLD);
+ (void)sigaddset(&all_signals, SIGALRM);
+ (void)sigaddset(&all_signals, SIGUSR1);
+ (void)sigaddset(&all_signals, SIGSEGV);
+
+}
+
+
+/*
+ * Mid-level signal handlers. These are called from within read_events(),
+ * and do the actual work appropriate for the given signal.
+ */
+
+/*
+ * Process-related routines. Call set_chld(xchild *) to indicate
+ * that a given child process should be watched for when it
+ * terminates. Call clear_chld() to remove the process from the
+ * list. When the child terminates, the record is removed from
+ * the list and xchild->proc is called.
+ * The caller can set the `io' member in xchild to a pointer to
+ * an xio structure for reading from the file descriptor; see
+ * psgs.c and util.c for examples.
+ */
+
+static struct xchild *child_recs = NULL; /* head of child process list */
+
+void
+set_chld(struct xchild *cp)
+{
+ cp->next = child_recs;
+ child_recs = cp;
+}
+
+void
+clear_chld(struct xchild *cp)
+{
+ struct xchild **cpp;
+ struct xchild *cp2;
+
+ if (child_recs == NULL) {
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "child_recs: %p\n", (void *)child_recs);
+ return;
+ }
+ for (cpp = &child_recs;;) {
+ cp2 = *cpp;
+ if (cp2 == cp)
+ break;
+ cpp = &cp2->next;
+ }
+ *cpp = cp->next;
+}
+
+static void
+do_sigchld(void)
+{
+ pid_t pid;
+ int status;
+
+ sig_flags &= ~SF_CHLD;
+
+#if ! HAVE_SIGACTION
+ (void) signal(SIGCHLD, handle_sigchld); /* reset the signal */
+#endif
+ for (;;) {
+#if HAVE_WAITPID
+ pid = waitpid(-1, &status, WNOHANG);
+#else
+ pid = wait3(&status, WNOHANG, NULL);
+#endif
+ if (pid == 0) break;
+
+ if (pid != -1) {
+ struct xchild **cpp;
+ struct xchild *cp;
+
+ for (cpp = &child_recs;;) {
+ cp = *cpp;
+ if (cp == NULL)
+ break;
+ if (cp->pid == pid) {
+ *cpp = cp->next; /* unlink it */
+ /* call exit reporting procedure for this child */
+ (cp->proc)(status, cp);
+ break;
+ }
+ cpp = &cp->next;
+ }
+ break;
+ }
+
+ if (errno == EINTR) continue;
+ if (errno == ECHILD) break;
+#if HAVE_WAITPID
+ perror("xdvi: waitpid");
+#else
+ perror("xdvi: wait3");
+#endif
+ break;
+ }
+}
+
+
+/*
+ * File-related routines. Call set_io() to indicate that a given fd
+ * should be watched for ability to input or output data. Call clear_io()
+ * to remove it from the list. When poll()/select() indicates that the fd
+ * is available for the indicated type of i/o, the corresponding routine
+ * is called. Call clear_io() to remove an fd from the list.
+ * Both set_io() and clear_io() can be called from within read_proc or
+ * write_proc (although turning an io descriptor on or off is better
+ * accomplished by setting the events flag in the xio structure, and
+ * in the corresponding pollfd structure if the pfd pointer is not NULL
+ * (it is always non-NULL when read_proc and write_proc are called)).
+ * We allocate space for one additional record in the pollfd array, to
+ * accommodate the fd for the X connection; this is done by initializing
+ * num_fds to 1 instead of zero.
+ */
+
+static struct xio *iorecs = NULL; /* head of xio list */
+
+#if HAVE_POLL
+static struct pollfd *fds = NULL;
+static int num_fds = 1; /* current number of fds */
+static int max_fds = 0; /* max allocated number of fds */
+static Boolean io_dirty= True; /* need to recompute fds[] array */
+#else
+static int numfds = 0;
+static fd_set readfds;
+static fd_set writefds;
+#endif
+
+void
+set_io(struct xio *ip)
+{
+ ip->next = iorecs;
+ iorecs = ip;
+
+#if HAVE_POLL
+ ++num_fds;
+ if (!io_dirty && num_fds <= max_fds) {
+ fds[num_fds - 1].fd = ip->fd;
+ fds[num_fds - 1].events = ip->xio_events;
+ ip->pfd = &fds[num_fds - 1];
+ }
+ else {
+ ip->pfd = NULL;
+ io_dirty = True;
+ }
+#else
+ if (numfds <= ip->fd) numfds = ip->fd + 1;
+#endif
+}
+
+void
+clear_io(struct xio *ip)
+{
+ struct xio **ipp;
+
+ for (ipp = &iorecs;;) {
+ struct xio *ip2;
+
+ ip2 = *ipp;
+ if (ip2 == ip) break;
+ ipp = &ip2->next;
+ }
+ *ipp = ip->next;
+
+#if HAVE_POLL
+ --num_fds;
+ io_dirty = True;
+#else
+# if FLAKY_SIGPOLL
+ numfds = ConnectionNumber(DISP);
+# else
+ numfds = (event_freq < 0 ? -1 : ConnectionNumber(DISP));
+# endif
+ for (ip = iorecs; ip != NULL; ip = ip->next)
+ if (ip->fd > numfds)
+ numfds = ip->fd;
+ ++numfds;
+#endif /* !HAVE_POLL */
+}
+
+static void
+do_sigpoll(void)
+{
+#if FLAKY_SIGPOLL
+ sig_flags &= ~SF_POLL;
+#else
+ struct xio *ip;
+
+ sig_flags &= ~SF_POLL;
+
+# if HAVE_POLL
+
+ if (io_dirty) {
+ struct pollfd *fp;
+
+ if (num_fds > max_fds) {
+ if (fds != NULL) free(fds);
+ fds = xmalloc(num_fds * sizeof *fds);
+ max_fds = num_fds;
+ fds->fd = ConnectionNumber(DISP);
+ fds->events = POLLIN;
+ }
+ fp = fds + 1;
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ fp->fd = ip->fd;
+ fp->events = ip->xio_events;
+ ip->pfd = fp;
+ ++fp;
+ }
+ io_dirty = False;
+ }
+
+ for (;;) {
+ if (poll(fds + 1, num_fds - 1, 0) >= 0)
+ break;
+
+ if (errno != EAGAIN && errno != EINTR) {
+ perror("xdvi: poll");
+ return;
+ }
+ }
+
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ int revents = ip->pfd->revents;
+ if (revents & POLLIN && ip->read_proc != NULL)
+ (void)(ip->read_proc)(ip->fd);
+ if (revents & POLLOUT && ip->write_proc != NULL)
+ (ip->write_proc)(ip->fd);
+ }
+
+# else
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (ip->xio_events & XIO_IN)
+ FD_SET(ip->fd, &readfds);
+ if (ip->xio_events & XIO_OUT)
+ FD_SET(ip->fd, &writefds);
+ }
+
+ for (;;) {
+ struct timeval tv;
+
+ tv.tv_sec = tv.tv_usec = 0;
+ if (select(numfds, &readfds, &writefds, (fd_set *) NULL, &tv) >= 0)
+ break;
+
+ if (errno != EAGAIN && errno != EINTR) {
+ perror("select (xdvi read_events)");
+ return;
+ }
+ }
+
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (FD_ISSET(ip->fd, &readfds) && ip->read_proc != NULL)
+ (void)(ip->read_proc)(ip->fd);
+ if (FD_ISSET(ip->fd, &writefds) && ip->write_proc != NULL)
+ (ip->write_proc)(ip->fd);
+ }
+
+# endif
+#endif /* not FLAKY_SIGPOLL */
+}
+
+
+/*
+ * Timer-related routines. Call set_timer() to set a timer a given number
+ * of milliseconds in the future. At that time, the timer will be cleared
+ * and the given procedure will be called with argument set to the struct
+ * passed to set_timer(). The timer routine may call set_timer() or
+ * cancel_timer().
+ */
+
+
+static struct xtimer *timers = NULL; /* head of timer list */
+
+static struct itimerval itv = {{0, 0}, {0, 0}};
+
+#ifndef timercmp
+#define timercmp(a, b, OP) (((a)->tv_sec OP (b)->tv_sec || \
+ ((a)->tv_sec == (b)->tv_sec && (a)->tv_usec OP (b)->tv_usec)))
+#endif /* timercmp */
+
+
+static void
+show_timers(char *what)
+{
+ struct xtimer *tp;
+ fprintf(stderr, "=======%s; timers:\n", what);
+ for (tp = timers; tp != NULL; tp = tp->next) {
+ fprintf(stderr, "timer %p: %lu\n", (void *)tp, (unsigned long)tp->when.tv_sec);
+ }
+ fprintf(stderr, "=======\n");
+}
+
+void
+set_timer(struct xtimer *tp, int ms)
+{
+ struct xtimer **tpp;
+ struct xtimer *tp2;
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: set_timer\n", __FILE__, __LINE__);
+
+ gettimeofday(&tp->when, NULL);
+ itv.it_value.tv_sec = ms / 1000;
+ itv.it_value.tv_usec = (ms % 1000) * 1000;
+ tp->when.tv_sec += itv.it_value.tv_sec;
+ tp->when.tv_usec += itv.it_value.tv_usec;
+ if (tp->when.tv_usec >= 1000000) {
+ tp->when.tv_usec -= 1000000;
+ ++tp->when.tv_sec;
+ }
+
+ for (tpp = &timers;;) { /* add timer to list */
+ tp2 = *tpp;
+ if (tp2 == NULL || timercmp(&tp->when, &tp2->when, <))
+ break;
+ tpp = &tp2->next;
+ }
+ tp->next = tp2;
+ *tpp = tp;
+
+ if (tpp == &timers) {
+ setitimer(ITIMER_REAL, &itv, NULL);
+ if (ms == 0)
+ sig_flags |= SF_ALRM;
+ }
+ if (globals.debug & DBG_EVENT)
+ show_timers("after set_timer");
+}
+
+void
+cancel_timer(struct xtimer *tp)
+{
+ struct xtimer **tpp;
+
+ if (globals.debug & DBG_EVENT)
+ show_timers("beginning of cancel_timer");
+
+ if (timers == NULL) {
+ fprintf(stderr, "%s:%d: BUG? timers == NULL!\n", __FILE__, __LINE__);
+ return;
+ }
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: cancel_timer %p from %p\n", __FILE__, __LINE__, (void *)&timers, (void *)tp);
+
+ ASSERT(timers != NULL, "timers in cancel_timer() mustn't be NULL");
+ for (tpp = &timers; ; ) { /* remove from list */
+
+ if (*tpp == tp)
+ break;
+ tpp = &(*tpp)->next;
+ }
+
+ *tpp = (*tpp)->next; /* unlink it */
+
+ if (timers == NULL) { /* cancel SIGALRM */
+ itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
+ setitimer(ITIMER_REAL, &itv, NULL);
+ }
+}
+
+#if XDVI_XT_TIMER_HACK
+/*
+ * Original comment by Paul:
+ * Newer versions of the Motif toolkit use the timer facility
+ * (XtAppAddTimeOut(), etc.) in the X Toolkit. Proper functioning of
+ * this mechanism, however, requires that the X Toolkit be in charge of
+ * blocking. Since xdvi does its own blocking, this means that we need
+ * to provide working alternatives to these X Toolkit routines (by
+ * redefining them ...).
+ * One symptom of the above-mentioned bug is that the printlog window
+ * eventually stops showing dvips progress until you move the mouse.
+ *
+ * Comment SU:
+ * Xdvik also uses XtAppAddTimeOut() in other places (hyperref/statusline/...),
+ * so we also need these redefinitions also in the Xaw version.
+ *
+ */
+
+static void xt_alarm (struct xtimer *);
+
+static struct xtimer *xt_free_timers = NULL;
+
+XtIntervalId
+XtAddTimeOut(unsigned long interval, XtTimerCallbackProc proc, XtPointer closure)
+{
+ return XtAppAddTimeOut(NULL, interval, proc, closure);
+}
+
+XtIntervalId
+XtAppAddTimeOut(XtAppContext app, unsigned long interval, XtTimerCallbackProc proc, XtPointer closure)
+{
+ struct xtimer *tp;
+
+ UNUSED(app);
+
+ /* FIXME: better way of checking this instead of static boolean sigalarm_initialized?
+ The following doesn't work, even after
+ sigaddset(&all_signals, SIGALRM);
+
+ static sigset_t sig_set;
+ (void)sigprocmask(0, NULL, &sig_set);
+ if (sigismember(&sig_set, SIGALRM))
+ ... OK ...
+ else
+ ... NOT OK ...
+ */
+ ASSERT(sigalarm_initialized, "Shouldn't invoke XtAppAddTimeOut() before setup_sigalarm()");
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "XtAppAddTimeOut: %lu msecs\n", interval);
+
+ if (xt_free_timers == NULL)
+ tp = xmalloc(sizeof *tp);
+ else {
+ tp = xt_free_timers;
+ xt_free_timers = xt_free_timers->next;
+ }
+
+ tp->proc = xt_alarm;
+ tp->xt_proc = proc;
+ tp->closure = closure;
+
+ set_timer(tp, interval);
+
+ if (globals.debug & DBG_EVENT)
+ show_timers("XtAppAddTimeOut");
+
+ return (XtIntervalId)tp;
+}
+
+void
+XtRemoveTimeOut(XtIntervalId id)
+{
+ struct xtimer *tp;
+
+ ASSERT(id != 0, "XtIntervalId argument in XtRemoveTimeOut() mustn't be NULL");
+ tp = (struct xtimer *)id;
+
+ /* Motif (2.1 on Solaris 9, 2003) sometimes calls XtRemoveTimeOut() after
+ the timer event has occurred, so we need to be sure not to remove
+ the timer record twice. */
+ if (tp->proc == NULL)
+ return;
+
+ cancel_timer(tp);
+
+ tp->next = xt_free_timers;
+ xt_free_timers = tp;
+
+ if (globals.debug & DBG_EVENT)
+ show_timers("XtRemoveTimeOut");
+}
+
+void
+xt_alarm(struct xtimer *tp)
+{
+ XtIntervalId id;
+
+ tp->proc = NULL; /* flag timer as used-up */
+ id = (XtIntervalId) tp;
+ (tp->xt_proc)(tp->closure, &id);
+
+ tp->next = xt_free_timers;
+ xt_free_timers = tp;
+
+ if (globals.debug & DBG_EVENT)
+ show_timers("xt_alarm");
+}
+#endif /* XDVI_XT_TIMER_HACK */
+
+static void
+do_sigalrm(void)
+{
+ struct timeval now;
+
+ sig_flags &= ~SF_ALRM;
+#ifndef HAVE_SIGACTION
+ (void) signal(SIGALRM, handle_sigalrm); /* reset the signal */
+#endif
+
+ gettimeofday(&now, NULL);
+
+ while (timers != NULL && timercmp(&timers->when, &now, <=)) {
+ struct xtimer *tp = timers;
+ timers = timers->next; /* unlink it _first_ */
+ (tp->proc)(tp);
+ }
+
+ if (timers != NULL) { /* set next timer */
+ int i;
+ itv.it_value.tv_sec = timers->when.tv_sec - now.tv_sec;
+ i = timers->when.tv_usec - now.tv_usec;
+ if (i < 0) {
+ --itv.it_value.tv_sec;
+ i += 1000000;
+ }
+ itv.it_value.tv_usec = i;
+
+ setitimer(ITIMER_REAL, &itv, NULL);
+ }
+}
+
+
+
+/*
+ * Handle SIGUSR1 signal. Pretty straightforward.
+ */
+
+static void
+do_sigusr(void)
+{
+ sig_flags &= ~SF_USR;
+#ifndef HAVE_SIGACTION
+ (void) signal(SIGUSR1, handle_sigusr); /* reset the signal */
+#endif
+ globals.ev.flags |= EV_RELOAD;
+}
+
+
+static void
+do_sigsegv(void)
+{
+ sig_flags &= ~SF_SEGV;
+#ifndef HAVE_SIGACTION
+ (void) signal(SIGSEGV, handle_sigsegv); /* reset the signal */
+#endif
+ handle_sigsegv(SIGSEGV);
+}
+
+
+/*
+ * Handle termination signals. Kill child processes, if permitted.
+ * Otherwise, leave it up to the caller. This is the only place where
+ * the EV_TERM event flag is set, and it can only happen if there's an
+ * active non-killable process. This should only happen if read_events()
+ * is called from one of a very few select locations.
+ */
+
+static void
+do_sigterm(void)
+{
+ struct xchild *cp;
+
+ sig_flags &= ~SF_TERM;
+
+ /* loop through child processes */
+ for (cp = child_recs; cp != NULL; cp = cp->next) {
+ if (cp->killable)
+ kill(cp->pid, SIGKILL);
+ }
+
+ /* SU: Unlike non-k xdvi, we don't care about whether all children have been
+ killed, since processes forked via fork_process() (e.g. the web browser)
+ may still continue running. So we just exit here.
+ */
+ xdvi_exit(EXIT_SUCCESS);
+
+ /* since xdvi_exit() may return, we mustn't do the following which
+ is in non-k xdvi, else we'll end up in a busy loop! I don't know
+ what's meant by `caller' here anyway ...
+
+ globals.ev.flags |= EV_TERM; /\* otherwise, let the caller handle it *\/
+ */
+}
+
+/*
+ * Since redrawing the screen is (potentially) a slow task, xdvi checks
+ * for incoming events while this is occurring. It does not register
+ * a work proc that draws and returns every so often, as the toolkit
+ * documentation suggests. Instead, it checks for events periodically
+ * (or not, if SIGPOLL can be used instead) and processes them in
+ * a subroutine called by the page drawing routine. This routine (below)
+ * checks to see if anything has happened and processes those events and
+ * signals. (Or, if it is called when there is no redrawing that needs
+ * to be done, it blocks until something happens.)
+ *
+ * Ultimately, the goal is to have this be the only place in xdvi where
+ * blocking occurs.
+ *
+ * The argument to this function should be a mask of event types (EV_*)
+ * indicating which event types should cause read_events to return instead
+ * of waiting for more events. This function will always process all
+ * pending events and signals before returning.
+ * The return value is the value of globals.ev.flags.
+ */
+
+unsigned int
+read_events(unsigned int ret_mask)
+{
+ XEvent event;
+
+#if !HAVE_POLL
+ if (numfds == 0)
+ numfds = ConnectionNumber(DISP) + 1;
+#endif
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: read_events %u\n", __FILE__, __LINE__, ret_mask);
+ for (;;) {
+ globals.ev.ctr = event_freq;
+ /*
+ * The above line clears the flag indicating that an event is
+ * pending. So if an event comes in right now, the flag will be
+ * set again needlessly, but we just end up making an extra call.
+ * Also, be careful about destroying the magnifying glass while
+ * drawing on it.
+ */
+
+#if !FLAKY_SIGPOLL
+
+ if (event_freq < 0) { /* if SIGPOLL works */
+ if (!XtPending()) {
+ sigset_t oldsig;
+
+ (void) sigprocmask(SIG_BLOCK, &all_signals, &oldsig);
+ for (;;) {
+#ifdef SHOW_SIG_FLAGS
+ /* this gives HUGE output ... */
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: sig_flags = %d\n",
+ __FILE__, __LINE__, sig_flags);
+#endif
+ while (sig_flags) {
+ flags_to_sigproc[sig_flags]();
+ }
+
+ if (XtPending())
+ break;
+
+ if (globals.ev.flags & ret_mask) {
+ (void) sigprocmask(SIG_SETMASK, &oldsig, (sigset_t *) NULL);
+ return globals.ev.flags;
+ }
+ (void) sigsuspend(&oldsig);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsig, (sigset_t *) NULL);
+ }
+ }
+ else
+
+#endif /* not FLAKY_SIGPOLL */
+
+ {
+ for (;;) {
+ struct xio *ip;
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: (flaky) sig_flags = %d\n",
+ __FILE__, __LINE__, sig_flags);
+ while (sig_flags) {
+ sigset_t oldsig;
+
+ (void) sigprocmask(SIG_BLOCK, &all_signals, &oldsig);
+
+ while (sig_flags) {
+ flags_to_sigproc[sig_flags]();
+ }
+
+ (void) sigprocmask(SIG_SETMASK, &oldsig,
+ (sigset_t *) NULL);
+ }
+
+ if (XtPending())
+ break;
+
+ if (globals.ev.flags & ret_mask)
+ return globals.ev.flags;
+
+ /* If a SIGUSR1 signal comes right now, then it will wait
+ until an X event or another SIGUSR1 signal arrives. */
+
+#if HAVE_POLL
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: have_poll!\n",
+ __FILE__, __LINE__);
+ if (io_dirty) {
+ struct pollfd *fp;
+
+ if (num_fds > max_fds) {
+ if (fds != NULL) free(fds);
+ fds = xmalloc(num_fds * sizeof *fds);
+ max_fds = num_fds;
+ fds->fd = ConnectionNumber(DISP);
+ fds->events = POLLIN;
+ }
+ fp = fds + 1;
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ fp->fd = ip->fd;
+ fp->events = ip->xio_events;
+ ip->pfd = fp;
+ ++fp;
+ }
+ io_dirty = False;
+ }
+
+ for (;;) {
+ if (poll(fds, num_fds, -1) >= 0) {
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ int revents = ip->pfd->revents;
+
+ if (revents & POLLIN && ip->read_proc != NULL)
+ (ip->read_proc)(ip->fd);
+ if (revents & POLLOUT && ip->write_proc != NULL)
+ (ip->write_proc)(ip->fd);
+ }
+ break;
+ }
+
+ if (errno == EINTR)
+ break;
+
+ if (errno != EAGAIN) {
+ perror("xdvi: poll");
+ break;
+ }
+ }
+#else /* HAVE_POLL */
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: NOT have_poll!\n",
+ __FILE__, __LINE__);
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_SET(ConnectionNumber(DISP), &readfds);
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (ip->xio_events & XIO_IN)
+ FD_SET(ip->fd, &readfds);
+ if (ip->xio_events & XIO_OUT)
+ FD_SET(ip->fd, &writefds);
+ }
+
+ for (;;) {
+ if (select(numfds, &readfds, &writefds, (fd_set *) NULL,
+ (struct timeval *) NULL) >= 0) {
+ for (ip = iorecs; ip != NULL; ip = ip->next) {
+ if (FD_ISSET(ip->fd, &readfds) && ip->read_proc != NULL) {
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: reading from %d\n",
+ __FILE__, __LINE__, ip->fd);
+ (ip->read_proc)(ip->fd);
+ }
+ if (FD_ISSET(ip->fd, &writefds) && ip->write_proc != NULL) {
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: writing to %d\n",
+ __FILE__, __LINE__, ip->fd);
+ (ip->write_proc)(ip->fd);
+ }
+ }
+ break;
+ }
+
+ if (errno == EINTR)
+ break;
+
+ if (errno != EAGAIN) {
+ perror("xdvi: select");
+ break;
+ }
+ }
+#endif /* HAVE_POLL */
+ }
+ }
+ XtAppNextEvent(app, &event);
+#ifdef MOTIF
+ if ((resource.expert_mode & XPRT_SHOW_TOOLBAR) != 0)
+ TipAppHandle(app, &event);
+#endif
+
+ if (resized)
+ get_geom();
+
+ if (event.xany.window == magnifier.win && event.type == Expose) {
+ handle_expose((Widget) NULL, (XtPointer) &magnifier, &event,
+ (Boolean *) NULL);
+ continue;
+ }
+ else if (globals.broken_motif_event_handling &&
+ (resource.mouse_mode == MOUSE_RULER_MODE ||
+ resource.mouse_mode == MOUSE_TEXT_MODE)) {
+ /* In this case, Act_motion() and Act_release() are not called properly
+ * for updating the ruler/text selection (it works with the magnifier though),
+ * so we need to invoke them ourselves here: */
+ if (event.type == MotionNotify)
+ Act_motion(NULL, &event, NULL, NULL);
+ else if (event.type == ButtonRelease)
+ Act_release(NULL, &event, NULL, NULL);
+ }
+
+#ifdef MOTIF
+ if (XtIsRealized(globals.widgets.top_level)
+ && event.xany.window == XtWindow(globals.widgets.clip_widget)
+ && event.type == KeyPress) { /* workaround for #610206 */
+ motif_translations_hack();
+ }
+#else
+ if (resource.expert_mode & XPRT_SHOW_BUTTONS)
+ SubMenuHandleEvent(app, &event);
+#endif
+ XtDispatchEvent(&event);
+ }
+}
+
+
+/*
+ * Higher-level routines for managing events.
+ */
+
+static void
+can_exposures(struct WindowRec *windowrec)
+{
+ windowrec->min_x = windowrec->min_y = MAXDIM;
+ windowrec->max_x = windowrec->max_y = 0;
+}
+
+void
+redraw(struct WindowRec *windowrec)
+{
+ currwin = *windowrec;
+ globals.win_expose.min_x = currwin.min_x + currwin.base_x;
+ globals.win_expose.min_y = currwin.min_y + currwin.base_y;
+ globals.win_expose.max_x = currwin.max_x + currwin.base_x;
+ globals.win_expose.max_y = currwin.max_y + currwin.base_y;
+ can_exposures(windowrec);
+
+ /* fix for bug #619070 - the complicated flags (and do_update_property)
+ are needed to avoid too many updates at exposures, especially for
+ a window of another xdvi instance when the magnifier intersects with
+ that window.
+ */
+ if (have_src_specials && do_update_property
+ && globals.win_expose.min_x != 1 && globals.win_expose.max_y - globals.win_expose.min_y != 1
+ && currwin.base_x == 0 && currwin.base_y == 0) {
+ update_window_property(XtWindow(globals.widgets.top_level), True);
+ }
+
+ TRACE_EVENTS((stderr, "Redraw %d x %d at (%d, %d) (base=%d,%d)",
+ globals.win_expose.max_x - globals.win_expose.min_x,
+ globals.win_expose.max_y - globals.win_expose.min_y,
+ globals.win_expose.min_x, globals.win_expose.min_y,
+ currwin.base_x, currwin.base_y));
+
+ /* can't use ev_cursor here, since the event loop might not see this change quick enough */
+ if (!(globals.ev.flags & EV_CURSOR)) {
+ TRACE_EVENTS((stderr, "Cursor: %ld", globals.cursor.flags));
+ if (!(globals.cursor.flags & (CURSOR_DRAG_H | CURSOR_DRAG_V | CURSOR_DRAG_A))) {
+ if (resource.mouse_mode == MOUSE_RULER_MODE)
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.rule);
+ else
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.wait);
+ XFlush(DISP);
+ }
+ globals.ev.flags |= EV_CURSOR;
+ }
+
+ /* No longer needed since windows are correctly transient now */
+ /* raise_message_windows(); */
+ raise_file_selector();
+ draw_page();
+ globals.warn_spec_now = False;
+}
+
+
+void
+redraw_page(void)
+{
+#if COLOR
+ const struct rgb *rgbp;
+#endif
+ TRACE_FILES((stderr, "Redraw page on %p", (void *)globals.dvi_file.bak_fp));
+
+ if (globals.dvi_file.bak_fp == NULL)
+ return;
+
+ if (scanned_page < current_page) {
+ TRACE_FILES((stderr, "redraw_page: scanned_page = %d, current_page = %d, prescanning %p\n",
+ scanned_page, current_page, (void *)globals.dvi_file.bak_fp));
+
+ prescan(globals.dvi_file.bak_fp);
+
+ if (globals.ev.flags & EV_GE_NEWPAGE) { /* if we need to re-prescan */
+ return;
+ }
+ }
+
+ TRACE_FILES((stderr, "redraw_page: current_page = %d", current_page));
+ if (pageinfo_get_window_width(current_page) != globals.page.unshrunk_w
+ || pageinfo_get_window_height(current_page) != globals.page.unshrunk_h) {
+ TRACE_FILES((stderr, "NEW SIZE: %dx%d",
+ pageinfo_get_window_width(current_page), pageinfo_get_window_height(current_page)));
+ init_page();
+ reconfig();
+ }
+
+ /* We can't call home() without proper unshrunk_page_*, which requires
+ * prescan(), which can't be done from within read_events() */
+
+ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ There's some complicated interaction with Postscript specials
+ here: if home_action check comes before the gs stuff, psp.drawfile
+ might not get initialized correctly, resulting in empty PS figures
+ (bounding box instead of figure). This is different in xdvi, due to
+ different handling of the home_action stuff, but at the moment I can't
+ remember the reason for this ...
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG ALERT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+#if PS_GS
+ if (gs_postpone_prescan) {
+ if (!setjmp(globals.ev.canit)) {
+ gs_resume_prescan();
+ }
+ else
+ return;
+ }
+#endif
+ if (home_action != NULL) {
+ home_action(False);
+ home_action = NULL;
+ /* This discards the expose event generated by home()
+ (1 for each page) */
+ if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE) {
+ return;
+ }
+
+ can_exposures(&mane);
+ }
+
+#if COLOR
+ rgbp = &bg_initial;
+ if (page_colors.stack != NULL) {
+ ASSERT(current_page < (int)page_colors.size, "page_colors.size too small");
+ rgbp = &page_colors.stack[current_page].bg;
+ }
+
+ /* Set background color */
+ if (bg_current == NULL
+ || rgbp->r != bg_current->color.r
+ || rgbp->g != bg_current->color.g
+ || rgbp->b != bg_current->color.b) {
+ struct bgrec **bgpp;
+
+ for (bgpp = &bg_head;;) {
+ bg_current = *bgpp;
+ if (bg_current == NULL) { /* if bg is not in list */
+ bg_current = *bgpp = xmalloc(sizeof *bg_current);
+ bg_current->next = NULL;
+ bg_current->color = *rgbp;
+ bg_current->fg_head = NULL;
+ bg_current->pixel_good = False;
+ break;
+ }
+ if (bg_current->color.r == rgbp->r
+ && bg_current->color.g == rgbp->g
+ && bg_current->color.b == rgbp->b)
+ break;
+ bgpp = &bg_current->next;
+ }
+ fg_current = NULL; /* force change of foreground color */
+ /* globals.gc.high is only used in XDrawRectangle, so its background color
+ doesn't need to be changed. */
+ if (globals.debug & DBG_DVI)
+ printf("Changing background color to %5d %5d %5d\n",
+ bg_current->color.r, bg_current->color.g,
+ bg_current->color.b);
+
+ if (!bg_current->pixel_good) {
+ bg_current->pixel = alloc_color(&bg_current->color,
+ color_data[1].pixel);
+ bg_current->pixel_good = True;
+ }
+ XSetWindowBackground(DISP, mane.win, bg_current->pixel);
+#if MOTIF && !FIXED_FLUSHING_PAGING
+ XtVaSetValues(XtParent(globals.widgets.draw_widget), XtNbackground, bg_current->pixel, NULL);
+#endif
+/* XSetWindowBackground(DISP, mane.win, bg_current->pixel); */
+/* XClearWindow(DISP, mane.win); */
+#if 0 /* don't recolor the cursor - gives too low contrast on color backgrounds,
+ and bad appearance when part of the background is white and cursor mask
+ is colored */
+ {
+ XColor bg_Color;
+ bg_Color.pixel = bg_current->pixel;
+ XQueryColor(DISP, G_colormap, &bg_Color);
+ XRecolorCursor(DISP, globals.cursor.ready, &globals.cr_color, &bg_Color);
+ XRecolorCursor(DISP, globals.cursor.wait, &globals.cr_color, &bg_Color);
+ }
+#endif
+ }
+#endif /* COLOR */
+
+ if (!globals.pausing.flag) {
+ XClearWindow(DISP, mane.win);
+ }
+
+ if (G_backing_store != NotUseful) {
+ mane.min_x = mane.min_y = 0;
+ mane.max_x = globals.page.w;
+ mane.max_y = globals.page.h;
+ }
+ else {
+ get_xy();
+ mane.min_x = -window_x;
+ mane.max_x = -window_x + mane.width;
+ mane.min_y = -window_y;
+ mane.max_y = -window_y + mane.height;
+ }
+
+/* update_TOC(); */
+ redraw(&mane);
+}
+
+void
+do_pages(void)
+{
+ if (globals.debug & DBG_BATCH) {
+
+ (void)read_events(EV_GT_IDLE);
+ for (current_page = 0; current_page < total_pages; ++current_page) {
+ if (resource.keep_flag) {
+ home_action = NULL;
+ }
+ else {
+ home_action = home;
+ }
+ globals.warn_spec_now = resource.warn_spec;
+#if PS_GS
+ for (;;) {
+ redraw_page();
+ (void) read_events(EV_NOWAIT);
+ if (!(globals.ev.flags & (EV_NEWPAGE | EV_NEWDOC | EV_RELOAD)))
+ break;
+ globals.ev.flags = EV_IDLE;
+ }
+#else
+ redraw_page();
+#endif
+ }
+ xdvi_exit(EXIT_SUCCESS);
+ }
+ else {
+ for (;;) { /* normal operation */
+ (void) read_events(EV_GT_IDLE);
+ TRACE_EVENTS((stderr, "globals.ev.flags: %d; ev_newpage: %d, ev_newdoc: %d, ev_reload: %d\n",
+ globals.ev.flags, EV_NEWPAGE, EV_NEWDOC, EV_RELOAD));
+ /* NOTE: reloading must be checked first! */
+ if (globals.ev.flags & (EV_NEWPAGE | EV_NEWDOC | EV_RELOAD | EV_PS_TOGGLE)) {
+ TRACE_EVENTS((stderr, "EV_NEWPAGE | ..."));
+ globals.ev.flags &= ~(EV_NEWPAGE | EV_EXPOSE | EV_PS_TOGGLE);
+ if (globals.ev.flags & EV_RELOAD) {
+ dviErrFlagT errflag;
+
+ globals.ev.flags &= ~EV_RELOAD;
+ if (load_dvi_file(True, &errflag)) {
+#if PS
+ ps_clear_cache();
+#if PS_GS
+ if (resource.gs_alpha) {
+ /* restart gs so that user has a method for fixing GS artifacts with gs_alpha
+ by using `reload' (see also GS_PIXMAP_CLEARING_HACK) */
+ ps_destroy();
+ }
+#endif
+#endif
+ statusline_print(STATUS_SHORT, "File reloaded.");
+ }
+/* else { */
+/* statusline_print(STATUS_MEDIUM, "File corrupted, not reloading."); */
+/* } */
+ }
+ if (globals.ev.flags & EV_NEWDOC) {
+ dviErrFlagT errflag;
+ TRACE_EVENTS((stderr, "EV_NEWDOC!"));
+/* fprintf(stderr, "newdoc!\n"); */
+ TRACE_FILES((stderr, "current page: %d", current_page));
+/* file_history_set_page(current_page); */
+ globals.ev.flags &= ~EV_NEWDOC;
+ if (load_dvi_file(True, &errflag)) {
+ statusline_append(STATUS_SHORT, "Opened ", "Opened \"%s\"", globals.dvi_name);
+/* statusline_print(STATUS_SHORT, "Opened \"%s\"", globals.dvi_name); */
+ TRACE_FILES((stderr, "Adding to history: |%s|\n", globals.dvi_name));
+ if (file_history_push(globals.dvi_name)) { /* it's a new file, add to history */
+ TRACE_FILES((stderr, "New entry!"));
+ filehist_menu_add_entry(globals.dvi_name);
+ }
+ else { /* only need to move existing elements to new positions */
+ TRACE_FILES((stderr, "Existing entry!\n"));
+ filehist_menu_refresh();
+ }
+ }
+ }
+
+ can_exposures(&mane);
+ can_exposures(&magnifier);
+
+#if PS && PS_GS && GS_PIXMAP_CLEARING_HACK
+ if (had_ps_specials && !MAGNIFIER_ACTIVE) {
+ erasepage_gs();
+ had_ps_specials = False;
+ }
+#endif /* PS && PS_GS && GS_PIXMAP_CLEARING_HACK */
+
+ if (globals.dvi_file.bak_fp != NULL) {
+ TRACE_EVENTS((stderr, "redraw_page()"));
+ redraw_page();
+ }
+ else {
+ TRACE_EVENTS((stderr, "dvi_file_changed()"));
+ (void)dvi_file_changed();
+ }
+ }
+ else if (globals.ev.flags & EV_FILEHIST_GOTO_PAGE) {
+ int pageno;
+ globals.ev.flags &= ~EV_FILEHIST_GOTO_PAGE;
+ pageno = check_goto_page(file_history_get_page());
+ goto_page(pageno, resource.keep_flag ? NULL : home, False);
+ TRACE_FILES((stderr, "got page: %d", pageno));
+ }
+ else if (globals.ev.flags & EV_PAGEHIST_INSERT) {
+ globals.ev.flags &= ~EV_PAGEHIST_INSERT;
+ page_history_insert(current_page);
+ }
+ else if (globals.ev.flags & EV_FIND_CANCEL) {
+ /* NOTE: This must be done before checking for expose() */
+ globals.ev.flags &= ~EV_FIND_CANCEL;
+ }
+ else if (globals.ev.flags & EV_ANCHOR) {
+ /*
+ * Similar to forward search: search for a htex anchor.
+ * This needs to come before the next case which does the redraw_page(),
+ * otherwise anchors for the current page might not be drawn at all:
+ * anchor_search() sets the info later used by htex_draw_anchormarkers(),
+ * which is invoked by redraw_page().
+ */
+
+ /* switch off the link cursor */
+ globals.cursor.flags &= ~CURSOR_LINK;
+
+ if (dvi_file_changed())
+ continue;
+
+ anchor_search(g_anchor_pos);
+ globals.ev.flags &= ~EV_ANCHOR;
+ }
+ else if (globals.ev.flags & EV_SRC) {
+ /*
+ * Source special operations are deferred to here because
+ * they call geom_scan(), which may call define_font(),
+ * which may call makefont(), which may call read_events()
+ * recursively.
+ */
+ if (globals.src.fwd_string != NULL) {
+ const char *s = globals.src.fwd_string;
+
+ if (dvi_file_changed())
+ continue;
+
+ source_forward_search(s);
+ globals.ev.flags &= ~EV_SRC;
+ globals.src.fwd_string = NULL;
+
+ /* de-iconify window if needed, and raise it */
+ XMapRaised(XtDisplay(globals.widgets.top_level), XtWindow(globals.widgets.top_level));
+ raise_message_windows();
+ }
+ else if (source_reverse_x != -1) {
+ if (dvi_file_changed())
+ continue;
+
+ source_reverse_search(source_reverse_x, source_reverse_y, True);
+ globals.ev.flags &= ~EV_SRC;
+ }
+ else {
+ source_special_show(source_show_all);
+ globals.ev.flags &= ~EV_SRC;
+ }
+ }
+ /* support for `-findstring' */
+ else if (globals.ev.flags & EV_FIND) {
+ if (dvi_file_changed())
+ continue;
+
+ if (resource.find_string != NULL) { /* not first call */
+ dvi_find_string(resource.find_string, False);
+ resource.find_string = NULL;
+ }
+ else { /* actually should never arrive here?? */
+ dvi_find_string(NULL, True);
+ }
+ globals.ev.flags &= ~EV_FIND;
+ }
+ else if (globals.ev.flags & EV_MAG_MOVE) {
+ MYTRACE((stderr, "moving mag!"));
+ move_magnifier();
+ }
+ else if (globals.ev.flags & EV_EXPOSE) {
+ if (magnifier.min_x < MAXDIM) {
+/* fprintf(stderr, "magnifier < maxdim!\n"); */
+ if (mane.min_x >= MAXDIM) {
+/* fprintf(stderr, "mane >= maxdim!\n"); */
+ globals.ev.flags &= ~EV_EXPOSE;
+ }
+ redraw(&magnifier);
+ }
+ else {
+ /* see comment in mag.c */
+ globals.ev.flags &= ~EV_EXPOSE;
+ if (mane.min_x < MAXDIM) {
+ redraw(&mane);
+ }
+ }
+ }
+ else if (globals.ev.flags & EV_CURSOR) {
+ /*
+ * This code eliminates unnecessary calls to XDefineCursor,
+ * since this is a slow operation on some hardware (e.g., S3
+ * chips).
+ */
+ XSync(DISP, False);
+ if (!XtPending()) {
+ Cursor curr;
+
+ if (globals.cursor.flags & CURSOR_DRAG_V)
+ curr = globals.cursor.drag_v;
+ else if (globals.cursor.flags & CURSOR_DRAG_H)
+ curr = globals.cursor.drag_h;
+ else if (globals.cursor.flags & CURSOR_DRAG_A)
+ curr = globals.cursor.drag_a;
+ else if (resource.mouse_mode == MOUSE_RULER_MODE)
+ curr = globals.cursor.rule;
+ else if (resource.mouse_mode == MOUSE_TEXT_MODE && !(globals.cursor.flags & CURSOR_LINK))
+ curr = globals.cursor.text;
+ else if (globals.cursor.flags & CURSOR_LINK)
+ curr = globals.cursor.link;
+ else if (globals.cursor.flags & CURSOR_MAG)
+ curr = globals.cursor.mag;
+ else if (globals.cursor.flags & CURSOR_CORRUPTED)
+ curr = globals.cursor.corrupted;
+ else if (globals.pausing.flag)
+ curr = globals.cursor.pause;
+ else
+ curr = globals.cursor.ready;
+ XDefineCursor(DISP, CURSORWIN, curr);
+ globals.ev.flags &= ~EV_CURSOR;
+ }
+ }
+ XFlush(DISP);
+ }
+ }
+}
+
+static void
+Act_unpause_or_next(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ if (block_this_mouse_event())
+ return;
+
+ if (globals.pausing.flag) {
+ globals.pausing.num++;
+ if (globals.pausing.num_save)
+ globals.pausing.num_save[current_page] = globals.pausing.num;
+ redraw_page();
+ }
+ else {
+ Act_down_or_next(w, event, params, num_params);
+ }
+}
+
+/*
+ * timer callback for watching the DVI file.
+ */
+void
+watch_file_cb(XtPointer client_data, XtIntervalId *id)
+{
+ static XtIntervalId timer = 0;
+
+ UNUSED(client_data);
+ UNUSED(id);
+
+ if (resource.watch_file > 0.0) {
+ unsigned long watch_time_ms;
+
+ (void)dvi_file_changed();
+
+ if (timer) {
+ XtRemoveTimeOut(timer);
+ timer = (XtIntervalId)(XtIntervalId)0;
+ }
+
+ watch_time_ms = (unsigned long)(resource.watch_file * 1000);
+ timer = XtAppAddTimeOut(app, watch_time_ms, watch_file_cb, (XtPointer)NULL);
+ }
+}
+
+void Act_pagehistory_back(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ arg = 1;
+ }
+ page_history_move(-arg);
+}
+
+void Act_pagehistory_forward(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ arg = 1;
+ }
+ page_history_move(arg);
+}
+
+void Act_pagehistory_clear(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (block_this_mouse_event())
+ return;
+
+ page_history_clear();
+}
+
+void Act_pagehistory_delete_backward(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ arg = 1;
+ }
+ page_history_delete(-arg);
+}
+
+void Act_pagehistory_delete_forward(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ arg = 1;
+ }
+ page_history_delete(arg);
+}
+
+#ifdef MOTIF
+void Act_prefs_dialog(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ int arg;
+
+ if (block_this_mouse_event())
+ return;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (!get_int_arg(params, num_params, &arg)) {
+ arg = -1;
+ }
+
+ popup_preferences_dialog(globals.widgets.top_level, arg);
+}
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/events.h b/Build/source/texk/xdvik/events.h
new file mode 100644
index 00000000000..93c6ca18d33
--- /dev/null
+++ b/Build/source/texk/xdvik/events.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1990-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef EVENTS_H_
+#define EVENTS_H_
+
+/*
+ * Flag values and masks for event_flags
+ */
+
+#define EV_IDLE (1<<0) /* 1 - non-event */
+#define EV_CURSOR (1<<1) /* 2 - cursor needs to revert back to ready */
+#define EV_EXPOSE (1<<2) /* 4 - expose occurred somewhere */
+#define EV_MAG_MOVE (1<<3) /* 8 - magnifier moved */
+#define EV_MAG_GONE (1<<4) /* 16 - magnifier gone while being drawn */
+#define EV_ACK (1<<5) /* 32 - used internally */
+#define EV_SRC (1<<6) /* 64 - source special operation is pending */
+#define EV_ANCHOR (1<<7) /* 128 - anchor search is pending - should maybe move this up? */
+#define EV_FIND (1<<8) /* 256 - string search */
+#define EV_FIND_CANCEL (1<<9) /* 512 - string search cancelled */
+#define EV_FILEHIST_GOTO_PAGE (1<<10) /* 1024 - get page from file history */
+#define EV_PAGEHIST_INSERT (1<<11) /* 2048 - get page from file history */
+#define EV_NEWPAGE (1<<12) /* 4096 - new page requested */
+#define EV_PS_TOGGLE (1<<13) /* 8192 - PostScript toggled on or off */
+#define EV_RELOAD (1<<14) /* 16384 - reload dvi file */
+#define EV_NEWDOC (1<<15) /* 32768 - new dvi file requested */
+#define EV_TERM (1<<16) /* 65536 - quit */
+#define EV_MAXPLUS1 (1<<17) /* 131072 - marker for highest element */
+
+#define EV_GE_IDLE (EV_MAXPLUS1 - EV_IDLE)
+#define EV_GT_IDLE (EV_MAXPLUS1 - EV_CURSOR)
+#define EV_GE_CURSOR (EV_MAXPLUS1 - EV_CURSOR)
+#define EV_GE_EXPOSE (EV_MAXPLUS1 - EV_EXPOSE)
+#define EV_GE_MAG_MOVE (EV_MAXPLUS1 - EV_MAG_MOVE)
+#define EV_GE_MAG_GONE (EV_MAXPLUS1 - EV_MAG_GONE)
+#define EV_GE_ACK (EV_MAXPLUS1 - EV_ACK)
+#define EV_GE_FIND (EV_MAXPLUS1 - EV_FIND)
+#define EV_GE_FIND_CANCEL (EV_MAXPLUS1 - EV_FIND_CANCEL)
+#define EV_GE_NEWPAGE (EV_MAXPLUS1 - EV_NEWPAGE)
+#define EV_GE_PS_TOGGLE (EV_MAXPLUS1 - EV_PS_TOGGLE)
+#define EV_GE_NEWDOC (EV_MAXPLUS1 - EV_NEWDOC)
+#define EV_GE_RELOAD (EV_MAXPLUS1 - EV_RELOAD)
+#define EV_GE_TERM (EV_MAXPLUS1 - EV_TERM)
+
+#define EV_NOWAIT EV_GE_IDLE
+
+
+struct xio {
+ struct xio *next; /* link to next in list */
+ int fd; /* file descriptor */
+ int xio_events; /* same as in struct pollfd
+ (can't call it events because poll.h
+ on AIX defines events to something else) */
+#if HAVE_POLL
+ struct pollfd *pfd;
+#endif
+ char *(*read_proc) (int); /* call to read from fd, or NULL */
+ void (*write_proc) (int); /* call to write to fd, or NULL */
+};
+
+struct xchild; /* forward declaration */
+
+typedef void (*childProcT)(int exitval, struct xchild *this);
+
+struct xchild {
+ struct xchild *next; /* link to next in list */
+ pid_t pid; /* pid of process, or 0 */
+ Boolean killable; /* if can be killed with SIGKILL */
+ char *name; /* name of process, for printing error message */
+ struct xio *io; /* pointer to i/o structure for reading error msg. */
+ void *data; /* arbitrary data passed to proc */
+
+ /* proc is a pointer to a function to call when the child exits; it will be
+ * called with 2 arguments:
+ * - The return status of the child
+ * - A pointer to the current struct (so that the procedure can free()
+ * (elements of) the struct when needed, or have access to the data field).
+ */
+ childProcT proc;
+};
+
+typedef enum xtimerT_ {
+ XTM_DEFAULT = 0,
+ XTM_STATUSLINE,
+ XTM_HREF
+} xtimerT;
+
+struct xtimer {
+ struct xtimer *next; /* link to next in chain */
+ struct timeval when; /* when to call the routine */
+ xtimerT type; /* timer type */
+ void (*proc) (struct xtimer *); /* procedure to call */
+#if XDVI_XT_TIMER_HACK
+ XtTimerCallbackProc xt_proc; /* additional data for Xt callbacks */
+ XtPointer closure;
+#endif
+};
+
+extern void set_timer(struct xtimer *tp, int ms);
+extern void cancel_timer(struct xtimer *tp);
+
+extern int get_num_actions(void);
+extern XtActionsRec *get_actions(void);
+
+extern int atopix(const char *, Boolean);
+
+extern int check_goto_page(int pageno);
+extern Boolean get_int_arg(String * param, Cardinal *num_params, int *res);
+extern Boolean toggle_arg(int arg, String * param, Cardinal *num_params);
+
+extern void clearexpose(struct WindowRec *windowrec, int x, int y, unsigned w,
+ unsigned h);
+extern void expose(struct WindowRec *windowrec, int x, int y, unsigned int w,
+ unsigned int h);
+extern void home(wide_bool);
+extern int set_bar_value(Widget bar, int value, int max);
+
+extern void reconfig(void);
+extern void redraw(struct WindowRec *windowrec);
+extern void handle_resize(Widget, XtPointer, XEvent *, Boolean *);
+extern void handle_expose(Widget, XtPointer, XEvent *, Boolean *);
+extern void handle_property_change(Widget, XtPointer, XEvent *, Boolean *);
+extern void handle_command(Widget widget, XtPointer client_data,
+ XtPointer call_data);
+extern void showmessage(const char *);
+extern void set_chld(struct xchild *);
+extern void clear_chld(struct xchild *);
+extern void set_io(struct xio *);
+extern void clear_io(struct xio *);
+extern unsigned int read_events(unsigned int);
+
+typedef void (*home_proc) (wide_bool);
+extern void goto_page(int page, home_proc proc, Boolean force);
+
+extern void setup_sigalarm(void);
+extern void setup_signal_handlers(void);
+extern int shrink_to_fit(void);
+extern void do_pages(void);
+extern void do_set_density(double newgamma, Boolean force, Boolean update_resource);
+extern void do_toggle_color(Boolean update_resource);
+
+#ifdef PS
+extern void Act_set_ps(Widget w, XEvent *event, String *params, Cardinal *num_params);
+#endif
+
+#ifdef PS_GS
+extern void Act_set_gs_alpha(Widget w, XEvent *event, String *params, Cardinal *num_params);
+#endif
+
+extern void Act_recent_files(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_htex_back(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_htex_forward(Widget w, XEvent *event, String *params, Cardinal *num_params);
+
+extern void Act_set_keep_flag(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_back_page(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_forward_page(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void do_set_shrinkfactor(int arg, Boolean set_resource);
+extern void Act_set_shrink_factor(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_shrink_to_dpi(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_set_expert_mode(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_use_tex_pages(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_ruler_mode(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_set_expert_mode(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_switch_mode(Widget w, XEvent *event, String *params, Cardinal *num_params);
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+extern void Act_set_papersize(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_set_paper_landscape(Widget w, XEvent *event, String *params, Cardinal *num_params);
+#endif /* NEW_MENU_CREATION */
+
+extern void Act_pagehistory_clear(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_pagehistory_back(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_pagehistory_forward(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_pagehistory_delete_backward(Widget w, XEvent *event, String *params, Cardinal *num_params);
+extern void Act_pagehistory_delete_forward(Widget w, XEvent *event, String *params, Cardinal *num_params);
+
+extern void null_mouse(XEvent *ignored);
+extern void block_next_mouse_event(void);
+extern Boolean block_this_mouse_event(void);
+extern void text_motion(XEvent *event);
+extern Boolean dragging_text_selection(void);
+
+typedef enum { TEXT_SEL_MOVE, TEXT_SEL_CLEAR, TEXT_SEL_REDRAW, TEXT_SEL_ERASE } textSelectionT;
+extern void text_change_region(textSelectionT mode, XEvent *event);
+
+extern void text_selection_start(XEvent *event);
+
+#if COLOR
+
+extern void update_expert_mode(void);
+
+extern Boolean check_resource_expert(void *val, const char *param);
+extern Boolean check_paper_landscape(void *val, const char *param);
+extern Boolean check_papersize(void *val, const char *param);
+extern Boolean check_toggle(void *val, const char *param);
+extern Boolean check_int(void *val, const char *param);
+
+#endif /* COLOR */
+
+
+struct xdvi_action {
+ XtActionProc proc;
+ Cardinal num_params;
+ String param;
+ struct xdvi_action *next;
+};
+
+extern struct xdvi_action *compile_action(const char *str);
+extern void watch_file_cb(XtPointer client_data, XtIntervalId * id);
+extern void redraw_page(void);
+
+extern void handle_x_scroll(Widget w, XtPointer closure, XEvent *ev, Boolean *cont);
+extern void handle_y_scroll(Widget w, XtPointer closure, XEvent *ev, Boolean *cont);
+extern void xdvi_exit_callback(Widget w, XtPointer client_data, XtPointer call_data);
+
+#endif /* EVENTS_H_ */
diff --git a/Build/source/texk/xdvik/filehist.c b/Build/source/texk/xdvik/filehist.c
new file mode 100644
index 00000000000..43664025e1e
--- /dev/null
+++ b/Build/source/texk/xdvik/filehist.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+*/
+
+/*
+ List of recently visited files, initialized from X resource
+ fileHistory and displayed in `File -> Open Recent' menu.
+*/
+
+#include <ctype.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "util.h"
+#include "my-snprintf.h"
+#include "string-utils.h"
+#include "dvi-init.h"
+#include "events.h"
+#include "message-window.h"
+#include "xm_menu.h"
+#include "xaw_menu.h"
+#include "filehist.h"
+
+/****************************************************************************
+ *
+ * File-scope globals
+ *
+ ****************************************************************************/
+
+/* list of files */
+static struct dl_list *m_file_history = NULL;
+
+/* current size of the list */
+static int m_file_history_length = 0;
+
+/* /\* current position in the list *\/ */
+/* static int m_file_history_currpos = 0; */
+
+/* item in above list */
+struct file_history {
+ char *filename;
+ int pageno;
+};
+
+#define DEBUG 1
+
+/****************************************************************************
+ *
+ * Private functions
+ *
+ ****************************************************************************/
+
+static void
+file_history_show(struct dl_list *list)
+{
+ if (globals.debug & DBG_FILES) {
+ int n;
+ fprintf(stderr, "======= File history:\n");
+ for (n = 0; list != NULL; list = list->next, n++) {
+ struct file_history *item = (struct file_history *)(list->item);
+ if (item == NULL) {
+ fprintf(stderr, "item %d is NULL!\n", n);
+ continue;
+ }
+ fprintf(stderr, "item %d: %d:%s\n", n, item->pageno, item->filename);
+ }
+ }
+}
+
+
+/****************************************************************************
+ *
+ * Exported functions
+ *
+ ****************************************************************************/
+
+void
+file_history_init(void)
+{
+ char **fileinfo;
+ size_t i;
+ struct dl_list *head = NULL;
+
+ m_file_history_length = 0;
+
+ if (resource.file_history == NULL)
+ return;
+
+ fileinfo = get_separated_list(resource.file_history, "\n", False);
+
+ for (i = 0; fileinfo[i] != NULL && i < (size_t)resource.file_history_size; i++) {
+ struct file_history *item = xmalloc(sizeof *item);
+ char *ptr;
+ int pageno = strtol(fileinfo[i], &ptr, 10);
+ TRACE_FILES((stderr, "FILEINFO: %s", fileinfo[i]));
+ if (ptr == fileinfo[i]) {
+ XDVI_WARNING((stderr, "Missing page number in resource line `%s'!\n",
+ fileinfo[i]));
+ pageno = 0;
+ }
+ else {
+ while (isspace((int)*ptr))
+ ptr++;
+ }
+
+ item->pageno = pageno;
+ item->filename = xstrdup(ptr);
+
+ TRACE_FILES((stderr, "FILE: %d:%s", item->pageno, item->filename));
+
+ m_file_history = dl_list_insert(m_file_history, item);
+ if (head == NULL) /* remember head position */
+ head = m_file_history;
+
+ TRACE_FILES((stderr, "NEW ELEM: %p", (void *)m_file_history));
+
+ m_file_history_length++;
+
+ free(fileinfo[i]);
+ }
+ free(fileinfo);
+
+ m_file_history = head;
+ file_history_show(m_file_history);
+}
+
+static Boolean
+equals_filename(const void *it, const void *fname)
+{
+ const struct file_history *item = (const struct file_history *)it;
+ const char *filename = (const char *)fname;
+
+ return strcmp(item->filename, filename) == 0;
+}
+
+
+/* put new elem for filename `filename' and page number `page' at the front
+ of the list. Return True if the addition caused the history to grow, else
+ False (in case the item was only moved to the front).
+*/
+Boolean
+file_history_push(const char *filename)
+{
+ int i;
+ struct file_history *item = NULL;
+ void *removed_data = NULL;
+ struct file_history *removed_item = NULL;
+ int len_bak = m_file_history_length;
+ int count = 0;
+
+ TRACE_FILES((stderr, "Pushing: |%s|", filename));
+
+ /* if list already contains an item with same filename, remove it */
+ m_file_history = dl_list_remove(m_file_history, filename, &count, &removed_data, equals_filename);
+ if (count == 0)
+ m_file_history_length++;
+
+ removed_item = (struct file_history *)removed_data;
+
+ file_history_show(m_file_history);
+
+ TRACE_FILES((stderr, "current length: %d, max: %d", m_file_history_length, resource.file_history_size));
+
+ /* truncate list if it has reached its max length */
+ if (m_file_history_length > resource.file_history_size) {
+ struct dl_list *listpos = m_file_history;
+ struct dl_list *last_pos = listpos;
+ for (i = 0; listpos != NULL && i < m_file_history_length; i++) {
+ last_pos = listpos;
+ listpos = listpos->next;
+ }
+
+ item = last_pos->item; /* reuse item */
+ TRACE_FILES((stderr, "Re-using item: |%s| -> |%s|", item->filename, filename));
+ item->filename = xrealloc(item->filename, strlen(filename) + 1);
+ strcpy(item->filename, filename);
+
+ (void)dl_list_remove_item(&last_pos);
+ m_file_history_length--;
+ }
+ else if (removed_item != NULL) {
+ TRACE_FILES((stderr, "Re-using item: |%s|\n", removed_item->filename));
+ item = removed_item; /* reuse item */
+ }
+ else {
+ item = xmalloc(sizeof *item);
+ TRACE_FILES((stderr, "NEW item: |%s|\n", filename));
+ item->filename = xstrdup(filename);
+ item->pageno = 0;
+ }
+
+ /* add new element at front of list */
+ m_file_history = dl_list_push_front(m_file_history, item);
+
+ file_history_show(m_file_history);
+
+ TRACE_FILES((stderr, "returning: %d < %d", len_bak, m_file_history_length));
+ return len_bak < m_file_history_length;
+}
+
+size_t file_history_size(void)
+{
+ return m_file_history_length;
+}
+
+void file_history_set_page(int pageno)
+{
+ struct dl_list *head;
+
+ TRACE_FILES((stderr, "SETTING HEAD to %d", pageno));
+ file_history_show(m_file_history);
+ head = dl_list_head(m_file_history);
+ if (head != NULL) {
+ struct file_history *item = (struct file_history *)head->item;
+ TRACE_FILES((stderr, "Setting page of |%s| to %d", item->filename, pageno));
+ item->pageno = pageno;
+ }
+}
+
+void file_history_set_page_at(int idx, int pageno)
+{
+ int i;
+ struct dl_list *listpos = dl_list_head(m_file_history);
+ struct file_history *item;
+
+ for (i = 0; listpos != NULL && i < idx; i++) {
+ listpos = listpos->next;
+ }
+ if (listpos == NULL) {
+ TRACE_FILES((stderr, "Asked for file at position %d, but only %d elements in list",
+ idx, i - 1));
+ return;
+ }
+ item = (struct file_history *)listpos->item;
+ TRACE_FILES((stderr, "set_page_at index %d: Setting page of |%s| to %d", idx, item->filename, pageno));
+ item->pageno = pageno;
+}
+
+int file_history_get_page(void)
+{
+ struct dl_list *head = dl_list_head(m_file_history);
+ if (head != NULL) {
+ struct file_history *item = (struct file_history *)head->item;
+ TRACE_FILES((stderr, "Getting page of |%s|: %d", item->filename, item->pageno));
+ return item->pageno;
+ }
+ return 0;
+}
+
+/*
+ * Invoke `callback' for each elem of file history, passing
+ * the current index, filename, page number, and data passed to
+ * this function.
+ */
+void
+file_history_enumerate(filehistCallbackT callback, void *data)
+{
+ int i;
+ struct dl_list *listpos = dl_list_head(m_file_history);
+
+ for (i = 0; listpos != NULL; i++) {
+ struct file_history *item = (struct file_history *)listpos->item;
+ callback(i, item->filename, item->pageno, data);
+ listpos = listpos->next;
+ }
+}
+
+char *
+file_history_get_elem(int idx, int *ret_page)
+{
+ int i;
+ struct dl_list *listpos = dl_list_head(m_file_history);
+ struct file_history *item;
+
+ for (i = 0; listpos != NULL && i < idx; i++) {
+ listpos = listpos->next;
+ }
+ if (listpos == NULL) {
+ XDVI_WARNING((stderr, "Asked for file at position %d, but only %d elements in list",
+ idx, i - 1));
+ return NULL;
+ }
+ item = (struct file_history *)listpos->item;
+ *ret_page = item->pageno;
+ file_history_show(m_file_history);
+ return item->filename;
+}
+
+char *
+file_history_get_list(void)
+{
+ char buf[LENGTH_OF_INT];
+ char *ret = xstrdup("");
+ struct dl_list *listpos;
+
+ for (listpos = dl_list_head(m_file_history);
+ listpos != NULL;
+ listpos = listpos->next) {
+
+ struct file_history *item = (struct file_history *)listpos->item;
+ SNPRINTF(buf, LENGTH_OF_INT, "%d ", item->pageno);
+ ret = xstrcat(ret, buf);
+ ret = xstrcat(ret, item->filename);
+ ret = xstrcat(ret, "\n");
+ }
+
+ ret[strlen(ret) - 1] = '\0'; /* chop off excess \n at end */
+ return ret;
+}
+
+void
+file_history_open(const char *fname)
+{
+ Boolean tried_dvi_ext = True;
+ char *new_dvi_name = NULL;
+
+ int dummy_cnt = 0;
+ void *dummy_data = NULL;
+
+ file_history_set_page(current_page);
+ if ((new_dvi_name = open_dvi_file_wrapper(fname,
+ True, /* pretend file is from commandline, otherwise xdvi will
+ try to fork for non-existing files, leading to confusing
+ popup error messages */
+ False, &tried_dvi_ext,
+ True /* don't exit on error */)) == NULL) {
+ /* remove this item from the file history */
+ m_file_history = dl_list_remove(m_file_history, fname, &dummy_cnt, &dummy_data, equals_filename);
+ m_file_history_length--;
+ file_history_show(m_file_history);
+
+ filehist_menu_refresh();
+ return;
+ }
+ else {
+ dviErrFlagT errflag;
+ if (load_dvi_file(True, &errflag)) {
+ /* page_history_insert(pageno); */
+ set_dvi_name(new_dvi_name);
+
+ globals.ev.flags |= EV_NEWDOC;
+ globals.ev.flags |= EV_FILEHIST_GOTO_PAGE;
+ globals.ev.flags |= EV_PAGEHIST_INSERT;
+ }
+ else { /* re-open old file */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Could not open `%s': %s.\n"
+ /* "Removing this file from the history." */,
+ globals.dvi_name, get_dvi_error(errflag));
+ /* remove this item from the file history */
+ m_file_history = dl_list_remove(m_file_history, globals.dvi_name,
+ &dummy_cnt, &dummy_data,
+ equals_filename);
+ m_file_history_length--;
+ filehist_menu_refresh();
+
+ if (!internal_open_dvi(globals.dvi_name, &errflag, True)) {
+/* || !internal_init_dvi(&errflag, True)) { */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Couldn't reopen `%s': %s.\n"
+ /* "Removing this file from the history." */,
+ globals.dvi_name, get_dvi_error(errflag));
+ /* remove this item from the file history */
+ m_file_history = dl_list_remove(m_file_history, globals.dvi_name, &dummy_cnt, &dummy_data, equals_filename);
+ m_file_history_length--;
+ filehist_menu_refresh();
+ }
+ else {
+ globals.ev.flags |= EV_NEWPAGE;
+ }
+ }
+ }
+}
diff --git a/Build/source/texk/xdvik/filehist.h b/Build/source/texk/xdvik/filehist.h
new file mode 100644
index 00000000000..5a1a75925fd
--- /dev/null
+++ b/Build/source/texk/xdvik/filehist.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ */
+
+#ifndef FILEHIST_H_
+#define FILEHIST_H_
+
+typedef void (*filehistCallbackT) (int idx, const char *filename, int pageno, void *data);
+
+extern void file_history_enumerate(filehistCallbackT callback, void *data);
+extern void file_history_init(void);
+extern Boolean file_history_push(const char *filename);
+extern void file_history_set_page(int pageno);
+extern void file_history_set_page_at(int idx, int pageno);
+extern int file_history_get_page(void);
+extern char *file_history_get_elem(int idx, int *ret_page);
+extern char *file_history_get_list(void);
+extern void file_history_open(const char *filename);
+extern size_t file_history_size(void);
+
+#endif /* FILEHIST_H_ */
+
diff --git a/Build/source/texk/xdvik/font-open.c b/Build/source/texk/xdvik/font-open.c
new file mode 100644
index 00000000000..da9762ad282
--- /dev/null
+++ b/Build/source/texk/xdvik/font-open.c
@@ -0,0 +1,496 @@
+/*
+ font_open.c: find font filenames. This bears no relation (but the
+ interface) to the original font_open.c.
+
+Copyright (c) 1999-2004 The texk project
+
+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.
+
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "dvi-draw.h"
+#include "util.h"
+#include "events.h"
+#include "my-snprintf.h"
+#include "print-log.h"
+
+#include "statusline.h"
+#include "font-open.h"
+
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/tex-glyph.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(status) (((status) & 255) == 0)
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(status) ((unsigned)(status) >> 8)
+#endif
+#ifndef WIFSIGNALED
+# ifndef WIFSTOPPED
+# define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+# endif
+# define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
+#endif
+#ifndef WTERMSIG
+# define WTERMSIG(status) ((status) & 0x7f)
+#endif
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+# define O_NONBLOCK O_NDELAY
+#endif
+
+#ifdef EWOULDBLOCK
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+# else
+# define AGAIN_CONDITION (errno == EWOULDBLOCK)
+# endif
+#else /* EWOULDBLOCK */
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EAGAIN)
+# endif
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif /* HAVE_POLL */
+
+#if 0
+// static int mktexpk_io[2];
+// static struct xchild mktexpk_child = { NULL, 0, True, "font creation", NULL, NULL, mktexpk_ended };
+//
+// static char *read_from_mktexpk(int ignored);
+// static void write_to_mktexpk(int ignored);
+//
+// static struct xio mktexpk_xio = { NULL, 0, XIO_IN,
+// #if HAVE_POLL
+// NULL,
+// #endif
+// read_from_mktexpk,
+// NULL};
+//
+
+static void
+mktexpk_ended(int status, struct xchild *this)
+{
+ char str[1024] = "";
+ char *err_msg = NULL;
+
+ fprintf(stderr, "------- MKTEXPK_ENDED!\n");
+ if (this->io != NULL && WIFEXITED(status)) {
+ err_msg = (this->io->read_proc)(this->io->fd);
+ SNPRINTF(str, 1024, "\nProcess `%s' returned exit code %d.\n",
+ this->name, WEXITSTATUS(status));
+ str[1024 - 1] = '\0';
+ printlog_append_str(str);
+ if (err_msg != NULL) {
+ fprintf(stderr, "FROM MKTEXPK: |%s|\n", err_msg);
+ printlog_append_str(err_msg);
+ }
+ }
+ printlog_enable_closebutton();
+/* free(this->name); */
+/* free(this->io); */
+/* free(this); */
+
+// read_from_mktexpk(0);
+// clear_io(this->io);
+// (void)close(mktexpk_xio.fd);
+//
+// if (WIFEXITED(status)) {
+// if (WEXITSTATUS(status) == 0) {
+// printlog_append("Done.\n", strlen("Done.\n"));
+// }
+// else
+// sprintf(str, "\nPrint process returned exit code %d.\n",
+// WEXITSTATUS(status));
+// }
+// else if (WIFSIGNALED(status))
+// sprintf(str, "\nPrint process terminated by signal %d.\n",
+// WTERMSIG(status));
+// else
+// sprintf(str, "\nPrint process returned unknown status 0x%x.\n",
+// status);
+//
+
+}
+
+static char *
+read_from_mktexpk(int fd)
+{
+ int bytes;
+ char line[80];
+ char *buf;
+
+ fprintf(stderr, "------- READ_FROM_MKTEXPK!\n");
+ for (;;) {
+#ifndef MOTIF
+ bytes = read(fd, line, sizeof line);
+#else
+ bytes = read(fd, line, sizeof line - 1);
+#endif
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi: read_from_mktexpk");
+ break;
+ }
+
+ if (bytes == 0)
+ break;
+ else {
+#ifdef MOTIF
+ line[bytes] = '\0';
+#endif
+ // fprintf(stderr, "------- READ_FROM_MKTEXPK:|%s|\n", line);
+ printlog_append(line, bytes);
+ }
+ }
+ buf = xmalloc(bytes + 1);
+ memcpy(buf, line, bytes);
+ buf[bytes] = '\0';
+ return buf;
+}
+
+// static void
+// write_to_mktexpk(int ignored)
+// {
+// UNUSED(ignored);
+//
+// return;
+// }
+#endif /* 0 */
+
+
+
+/* We try for a VF first because that's what dvips does. Also, it's
+ easier to avoid running mktexpk if we have a VF this way. */
+
+FILE *
+font_open(char *font, char **font_ret,
+ double dpi, int *dpi_ret,
+ char **filename_ret
+#ifdef T1LIB
+ , int *t1id
+#endif
+ )
+{
+ char *name;
+ kpse_glyph_file_type file_ret;
+
+ /* defaults in case of success; filename_ret will be
+ non-NULL iff the fallback font is used.
+ */
+ *font_ret = NULL;
+ /* filename_ret is NULL iff a T1 version of a font has been used */
+ *filename_ret = NULL;
+ *dpi_ret = dpi;
+
+ if (resource.omega) { /* for omega, first try 16-bit ovf's, then 8-bit vf's. */
+ name = kpse_find_ovf(font);
+ if (name == NULL)
+ name = kpse_find_vf(font);
+ }
+ else {
+ name = kpse_find_vf(font);
+ }
+
+#ifdef T1LIB
+ if (resource.t1lib) {
+ *t1id = -1;
+ }
+#endif /* T1LIB */
+
+ if (name) { /* found a vf font */
+ /* pretend it has the expected dpi value, else caller will complain */
+ *dpi_ret = dpi;
+ *filename_ret = name;
+ return XFOPEN(name, FOPEN_R_MODE);
+ }
+
+#ifdef T1LIB
+ if (resource.t1lib) {
+ /* First attempt: T1 font of correct size */
+ *t1id = find_T1_font(font);
+ if (*t1id >= 0) {
+ TRACE_T1((stderr, "found T1 font %s", font));
+ return NULL;
+ }
+ TRACE_T1((stderr,
+ "T1 version of font %s not found, trying pixel version next, then fallback",
+ font));
+ }
+#endif /* T1LIB */
+
+#ifdef EXPERIMENTAL_DELAYED_MTKEXPK
+ /*
+ From this point on, kpathsea might create some fonts (and fail horribly ...)
+ We want to catch its error messages and present them to the user in a window,
+ so fork and collect all output of the child into a pipe, similar to what's done for
+ dvips.
+
+ Actually, the approach outlined here is bogus, since it still
+ ignores the main issue of knowing, in the parent, when all the
+ font creation commands have finished (so that we can start
+ drawing the pages). What is needed here is a child procedure
+ that works through a stack of font names, creating the fonts if
+ needed, and the parent checking the return values from these
+ font creation processes. Only after the child is finished,
+ xdvi can go on drawing the page, by calling the drawing routine
+ *from within* mktexpk_ended().
+ */
+ {
+ struct xchild *mktexpk_child = xmalloc(sizeof *mktexpk_child);
+ struct xio *mktexpk_xio = xmalloc(sizeof *mktexpk_xio);
+ int mktexpk_io[2];
+ int pid;
+
+ fprintf(stderr, "BEFORE CREATING PIPE\n");
+
+ if (xpipe(mktexpk_io) != 0) {
+ perror("[xdvi] pipe");
+ return NULL;
+ }
+
+ /* 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(stderr);
+ fflush(stdout);
+
+ switch (pid = fork()) {
+ case -1: /* forking error */
+ perror("fork");
+ close(mktexpk_io[0]);
+ close(mktexpk_io[1]);
+ return NULL;
+ case 0: /* child */
+ fprintf(stderr, "CHILD\n");
+ close(mktexpk_io[0]); /* no reading from io */
+
+ /* make stdout and stderr of child go to mktexpk_io[1] */
+ if (mktexpk_io[1] == STDOUT_FILENO)
+ XDVI_ABORT((stderr, "mktexpk_io[1] shouldn't be STDOUT_FILENO"));
+ if (dup2(mktexpk_io[1], STDOUT_FILENO) != STDOUT_FILENO)
+ XDVI_ABORT((stderr, "dup2: mktexpk_io[1], STDOUT_FILENO: %s", strerror(errno)));
+
+ if (mktexpk_io[1] == STDERR_FILENO)
+ XDVI_ABORT((stderr, "mktexpk_io[1] shouldn't be STDERR_FILENO"));
+ if (dup2(mktexpk_io[1], STDERR_FILENO) != STDERR_FILENO)
+ XDVI_ABORT((stderr, "dup2: mktexpk_io[1], STDERR_FILENO: %s", strerror(errno)));
+ close(mktexpk_io[1]);
+
+ fprintf(stderr, "Running ...\n");
+ fprintf(stdout, "Running to stdout ...\n");
+
+ /* TODO: We could use a convenience routine from kpathsea (which we'd need to create first though)
+ like
+ kpse_find_glyph_nocreate()
+ that just returns NULL instead of invoking mktexpk. However this still doesn't give us
+ access to error messages from mktexpk etc.
+ Maybe it would be better to collect all output from mktexpk into a `log' window, and at
+ the same time filter the output for (shorter) messages in the statusline, a la:
+ `generating font %s (n of m) ...'
+ How is the `n of m' part done in e.g. kdvi? Investigate.
+ */
+
+ /* Second attempt: PK/GF/... font within allowable size range */
+ name = kpse_find_glyph(font, (unsigned)(dpi + .5),
+ kpse_any_glyph_format, &file_ret);
+
+ if (name) { /* success */
+ fprintf(stderr, "\n1 DPI: %d\nFONTNAME: %s\n", file_ret.dpi, name);
+ *dpi_ret = file_ret.dpi;
+ *filename_ret = name;
+ _exit(0);
+ /* ? return XFOPEN(name, FOPEN_R_MODE); */
+ }
+ else if (resource.alt_font != NULL) {
+ /* The strange thing about kpse_find_glyph() is that it
+ won't create a PK version of alt_font if it doesn't
+ already exist. So we invoke it explicitly a second time
+ for that one.
+ */
+ TRACE_T1((stderr, "Trying fallback"));
+#ifdef T1LIB
+ if (resource.t1lib) {
+ /* Third attempt: T1 version of fallback font */
+ *t1id = find_T1_font(resource.alt_font);
+ if (*t1id >= 0) {
+ TRACE_T1((stderr, "found fallback font for %s: %s", font, resource.alt_font));
+ *font_ret = xstrdup(resource.alt_font);
+ _exit(0);
+ }
+ TRACE_T1((stderr,
+ "Type1 version of fallback font %s not found, trying pixel version",
+ resource.alt_font));
+ }
+#endif /* T1LIB */
+ /* Forth attempt: PK version of fallback font */
+ name = kpse_find_glyph(resource.alt_font, (unsigned)(dpi + .5),
+ kpse_any_glyph_format, &file_ret);
+ if (name) { /* success */
+ fprintf(stderr, "\n2 DPI: %d\nFONTNAME: %s\nRET_FONT: %s\n", file_ret.dpi, name, resource.alt_font);
+ *dpi_ret = file_ret.dpi;
+ *filename_ret = name;
+ *font_ret = xstrdup(resource.alt_font);
+ _exit(0);
+ /* ? return XFOPEN(name, FOPEN_R_MODE); */
+ }
+ }
+ _exit(1);
+ default: /* parent */
+ close(mktexpk_io[1]); /* no writing to io */
+
+ mktexpk_xio->next = NULL;
+ mktexpk_xio->fd = mktexpk_io[0];
+ mktexpk_xio->xio_events = XIO_IN;
+#if HAVE_POLL
+ mktexpk_xio->pfd = NULL;
+#endif
+ mktexpk_xio->read_proc = read_from_mktexpk;
+ mktexpk_xio->write_proc = NULL;
+
+ mktexpk_child->next = NULL;
+ mktexpk_child->pid = pid;
+ mktexpk_child->name = xstrdup(font);
+ mktexpk_child->data = NULL;
+ mktexpk_child->proc = mktexpk_ended;
+ mktexpk_child->io = mktexpk_xio;
+
+ set_chld(mktexpk_child);
+
+ /* TODO: get DPI and FONTNAME from the log window, save to *dpi_ret, *filename_ret and *font_ret
+ and return XFOPEN(name, FOPEN_R_MODE);
+ */
+
+ return NULL;
+ }
+ }
+
+#else /* EXPERIMENTAL_DELAYED_MTKEXPK */
+
+ /*
+ TODO:
+
+ Probably a better approach would be as follows:
+
+ 1. Read the postamble to get all font definitions. Then, set:
+
+ kpse_set_program_enabled(kpse_any_glyph_format, False, kpse_src_compile);
+
+ and run load_font() on all of the fonts, with an array in which to save
+ the names that don't exist (that returned NULL).
+
+ 2. Run load_font() again on the fonts that didn't exist in step
+ (1) and display the output in a window. This somehow needs to
+ be fork()ed so that the window itself remains responsive.
+ (Maybe it's easier to call mktexpk directly on the command-line?)
+
+ _________________________________________________________
+ | |
+ | Xdvi is creating fonts, please be patient ... |
+ | |
+ | Font xyz (n of m) |
+ | |
+ | Errors: 0 [ Show Details ... ] |
+ | |
+ | [ ... some progress meter or busy indicator ... ] |
+ | |
+ | |
+ | [ Exit xdvi ] [ Help ] |
+ | |
+ ---------------------------------------------------------
+
+ This window can be shown before the main window is opened.
+
+ */
+
+ /* Second try: PK/GF/... font within allowable size range */
+ /*
+ NOTE SU: The problem with this is that it will already use the PK version
+ of the fallback font (e.g. cmr10.600pk) if the PK version exists, so the
+ Type1 version of the fallback won't get used at all. But maybe this isn't
+ that severe, given that the font is grossly wrong anyway.
+ */
+ name = kpse_find_glyph(font, (unsigned)(dpi + .5),
+ kpse_any_glyph_format, &file_ret);
+
+ if (name) { /* success */
+ *dpi_ret = file_ret.dpi;
+ *filename_ret = name;
+ *font_ret = file_ret.name;
+ TRACE_T1((stderr, "Found pixel version: %s at %d dpi", file_ret.name, *dpi_ret));
+ return XFOPEN(name, FOPEN_R_MODE);
+ }
+ else if (resource.alt_font != NULL) {
+ /* The strange thing about kpse_find_glyph() is that it
+ won't create a PK version of alt_font if it doesn't
+ already exist. So we invoke it explicitly a second time
+ for that one.
+ */
+ TRACE_T1((stderr, "Trying fallback"));
+#ifdef T1LIB
+ if (resource.t1lib) {
+ /* Third attempt: T1 version of fallback font */
+ *t1id = find_T1_font(resource.alt_font);
+ if (*t1id >= 0) {
+ TRACE_T1((stderr, "found fallback font for %s: %s", font, resource.alt_font));
+ *font_ret = xstrdup(resource.alt_font);
+ return NULL;
+ }
+ TRACE_T1((stderr,
+ "Type1 version of fallback font %s not found, trying pixel version",
+ resource.alt_font));
+ }
+#endif /* T1LIB */
+ /* Forth attempt: PK version of fallback font */
+ name = kpse_find_glyph(resource.alt_font, (unsigned)(dpi + .5),
+ kpse_any_glyph_format, &file_ret);
+ if (name) { /* success */
+ TRACE_T1((stderr, "Success for PK version of fallback"));
+ *dpi_ret = file_ret.dpi;
+ *filename_ret = name;
+ *font_ret = xstrdup(resource.alt_font);
+ return XFOPEN(name, FOPEN_R_MODE);
+ }
+ else {
+ TRACE_T1((stderr, "Failure for PK version of fallback"));
+ }
+ }
+#endif /* EXPERIMENTAL_DELAYED_MTKEXPK */
+ /* all other cases are failure */
+ TRACE_T1((stderr, "Failure"));
+ return NULL;
+}
diff --git a/Build/source/texk/xdvik/font-open.h b/Build/source/texk/xdvik/font-open.h
new file mode 100644
index 00000000000..cd4a2d94975
--- /dev/null
+++ b/Build/source/texk/xdvik/font-open.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef FONT_OPEN_H_
+#define FONT_OPEN_H_
+
+extern FILE *font_open(char * font, char ** font_ret, double dpi, int * dpi_ret, char ** filename_ret
+#ifdef T1LIB
+ , int * t1id
+#endif
+ );
+
+#endif /* FONT_OPEN_H_ */
diff --git a/Build/source/texk/xdvik/gf.c b/Build/source/texk/xdvik/gf.c
new file mode 100644
index 00000000000..8c0d9a6da11
--- /dev/null
+++ b/Build/source/texk/xdvik/gf.c
@@ -0,0 +1,326 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2004 Paul Vojta
+
+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.
+
+\*========================================================================*/
+
+/*
+ * GF font reading routines.
+ * Public routines are read_GF_index and read_GF_char.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "dvi-init.h"
+#include "util.h"
+
+#define PAINT_0 0
+#define PAINT1 64
+#define PAINT2 65
+#define PAINT3 66
+#define BOC 67
+#define BOC1 68
+#define EOC 69
+#define SKIP0 70
+#define SKIP1 71
+#define SKIP2 72
+#define SKIP3 73
+#define NEW_ROW_0 74
+#define NEW_ROW_MAX 238
+#define XXX1 239
+#define XXX2 240
+#define XXX3 241
+#define XXX4 242
+#define YYY 243
+#define NO_OP 244
+#define CHAR_LOC 245
+#define CHAR_LOC0 246
+#define PRE 247
+#define POST 248
+#define POST_POST 249
+
+#define GF_ID_BYTE 131
+#define TRAILER 223 /* Trailing bytes at end of file */
+
+static FILE *GF_file;
+
+static void
+expect(ubyte ch)
+{
+ ubyte ch1 = get_byte(GF_file);
+
+ if (ch1 != ch)
+ XDVI_FATAL((stderr, "Bad GF file: %d expected, %d received.", ch, ch1));
+}
+
+static void
+too_many_bits(ubyte ch)
+{
+ XDVI_FATAL((stderr, "Too many bits found when loading character %d", ch));
+}
+
+/*
+ * Public routines
+ */
+
+
+static void
+read_GF_char(struct font *fontp,
+ wide_ubyte ch)
+{
+ struct glyph *g;
+ ubyte cmnd;
+ int min_m, max_m, min_n, max_n;
+ bmUnitT *cp, *basep, *maxp;
+ int bytes_wide;
+ Boolean paint_switch;
+#define White False
+#define Black True
+ Boolean new_row;
+ int count;
+ int word_weight;
+
+ g = &fontp->glyph[ch];
+ GF_file = fontp->file;
+
+ if (globals.debug & DBG_PK)
+ printf("Loading gf char %d", ch);
+
+ for (;;) {
+ switch (cmnd = get_byte(GF_file)) {
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ fseek(GF_file, (long)get_bytes(GF_file, (int)(cmnd - XXX1 + 1)), SEEK_CUR);
+ continue;
+ case YYY:
+ (void)get_bytes(GF_file, 4);
+ continue;
+ case BOC:
+ (void)get_bytes(GF_file, 4); /* skip character code */
+ (void)get_bytes(GF_file, 4); /* skip pointer to prev char */
+ min_m = get_lbytes(GF_file, 4);
+ max_m = get_lbytes(GF_file, 4);
+ g->x = -min_m;
+ min_n = get_lbytes(GF_file, 4);
+ g->y = max_n = get_lbytes(GF_file, 4);
+ g->bitmap.w = max_m - min_m + 1;
+ g->bitmap.h = max_n - min_n + 1;
+ break;
+ case BOC1:
+ (void)get_byte(GF_file); /* skip character code */
+ g->bitmap.w = get_byte(GF_file); /* max_m - min_m */
+ g->x = g->bitmap.w - get_byte(GF_file); /* ditto - max_m */
+ ++g->bitmap.w;
+ g->bitmap.h = get_byte(GF_file) + 1;
+ g->y = get_byte(GF_file);
+ break;
+ default:
+ XDVI_FATAL((stderr, "Bad BOC code: %d", cmnd));
+ }
+ break;
+ }
+ paint_switch = White;
+
+ if (globals.debug & DBG_PK)
+ printf(", size=%dx%d, dvi_adv=%ld\n", g->bitmap.w, g->bitmap.h,
+ g->dvi_adv);
+
+ alloc_bitmap(&g->bitmap);
+ cp = basep = (bmUnitT *) g->bitmap.bits;
+ /*
+ * Read character data into *basep
+ */
+ bytes_wide = ROUNDUP((int)g->bitmap.w, BMBITS) * BMBYTES;
+ maxp = ADD(basep, g->bitmap.h * bytes_wide);
+ memset(g->bitmap.bits, 0, g->bitmap.h * bytes_wide);
+ new_row = False;
+ word_weight = BMBITS;
+ for (;;) {
+ count = -1;
+ cmnd = get_byte(GF_file);
+ if (cmnd < 64)
+ count = cmnd;
+ else if (cmnd >= NEW_ROW_0 && cmnd <= NEW_ROW_MAX) {
+ count = cmnd - NEW_ROW_0;
+ paint_switch = White; /* it'll be complemented later */
+ new_row = True;
+ }
+ else
+ switch (cmnd) {
+ case PAINT1:
+ case PAINT2:
+ case PAINT3:
+ count = get_bytes(GF_file, (int)(cmnd - PAINT1 + 1));
+ break;
+ case EOC:
+ if (cp >= ADD(basep, bytes_wide))
+ too_many_bits(ch);
+ return;
+ case SKIP1:
+ case SKIP2:
+ case SKIP3:
+ basep += get_bytes(GF_file, (int)(cmnd - SKIP0)) * bytes_wide / sizeof(bmUnitT);
+/* *((char **)&basep) += get_bytes(GF_file, WIDENINT cmnd - SKIP0) * bytes_wide; */
+ case SKIP0:
+ new_row = True;
+ paint_switch = White;
+ break;
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ fseek(GF_file, (long)get_bytes(GF_file, (int)(cmnd - XXX1 + 1)), SEEK_CUR);
+ break;
+ case YYY:
+ (void)get_bytes(GF_file, 4);
+ break;
+ case NO_OP:
+ break;
+ default:
+ XDVI_FATAL((stderr, "Bad command in GF file: %d", cmnd));
+ } /* end switch */
+ if (new_row) {
+ basep += bytes_wide / sizeof(bmUnitT);
+/* *((char **)&basep) += bytes_wide; */
+ if (basep >= maxp || cp >= basep)
+ too_many_bits(ch);
+ cp = basep;
+ word_weight = BMBITS;
+ new_row = False;
+ }
+ if (count >= 0) {
+ while (count)
+ if (count <= word_weight) {
+#ifndef WORDS_BIGENDIAN
+ if (paint_switch)
+ *cp |= bit_masks[count] << (BMBITS - word_weight);
+#endif
+ word_weight -= count;
+#ifdef WORDS_BIGENDIAN
+ if (paint_switch)
+ *cp |= bit_masks[count] << word_weight;
+#endif
+ break;
+ }
+ else {
+ if (paint_switch)
+#ifndef WORDS_BIGENDIAN
+ *cp |= bit_masks[word_weight] << (BMBITS - word_weight);
+#else
+ *cp |= bit_masks[word_weight];
+#endif
+ cp++;
+ count -= word_weight;
+ word_weight = BMBITS;
+ }
+ paint_switch = 1 - paint_switch;
+ }
+ } /* end for */
+}
+
+
+void
+read_GF_index(struct font *fontp, wide_bool hushcs)
+{
+ int hppp, vppp;
+ ubyte ch, cmnd;
+ struct glyph *g;
+ long checksum;
+
+ fontp->read_char = read_GF_char;
+ GF_file = fontp->file;
+ if (globals.debug & DBG_PK)
+ printf("Reading GF pixel file %s\n", fontp->filename);
+ /*
+ * Find postamble.
+ */
+ fseek(GF_file, (long)-4, SEEK_END);
+ while (get_bytes(GF_file, 4) != ((unsigned long)TRAILER << 24 | TRAILER << 16
+ | TRAILER << 8 | TRAILER))
+ fseek(GF_file, (long)-5, SEEK_CUR);
+ fseek(GF_file, (long)-5, SEEK_CUR);
+ for (;;) {
+ ch = get_byte(GF_file);
+ if (ch != TRAILER)
+ break;
+ fseek(GF_file, (long)-2, SEEK_CUR);
+ }
+ if (ch != GF_ID_BYTE)
+ XDVI_FATAL((stderr, "Bad end of font file %s", fontp->fontname));
+ fseek(GF_file, (long)-6, SEEK_CUR);
+ expect(POST_POST);
+ fseek(GF_file, get_lbytes(GF_file, 4), SEEK_SET); /* move to postamble */
+ /*
+ * Read postamble.
+ */
+ expect(POST);
+ (void)get_bytes(GF_file, 4); /* pointer to last eoc + 1 */
+ (void)get_bytes(GF_file, 4); /* skip design size */
+ checksum = get_bytes(GF_file, 4);
+ if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
+ && !hushcs)
+ XDVI_WARNING((stderr, "Checksum mismatch (dvi = %lu, gf = %lu) in font file %s",
+ fontp->checksum, checksum, fontp->filename));
+ hppp = get_lbytes(GF_file, 4);
+ vppp = get_lbytes(GF_file, 4);
+ if (hppp != vppp && (globals.debug & DBG_PK))
+ printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp);
+ (void)get_bytes(GF_file, 4); /* skip min_m */
+ (void)get_bytes(GF_file, 4); /* skip max_m */
+ (void)get_bytes(GF_file, 4); /* skip min_n */
+ (void)get_bytes(GF_file, 4); /* skip max_n */
+ /*
+ * Prepare glyph array.
+ */
+ fontp->glyph = xmalloc(256 * sizeof(struct glyph));
+ memset((char *)fontp->glyph, 0, 256 * sizeof(struct glyph));
+ /*
+ * Read glyph directory.
+ */
+ while ((cmnd = get_byte(GF_file)) != POST_POST) {
+ int addr;
+
+ ch = get_byte(GF_file); /* character code */
+ g = &fontp->glyph[ch];
+ switch (cmnd) {
+ case CHAR_LOC:
+ /* g->pxl_adv = get_lbytes(GF_file, 4); */
+ (void)get_bytes(GF_file, 4);
+ (void)get_bytes(GF_file, 4); /* skip dy */
+ break;
+ case CHAR_LOC0:
+ /* g->pxl_adv = get_byte(GF_file) << 16; */
+ (void)get_byte(GF_file);
+ break;
+ default:
+ XDVI_FATAL((stderr, "Non-char_loc command found in GF preamble: %d", cmnd));
+ }
+ g->dvi_adv = fontp->dimconv * get_lbytes(GF_file, 4);
+ addr = get_bytes(GF_file, 4);
+ if (addr != -1)
+ g->addr = addr;
+ if (globals.debug & DBG_PK)
+ printf("Read GF glyph for character %d; dy = %ld, addr = %x\n",
+ ch, g->dvi_adv, addr);
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/Makefile.in b/Build/source/texk/xdvik/gui/Makefile.in
new file mode 100644
index 00000000000..20343fd95b3
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Makefile.in
@@ -0,0 +1,80 @@
+# Makefile for xdvik
+#
+# - 1999/05/08: janl: Removed submakes for libwww and kpathsea. That's what
+# the top makefile is for!
+#
+
+
+### NOTE: ac_include paths must be relative to texk/xdvik, since that
+### is from where the configure is run!
+kpse_include ../make/paths.mk
+kpse_include ../make/library.mk
+kpse_include ../make/common.mk
+kpse_include ../make/programs.mk
+
+kpathsea_parent = ../..
+
+CPP = @CPP@
+RANLIB = @RANLIB@
+
+# Make `#include <X11/...>' and `-lX...' work.
+# This matches web2c (needed only for Metafont).
+x_cppflags = @X_CFLAGS@
+
+# Extra xdvi-specific compiler options.
+ps_def = @PS_DEF@ -DXSERVER_INFO
+prog_cflags = @XTRA_WARN_CFLAGS@ -I.. -I$(srcdir)/.. $(x_cppflags) $(ps_def)
+
+# Note: to be able to use one depend.mk file for both Motif/Xaw (which
+# is needed since only maintainers are supposed to invoke `make depend')
+# we include *all* object files and have tests for #ifdef MOTIF/XAW inside
+# the files.
+objects = \
+ help-window.o \
+ message-window.o \
+ mag.o \
+ menu.o \
+ Panner.o \
+ pagesel.o \
+ print-dialog.o \
+ print-log.o \
+ search-dialog.o \
+ selection.o \
+ sfDir.o \
+ sfDraw.o \
+ sfPath.o \
+ sfSelFile.o \
+ statusline.o \
+ Tip.o \
+ topic-window.o \
+ xaw_bitmaps.o \
+ xaw_menu.o \
+ xicon.o \
+ xlwradio.o \
+ xm_colorsel.o \
+ xm_filesel.o \
+ xm_menu.o \
+ xm_prefs.o \
+ xm_prefs_appearance.o \
+ xm_prefs_fonts.o \
+ xm_prefs_page.o \
+ xm_prefs_scroll.o \
+ xm_prefs_helpers.o \
+ xm_toolbar.o
+
+libgui.a: $(objects)
+### hmm, I don't understand ar ... sometimes objects were NOT replaced.
+### Play it safe and always remove the archive before creating new one.
+ rm -f $@
+ $(AR) $(ARFLAGS) $@ $(objects)
+ $(RANLIB) $@
+
+kpse_include ../make/dist.mk
+kpse_include ../make/clean.mk
+
+clean::
+ rm -f *.o *.a
+
+c_auto_h_dir = ..
+kpse_include ../make/rdepend.mk
+kpse_include ./gui/depend.mk
diff --git a/Build/source/texk/xdvik/gui/Panner.c b/Build/source/texk/xdvik/gui/Panner.c
new file mode 100644
index 00000000000..1ff157b6242
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Panner.c
@@ -0,0 +1,1230 @@
+/*
+ * $XConsortium: Panner.c,v 1.52 95/01/10 14:31:26 kaleb Exp $
+ *
+Copyright (c) 1989, 1994 X Consortium
+
+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 THE
+X CONSORTIUM 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.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "string-utils.h"
+
+#if defined(MOTIF) && defined(USE_PANNER) && USE_XAW_PANNER /* entire file */
+
+#if defined(__GNUC__) && DEVEL_MODE
+#warning COMPILING Panner_c
+#endif
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h> /* for XtN and XtC defines */
+#include <X11/Xmu/CharSet.h> /* for XmuCompareISOLatin1() */
+#include "PannerP.h" /* us */
+#include <X11/Xos.h>
+#include <X11/Xmu/Misc.h> /* for Min */
+#include <X11/Xmu/Drawing.h>
+#include <ctype.h> /* for isascii() etc. */
+
+extern Bool XmuDistinguishablePixels(); /* not defined in any Xmu headers */
+
+/*
+ ======================================================================
+ begin copy from Simple.c
+ ======================================================================
+*/
+
+#define offset(field) XtOffsetOf(SimpleRec, simple.field)
+
+static XtResource resources[] = {
+ {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None},
+ {XtNinsensitiveBorder, XtCInsensitive, XtRPixmap, sizeof(Pixmap),
+ offset(insensitive_border), XtRImmediate, (XtPointer) NULL},
+ {XtNpointerColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(pointer_fg), XtRString, XtDefaultForeground},
+ {XtNpointerColorBackground, XtCBackground, XtRPixel, sizeof(Pixel),
+ offset(pointer_bg), XtRString, XtDefaultBackground},
+ {XtNcursorName, XtCCursor, XtRString, sizeof(String),
+ offset(cursor_name), XtRString, NULL},
+ {XtNinternational, XtCInternational, XtRBoolean, sizeof(Boolean),
+ offset(international), XtRImmediate, (XtPointer) FALSE},
+#undef offset
+};
+
+static void ClassPartInitialize(), ClassInitialize(),Realize(),ConvertCursor();
+static Bool SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args);
+static Bool ChangeSensitive(Widget w);
+
+SimpleClassRec simpleClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &widgetClassRec,
+ /* class_name */ "Simple",
+ /* widget_size */ sizeof(SimpleRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ FALSE,
+ /* initialize */ NULL,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ NULL,
+ /* expose */ NULL,
+#warning FIXME: incompatible pointer type
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ ChangeSensitive
+#ifndef HAVE_OLD_XAW
+ , NULL
+#endif
+ }
+};
+
+WidgetClass simpleWidgetClass = (WidgetClass)&simpleClassRec;
+
+static void ClassInitialize()
+{
+ static XtConvertArgRec convertArg[] = {
+ {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.screen),
+ sizeof(Screen *)},
+ {XtResourceString, (XtPointer) XtNpointerColor, sizeof(Pixel)},
+ {XtResourceString, (XtPointer) XtNpointerColorBackground,
+ sizeof(Pixel)},
+ {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.colormap),
+ sizeof(Colormap)}
+ };
+
+ XawInitializeWidgetSet();
+ XtSetTypeConverter( XtRString, XtRColorCursor, XmuCvtStringToColorCursor,
+ convertArg, XtNumber(convertArg),
+ XtCacheByDisplay, (XtDestructor)NULL);
+}
+
+static void ClassPartInitialize(class)
+ WidgetClass class;
+{
+ SimpleWidgetClass c = (SimpleWidgetClass) class;
+ SimpleWidgetClass super = (SimpleWidgetClass)
+ c->core_class.superclass;
+
+ if (c->simple_class.change_sensitive == NULL) {
+ char buf[BUFSIZ];
+
+ (void) sprintf(buf,
+ "%s Widget: The Simple Widget class method 'change_sensitive' is undefined.\nA function must be defined or inherited.",
+ c->core_class.class_name);
+ XtWarning(buf);
+ c->simple_class.change_sensitive = ChangeSensitive;
+ }
+
+ if (c->simple_class.change_sensitive == XtInheritChangeSensitive)
+ c->simple_class.change_sensitive = super->simple_class.change_sensitive;
+}
+
+static void Realize(w, valueMask, attributes)
+ Widget w;
+ Mask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ Pixmap border_pixmap = 0;
+ if (!XtIsSensitive(w)) {
+ /* change border to gray; have to remember the old one,
+ * so XtDestroyWidget deletes the proper one */
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ border_pixmap = w->core.border_pixmap;
+ attributes->border_pixmap =
+ w->core.border_pixmap = ((SimpleWidget)w)->simple.insensitive_border;
+
+ *valueMask |= CWBorderPixmap;
+ *valueMask &= ~CWBorderPixel;
+ }
+
+ ConvertCursor(w);
+
+ if ((attributes->cursor = ((SimpleWidget)w)->simple.cursor) != None)
+ *valueMask |= CWCursor;
+
+ XtCreateWindow( w, (unsigned int)InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attributes );
+
+ if (!XtIsSensitive(w))
+ w->core.border_pixmap = border_pixmap;
+}
+
+/* Function Name: ConvertCursor
+ * Description: Converts a name to a new cursor.
+ * Arguments: w - the simple widget.
+ * Returns: none.
+ */
+
+static void
+ConvertCursor(w)
+Widget w;
+{
+ SimpleWidget simple = (SimpleWidget) w;
+ XrmValue from, to;
+ Cursor cursor;
+
+ if (simple->simple.cursor_name == NULL)
+ return;
+
+ from.addr = (XPointer) simple->simple.cursor_name;
+ from.size = strlen((char *) from.addr) + 1;
+
+ to.size = sizeof(Cursor);
+ to.addr = (XPointer) &cursor;
+
+ if (XtConvertAndStore(w, XtRString, &from, XtRColorCursor, &to)) {
+ if ( cursor != None)
+ simple->simple.cursor = cursor;
+ }
+ else {
+ XtAppErrorMsg(XtWidgetToApplicationContext(w),
+ "convertFailed","ConvertCursor","XawError",
+ "Simple: ConvertCursor failed.",
+ (String *)NULL, (Cardinal *)NULL);
+ }
+}
+
+
+/* ARGSUSED */
+static Bool
+SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
+{
+ SimpleWidget s_old = (SimpleWidget) current;
+ SimpleWidget s_new = (SimpleWidget) new;
+ Boolean new_cursor = FALSE;
+
+ UNUSED(request);
+ UNUSED(args);
+ UNUSED(num_args);
+ /* this disables user changes after creation*/
+ s_new->simple.international = s_old->simple.international;
+
+ if ( XtIsSensitive(current) != XtIsSensitive(new) )
+ (*((SimpleWidgetClass)XtClass(new))->
+ simple_class.change_sensitive) ( new );
+
+ if (s_old->simple.cursor != s_new->simple.cursor) {
+ new_cursor = TRUE;
+ }
+
+/*
+ * We are not handling the string cursor_name correctly here.
+ */
+
+ if ( (s_old->simple.pointer_fg != s_new->simple.pointer_fg) ||
+ (s_old->simple.pointer_bg != s_new->simple.pointer_bg) ||
+ (s_old->simple.cursor_name != s_new->simple.cursor_name) ) {
+ ConvertCursor(new);
+ new_cursor = TRUE;
+ }
+
+ if (new_cursor && XtIsRealized(new))
+ XDefineCursor(XtDisplay(new), XtWindow(new), s_new->simple.cursor);
+
+ return False;
+}
+
+
+static Bool ChangeSensitive(Widget w)
+{
+ if (XtIsRealized(w)) {
+ if (XtIsSensitive(w))
+ if (w->core.border_pixmap != XtUnspecifiedPixmap)
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ w->core.border_pixmap );
+ else
+ XSetWindowBorder( XtDisplay(w), XtWindow(w),
+ w->core.border_pixel );
+ else {
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ ((SimpleWidget)w)->
+ simple.insensitive_border );
+ }
+ }
+ return False;
+}
+
+/*
+ ======================================================================
+ end copy from Simple.c
+ ======================================================================
+*/
+
+
+/* following function copied from XawInit.c */
+void XawInitializeWidgetSet ()
+{
+ static int firsttime = 1;
+
+ if (firsttime) {
+ firsttime = 0;
+ XtInitializeWidgetClass (vendorShellWidgetClass);
+ }
+}
+
+static char defaultTranslations[] =
+ "<Btn1Down>: start() \n\
+ <Btn1Motion>: move() \n\
+ <Btn1Up>: notify() stop() \n\
+ <Btn2Down>: abort() \n\
+ :<Key>KP_Enter: set(rubberband,toggle) \n\
+ <Key>space: page(+1p,+1p) \n\
+ <Key>Delete: page(-1p,-1p) \n\
+ :<Key>KP_Delete: page(-1p,-1p) \n\
+ <Key>BackSpace: page(-1p,-1p) \n\
+ <Key>Left: page(-.5p,+0) \n\
+ :<Key>KP_Left: page(-.5p,+0) \n\
+ <Key>Right: page(+.5p,+0) \n\
+ :<Key>KP_Right: page(+.5p,+0) \n\
+ <Key>Up: page(+0,-.5p) \n\
+ :<Key>KP_Up: page(+0,-.5p) \n\
+ <Key>Down: page(+0,+.5p) \n\
+ :<Key>KP_Down: page(+0,+.5p) \n\
+ <Key>Home: page(0,0) \n\
+ :<Key>KP_Home: page(0,0)";
+
+
+static void ActionStart(), ActionStop(), ActionAbort(), ActionMove();
+static void ActionPage(), ActionNotify(), ActionSet();
+
+static XtActionsRec actions[] = {
+ { "start", ActionStart }, /* start tmp graphics */
+ { "stop", ActionStop }, /* stop tmp graphics */
+ { "abort", ActionAbort }, /* punt */
+ { "move", ActionMove }, /* move tmp graphics on Motion event */
+ { "page", ActionPage }, /* page around usually from keyboard */
+ { "notify", ActionNotify }, /* callback new position */
+ { "set", ActionSet }, /* set various parameters */
+};
+
+
+/*
+ * resources for the panner
+ */
+static XtResource panner_resources[] = {
+#define poff(field) XtOffsetOf(PannerRec, panner.field)
+ { XtNallowOff, XtCAllowOff, XtRBoolean, sizeof(Boolean),
+ poff(allow_off), XtRImmediate, (XtPointer) FALSE },
+ { XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
+ poff(resize_to_pref), XtRImmediate, (XtPointer) TRUE },
+ { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
+ poff(report_callbacks), XtRCallback, (XtPointer) NULL },
+ { XtNdefaultScale, XtCDefaultScale, XtRDimension, sizeof(Dimension),
+ poff(default_scale), XtRImmediate, (XtPointer) PANNER_DEFAULT_SCALE },
+ { XtNrubberBand, XtCRubberBand, XtRBoolean, sizeof(Boolean),
+ poff(rubber_band), XtRImmediate, (XtPointer) FALSE },
+ { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ poff(foreground), XtRString, (XtPointer) XtDefaultBackground },
+ { XtNinternalSpace, XtCInternalSpace, XtRDimension, sizeof(Dimension),
+ poff(internal_border), XtRImmediate, (XtPointer) 4 },
+ { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof(Dimension),
+ poff(line_width), XtRImmediate, (XtPointer) 0 },
+ { XtNcanvasWidth, XtCCanvasWidth, XtRDimension, sizeof(Dimension),
+ poff(canvas_width), XtRImmediate, (XtPointer) 0 },
+ { XtNcanvasHeight, XtCCanvasHeight, XtRDimension, sizeof(Dimension),
+ poff(canvas_height), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderX, XtCSliderX, XtRPosition, sizeof(Position),
+ poff(slider_x), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderY, XtCSliderY, XtRPosition, sizeof(Position),
+ poff(slider_y), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderWidth, XtCSliderWidth, XtRDimension, sizeof(Dimension),
+ poff(slider_width), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderHeight, XtCSliderHeight, XtRDimension, sizeof(Dimension),
+ poff(slider_height), XtRImmediate, (XtPointer) 0 },
+ { XtNshadowColor, XtCShadowColor, XtRPixel, sizeof(Pixel),
+ poff(shadow_color), XtRString, (XtPointer) XtDefaultForeground },
+ { XtNshadowThickness, XtCShadowThickness, XtRDimension, sizeof(Dimension),
+ poff(shadow_thickness), XtRImmediate, (XtPointer) 2 },
+ { XtNbackgroundStipple, XtCBackgroundStipple, XtRString, sizeof(String),
+ poff(stipple_name), XtRImmediate, (XtPointer) NULL },
+#undef poff
+};
+
+
+/*
+ * widget class methods used below
+ */
+static void Initialize(); /* create gc's */
+static void PannerRealize(); /* create window */
+static void Destroy(); /* clean up widget */
+static void Resize(); /* need to rescale ourselves */
+static void Redisplay(); /* draw ourselves */
+static Boolean PannerSetValues(); /* set all of the resources */
+static void SetValuesAlmost(); /* deal with failed setval geom req */
+static XtGeometryResult QueryGeometry(); /* say how big we would like to be */
+
+PannerClassRec pannerClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Panner",
+ /* widget_size */ sizeof(PannerRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ PannerRealize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ panner_resources,
+ /* num_resources */ XtNumber(panner_resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ PannerSetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ SetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ XtInheritChangeSensitive
+#ifndef HAVE_OLD_XAW
+ , NULL
+#endif
+ },
+ { /* panner fields */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
+
+
+/*****************************************************************************
+ * *
+ * panner utility routines *
+ * *
+ *****************************************************************************/
+
+static void reset_shadow_gc (pw) /* used when resources change */
+ PannerWidget pw;
+{
+ XtGCMask valuemask = GCForeground;
+ XGCValues values;
+ unsigned long pixels[3];
+
+ if (pw->panner.shadow_gc) XtReleaseGC ((Widget) pw, pw->panner.shadow_gc);
+
+ pixels[0] = pw->panner.foreground;
+ pixels[1] = pw->core.background_pixel;
+ pixels[2] = pw->panner.shadow_color;
+ if (!pw->panner.stipple_name &&
+ !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
+ pixels, 3) &&
+ XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
+ pixels, 2))
+ {
+ valuemask = GCTile | GCFillStyle;
+ values.fill_style = FillTiled;
+ values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
+ pw->panner.foreground,
+ pw->core.background_pixel,
+ pw->core.depth);
+ }
+ else
+ {
+ if (!pw->panner.line_width &&
+ !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
+ pixels, 2))
+ pw->panner.line_width = 1;
+ valuemask = GCForeground;
+ values.foreground = pw->panner.shadow_color;
+ }
+ if (pw->panner.line_width > 0) {
+ values.line_width = pw->panner.line_width;
+ valuemask |= GCLineWidth;
+ }
+
+ pw->panner.shadow_gc = XtGetGC ((Widget) pw, valuemask, &values);
+}
+
+static void reset_slider_gc (pw) /* used when resources change */
+ PannerWidget pw;
+{
+ XtGCMask valuemask = GCForeground;
+ XGCValues values;
+
+ if (pw->panner.slider_gc) XtReleaseGC ((Widget) pw, pw->panner.slider_gc);
+
+ values.foreground = pw->panner.foreground;
+
+ pw->panner.slider_gc = XtGetGC ((Widget) pw, valuemask, &values);
+}
+
+static void reset_xor_gc (pw) /* used when resources change */
+ PannerWidget pw;
+{
+ if (pw->panner.xor_gc) XtReleaseGC ((Widget) pw, pw->panner.xor_gc);
+
+ if (pw->panner.rubber_band) {
+ XtGCMask valuemask = (GCForeground | GCFunction);
+ XGCValues values;
+ Pixel tmp;
+
+ tmp = ((pw->panner.foreground == pw->core.background_pixel) ?
+ pw->panner.shadow_color : pw->panner.foreground);
+ values.foreground = tmp ^ pw->core.background_pixel;
+ values.function = GXxor;
+ if (pw->panner.line_width > 0) {
+ valuemask |= GCLineWidth;
+ values.line_width = pw->panner.line_width;
+ }
+ pw->panner.xor_gc = XtGetGC ((Widget) pw, valuemask, &values);
+ } else {
+ pw->panner.xor_gc = NULL;
+ }
+}
+
+
+static void check_knob (pw, knob)
+ PannerWidget pw;
+ Boolean knob;
+{
+ Position pad = pw->panner.internal_border * 2;
+ Position maxx = (((Position) pw->core.width) - pad -
+ ((Position) pw->panner.knob_width));
+ Position maxy = (((Position) pw->core.height) - pad -
+ ((Position) pw->panner.knob_height));
+ Position *x = (knob ? &pw->panner.knob_x : &pw->panner.tmp.x);
+ Position *y = (knob ? &pw->panner.knob_y : &pw->panner.tmp.y);
+
+ /*
+ * note that positions are already normalized (i.e. internal_border
+ * has been subtracted out)
+ */
+ if (*x < 0) *x = 0;
+ if (*x > maxx) *x = maxx;
+
+ if (*y < 0) *y = 0;
+ if (*y > maxy) *y = maxy;
+
+ if (knob) {
+ pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
+ pw->panner.haspect + 0.5);
+ pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
+ pw->panner.vaspect + 0.5);
+ pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
+ }
+}
+
+
+static void move_shadow (pw)
+ PannerWidget pw;
+{
+ if (pw->panner.shadow_thickness > 0) {
+ int lw = pw->panner.shadow_thickness + pw->panner.line_width * 2;
+ int pad = pw->panner.internal_border;
+
+ if ((int)pw->panner.knob_height > lw && (int)pw->panner.knob_width > lw) {
+ XRectangle *r = pw->panner.shadow_rects;
+ r->x = (short) (pw->panner.knob_x + pad + pw->panner.knob_width);
+ r->y = (short) (pw->panner.knob_y + pad + lw);
+ r->width = pw->panner.shadow_thickness;
+ r->height = (unsigned short) (pw->panner.knob_height - lw);
+ r++;
+ r->x = (short) (pw->panner.knob_x + pad + lw);
+ r->y = (short) (pw->panner.knob_y + pad + pw->panner.knob_height);
+ r->width = (unsigned short) (pw->panner.knob_width - lw +
+ pw->panner.shadow_thickness);
+ r->height = pw->panner.shadow_thickness;
+ pw->panner.shadow_valid = TRUE;
+ return;
+ }
+ }
+ pw->panner.shadow_valid = FALSE;
+}
+
+static void scale_knob (pw, location, size) /* set knob size and/or loc */
+ PannerWidget pw;
+ Boolean location, size;
+{
+ if (location) {
+ pw->panner.knob_x = (Position) PANNER_HSCALE (pw, pw->panner.slider_x);
+ pw->panner.knob_y = (Position) PANNER_VSCALE (pw, pw->panner.slider_y);
+ }
+ if (size) {
+ Dimension width, height;
+
+ if (pw->panner.slider_width < 1) {
+ pw->panner.slider_width = pw->panner.canvas_width;
+ }
+ if (pw->panner.slider_height < 1) {
+ pw->panner.slider_height = pw->panner.canvas_height;
+ }
+ width = Min (pw->panner.slider_width, pw->panner.canvas_width);
+ height = Min (pw->panner.slider_height, pw->panner.canvas_height);
+
+ pw->panner.knob_width = (Dimension) PANNER_HSCALE (pw, width);
+ pw->panner.knob_height = (Dimension) PANNER_VSCALE (pw, height);
+ }
+ if (!pw->panner.allow_off) check_knob (pw, TRUE);
+ move_shadow (pw);
+}
+
+static void rescale (pw)
+ PannerWidget pw;
+{
+ int hpad = pw->panner.internal_border * 2;
+ int vpad = hpad;
+
+ if (pw->panner.canvas_width < 1)
+ pw->panner.canvas_width = pw->core.width;
+ if (pw->panner.canvas_height < 1)
+ pw->panner.canvas_height = pw->core.height;
+
+ if ((int)pw->core.width <= hpad) hpad = 0;
+ if ((int)pw->core.height <= vpad) vpad = 0;
+
+ pw->panner.haspect = ((double) pw->core.width - hpad) /
+ (double) pw->panner.canvas_width;
+ pw->panner.vaspect = ((double) pw->core.height - vpad) /
+ (double) pw->panner.canvas_height;
+ scale_knob (pw, TRUE, TRUE);
+}
+
+
+static void get_default_size (pw, wp, hp)
+ PannerWidget pw;
+ Dimension *wp, *hp;
+{
+ Dimension pad = pw->panner.internal_border * 2;
+ *wp = PANNER_DSCALE (pw, pw->panner.canvas_width) + pad;
+ *hp = PANNER_DSCALE (pw, pw->panner.canvas_height) + pad;
+}
+
+static Boolean get_event_xy (pw, event, x, y)
+ PannerWidget pw;
+ XEvent *event;
+ int *x, *y;
+{
+ int pad = pw->panner.internal_border;
+
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x - pad;
+ *y = event->xbutton.y - pad;
+ return TRUE;
+
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x - pad;
+ *y = event->xkey.y - pad;
+ return TRUE;
+
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x - pad;
+ *y = event->xcrossing.y - pad;
+ return TRUE;
+
+ case MotionNotify:
+ *x = event->xmotion.x - pad;
+ *y = event->xmotion.y - pad;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int parse_page_string (s, pagesize, canvassize, relative)
+ char *s;
+ int pagesize, canvassize;
+ Boolean *relative;
+{
+ char *cp;
+ double val = 1.0;
+ Boolean rel = FALSE;
+
+ /*
+ * syntax: spaces [+-] number spaces [pc\0] spaces
+ */
+
+ for (; isascii(*s) && isspace(*s); s++) ; /* skip white space */
+
+ if (*s == '+' || *s == '-') { /* deal with signs */
+ rel = TRUE;
+ if (*s == '-') val = -1.0;
+ s++;
+ }
+ if (!*s) { /* if null then return nothing */
+ *relative = TRUE;
+ return 0;
+ }
+
+ /* skip over numbers */
+ for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
+ val *= atof(cp);
+
+ /* skip blanks */
+ for (; isascii(*s) && isspace(*s); s++) ;
+
+ if (*s) { /* if units */
+ switch (s[0]) {
+ case 'p': case 'P':
+ val *= (double) pagesize;
+ break;
+
+ case 'c': case 'C':
+ val *= (double) canvassize;
+ break;
+ }
+ }
+ *relative = rel;
+ return ((int) val);
+}
+
+
+#define DRAW_TMP(pw) \
+{ \
+ XDrawRectangle (XtDisplay(pw), XtWindow(pw), \
+ pw->panner.xor_gc, \
+ (int) (pw->panner.tmp.x + pw->panner.internal_border), \
+ (int) (pw->panner.tmp.y + pw->panner.internal_border), \
+ (unsigned int) (pw->panner.knob_width - 1), \
+ (unsigned int) (pw->panner.knob_height - 1)); \
+ pw->panner.tmp.showing = !pw->panner.tmp.showing; \
+}
+
+#define UNDRAW_TMP(pw) \
+{ \
+ if (pw->panner.tmp.showing) DRAW_TMP(pw); \
+}
+
+#define BACKGROUND_STIPPLE(pw) \
+ XmuLocatePixmapFile (pw->core.screen, pw->panner.stipple_name, \
+ pw->panner.shadow_color, pw->core.background_pixel, \
+ pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
+
+#define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
+
+
+/*****************************************************************************
+ * *
+ * panner class methods *
+ * *
+ *****************************************************************************/
+
+
+/*ARGSUSED*/
+static void Initialize (greq, gnew, args, num_args)
+ Widget greq, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
+ Dimension defwidth, defheight;
+
+ UNUSED(args);
+ UNUSED(num_args);
+
+ if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
+ if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
+ if (req->panner.default_scale < 1)
+ new->panner.default_scale = PANNER_DEFAULT_SCALE;
+
+ get_default_size (req, &defwidth, &defheight);
+ if (req->core.width < 1) new->core.width = defwidth;
+ if (req->core.height < 1) new->core.height = defheight;
+
+ new->panner.shadow_gc = NULL;
+ reset_shadow_gc (new); /* shadowColor */
+ new->panner.slider_gc = NULL;
+ reset_slider_gc (new); /* foreground */
+ new->panner.xor_gc = NULL;
+ reset_xor_gc (new); /* foreground ^ background */
+
+ rescale (new); /* does a position check */
+ new->panner.shadow_valid = FALSE;
+ new->panner.tmp.doing = FALSE;
+ new->panner.tmp.showing = FALSE;
+}
+
+
+static void PannerRealize (gw, valuemaskp, attr)
+ Widget gw;
+ XtValueMask *valuemaskp;
+ XSetWindowAttributes *attr;
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Pixmap pm = XtUnspecifiedPixmap;
+ Boolean gotpm = FALSE;
+
+ if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
+ if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
+
+ if (PIXMAP_OKAY(pm)) {
+ attr->background_pixmap = pm;
+ *valuemaskp |= CWBackPixmap;
+ *valuemaskp &= ~CWBackPixel;
+ gotpm = TRUE;
+ }
+ }
+ (*pannerWidgetClass->core_class.superclass->core_class.realize)
+ (gw, valuemaskp, attr);
+
+ if (gotpm) XFreePixmap (XtDisplay(gw), pm);
+}
+
+
+static void Destroy (gw)
+ Widget gw;
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ XtReleaseGC (gw, pw->panner.shadow_gc);
+ XtReleaseGC (gw, pw->panner.slider_gc);
+ XtReleaseGC (gw, pw->panner.xor_gc);
+}
+
+
+static void Resize (gw)
+ Widget gw;
+{
+ rescale ((PannerWidget) gw);
+}
+
+
+/* ARGSUSED */
+static void Redisplay (Widget gw, XEvent *event, Region region)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Display *dpy = XtDisplay(gw);
+ Window w = XtWindow(gw);
+ int pad = pw->panner.internal_border;
+ Dimension lw = pw->panner.line_width;
+ Dimension extra = pw->panner.shadow_thickness + lw * 2;
+ int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
+
+ UNUSED(event);
+ UNUSED(region);
+
+ pw->panner.tmp.showing = FALSE;
+ XClearArea (XtDisplay(pw), XtWindow(pw),
+ (int) pw->panner.last_x - ((int) lw) + pad,
+ (int) pw->panner.last_y - ((int) lw) + pad,
+ (unsigned int) (pw->panner.knob_width + extra),
+ (unsigned int) (pw->panner.knob_height + extra),
+ False);
+ pw->panner.last_x = pw->panner.knob_x;
+ pw->panner.last_y = pw->panner.knob_y;
+
+ XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
+ pw->panner.knob_width - 1, pw->panner.knob_height - 1);
+
+ if (lw)
+ {
+ XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
+ (unsigned int) (pw->panner.knob_width - 1),
+ (unsigned int) (pw->panner.knob_height - 1));
+ }
+
+ if (pw->panner.shadow_valid) {
+ XFillRectangles (dpy, w, pw->panner.shadow_gc,
+ pw->panner.shadow_rects, 2);
+ }
+ if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
+}
+
+
+/* ARGSUSED */
+static Boolean PannerSetValues (Widget gcur, Widget greq, Widget gnew, ArgList args, Cardinal *num_args)
+{
+ PannerWidget cur = (PannerWidget) gcur;
+ PannerWidget new = (PannerWidget) gnew;
+ Boolean redisplay = FALSE;
+
+ UNUSED(greq);
+ UNUSED(args);
+ UNUSED(num_args);
+
+ if (cur->panner.foreground != new->panner.foreground) {
+ reset_slider_gc (new);
+ if (cur->panner.foreground != cur->core.background_pixel)
+ reset_xor_gc (new);
+ redisplay = TRUE;
+ } else if (cur->panner.line_width != new->panner.line_width ||
+ cur->core.background_pixel != new->core.background_pixel) {
+ reset_xor_gc (new);
+ redisplay = TRUE;
+ }
+ if (cur->panner.shadow_color != new->panner.shadow_color) {
+ reset_shadow_gc (new);
+ if (cur->panner.foreground == cur->core.background_pixel)
+ reset_xor_gc (new);
+ redisplay = TRUE;
+ }
+ if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
+ move_shadow (new);
+ redisplay = TRUE;
+ }
+ if (cur->panner.rubber_band != new->panner.rubber_band) {
+ reset_xor_gc (new);
+ if (new->panner.tmp.doing) redisplay = TRUE;
+ }
+
+ if ((cur->panner.stipple_name != new->panner.stipple_name ||
+ cur->panner.shadow_color != new->panner.shadow_color ||
+ cur->core.background_pixel != new->core.background_pixel) &&
+ XtIsRealized(gnew)) {
+ Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
+ : XtUnspecifiedPixmap);
+
+ if (PIXMAP_OKAY(pm)) {
+ XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
+ XFreePixmap (XtDisplay (new), pm);
+ } else {
+ XSetWindowBackground (XtDisplay (new), XtWindow(new),
+ new->core.background_pixel);
+ }
+ redisplay = TRUE;
+ }
+
+ if (new->panner.resize_to_pref &&
+ (cur->panner.canvas_width != new->panner.canvas_width ||
+ cur->panner.canvas_height != new->panner.canvas_height ||
+ cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
+ get_default_size (new, &new->core.width, &new->core.height);
+ redisplay = TRUE;
+ } else if (cur->panner.canvas_width != new->panner.canvas_width ||
+ cur->panner.canvas_height != new->panner.canvas_height ||
+ cur->panner.internal_border != new->panner.internal_border) {
+ rescale (new); /* does a scale_knob as well */
+ redisplay = TRUE;
+ } else {
+ Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
+ cur->panner.slider_y != new->panner.slider_y);
+ Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
+ cur->panner.slider_height != new->panner.slider_height);
+ if (loc || siz ||
+ (cur->panner.allow_off != new->panner.allow_off &&
+ new->panner.allow_off)) {
+ scale_knob (new, loc, siz);
+ redisplay = TRUE;
+ }
+ }
+
+ return redisplay;
+}
+
+static void SetValuesAlmost (gold, gnew, req, reply)
+ Widget gold, gnew;
+ XtWidgetGeometry *req, *reply;
+{
+ if (reply->request_mode == 0) { /* got turned down, so cope */
+ Resize (gnew);
+ }
+ (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
+ (gold, gnew, req, reply);
+}
+
+static XtGeometryResult QueryGeometry (gw, intended, pref)
+ Widget gw;
+ XtWidgetGeometry *intended, *pref;
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ pref->request_mode = (CWWidth | CWHeight);
+ get_default_size (pw, &pref->width, &pref->height);
+
+ if (((intended->request_mode & (CWWidth | CWHeight)) ==
+ (CWWidth | CWHeight)) &&
+ intended->width == pref->width &&
+ intended->height == pref->height)
+ return XtGeometryYes;
+ else if (pref->width == pw->core.width && pref->height == pw->core.height)
+ return XtGeometryNo;
+ else
+ return XtGeometryAlmost;
+}
+
+
+/*****************************************************************************
+ * *
+ * panner action procs *
+ * *
+ *****************************************************************************/
+
+/* ARGSUSED */
+static void ActionStart (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ int x, y;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!get_event_xy (pw, event, &x, &y)) {
+ XBell (XtDisplay(gw), 0); /* should do error message */
+ return;
+ }
+
+ pw->panner.tmp.doing = TRUE;
+ pw->panner.tmp.startx = pw->panner.knob_x;
+ pw->panner.tmp.starty = pw->panner.knob_y;
+ pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
+ pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
+ pw->panner.tmp.x = pw->panner.knob_x;
+ pw->panner.tmp.y = pw->panner.knob_y;
+ if (pw->panner.rubber_band) DRAW_TMP (pw);
+}
+
+/* ARGSUSED */
+static void ActionStop (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ int x, y;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (get_event_xy (pw, event, &x, &y)) {
+ pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
+ pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
+ if (!pw->panner.allow_off) check_knob (pw, FALSE);
+ }
+ if (pw->panner.rubber_band) UNDRAW_TMP (pw);
+ pw->panner.tmp.doing = FALSE;
+}
+
+/* ARGSUSED */
+static void ActionAbort (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!pw->panner.tmp.doing) return;
+
+ if (pw->panner.rubber_band) UNDRAW_TMP (pw);
+
+ if (!pw->panner.rubber_band) { /* restore old position */
+ pw->panner.tmp.x = pw->panner.tmp.startx;
+ pw->panner.tmp.y = pw->panner.tmp.starty;
+ ActionNotify (gw, event, params, num_params);
+ }
+ pw->panner.tmp.doing = FALSE;
+}
+
+
+/* ARGSUSED */
+static void ActionMove (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ int x, y;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!pw->panner.tmp.doing) return;
+
+ if (!get_event_xy (pw, event, &x, &y)) {
+ XBell (XtDisplay(gw), 0); /* should do error message */
+ return;
+ }
+
+ if (pw->panner.rubber_band) UNDRAW_TMP (pw);
+ pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
+ pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
+
+ if (!pw->panner.rubber_band) {
+ ActionNotify (gw, event, params, num_params); /* does a check */
+ } else {
+ if (!pw->panner.allow_off) check_knob (pw, FALSE);
+ DRAW_TMP (pw);
+ }
+}
+
+
+/* ARGSUSED */
+static void ActionPage (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Cardinal zero = 0;
+ Boolean isin = pw->panner.tmp.doing;
+ int x, y;
+ Boolean relx, rely;
+ int pad = pw->panner.internal_border * 2;
+
+ UNUSED(event);
+ UNUSED(num_params);
+
+ if (*num_params != 2) {
+ XBell (XtDisplay(gw), 0);
+ return;
+ }
+
+ x = parse_page_string (params[0], (int) pw->panner.knob_width,
+ ((int) pw->core.width) - pad, &relx);
+ y = parse_page_string (params[1], (int) pw->panner.knob_height,
+ ((int) pw->core.height) - pad, &rely);
+
+ if (relx) x += pw->panner.knob_x;
+ if (rely) y += pw->panner.knob_y;
+
+ if (isin) { /* if in, then use move */
+ XEvent ev;
+ ev.xbutton.type = ButtonPress;
+ ev.xbutton.x = x;
+ ev.xbutton.y = y;
+ ActionMove (gw, &ev, (String *) NULL, &zero);
+ } else { /* else just do it */
+ pw->panner.tmp.doing = TRUE;
+ pw->panner.tmp.x = x;
+ pw->panner.tmp.y = y;
+ ActionNotify (gw, event, (String *) NULL, &zero);
+ pw->panner.tmp.doing = FALSE;
+ }
+}
+
+
+/* ARGSUSED */
+static void ActionNotify (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!pw->panner.tmp.doing) return;
+
+ if (!pw->panner.allow_off) check_knob (pw, FALSE);
+ pw->panner.knob_x = pw->panner.tmp.x;
+ pw->panner.knob_y = pw->panner.tmp.y;
+ move_shadow (pw);
+
+ pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
+ pw->panner.haspect + 0.5);
+ pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
+ pw->panner.vaspect + 0.5);
+ if (!pw->panner.allow_off) {
+ Position tmp;
+
+ if (pw->panner.slider_x >
+ (tmp = (((Position) pw->panner.canvas_width) -
+ ((Position) pw->panner.slider_width))))
+ pw->panner.slider_x = tmp;
+ if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
+ if (pw->panner.slider_y >
+ (tmp = (((Position) pw->panner.canvas_height) -
+ ((Position) pw->panner.slider_height))))
+ pw->panner.slider_y = tmp;
+ if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
+ }
+
+ if (pw->panner.last_x != pw->panner.knob_x ||
+ pw->panner.last_y != pw->panner.knob_y) {
+ XawPannerReport rep;
+
+ Redisplay (gw, (XEvent*) NULL, (Region) NULL);
+ rep.changed = (XawPRSliderX | XawPRSliderY);
+ rep.slider_x = pw->panner.slider_x;
+ rep.slider_y = pw->panner.slider_y;
+ rep.slider_width = pw->panner.slider_width;
+ rep.slider_height = pw->panner.slider_height;
+ rep.canvas_width = pw->panner.canvas_width;
+ rep.canvas_height = pw->panner.canvas_height;
+ XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
+ }
+}
+
+/* ARGSUSED */
+static void ActionSet (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Boolean rb;
+
+ UNUSED(event);
+
+ if (*num_params < 2 ||
+ XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
+ XBell (XtDisplay(gw), 0);
+ return;
+ }
+
+ if (XmuCompareISOLatin1 (params[1], "on") == 0) {
+ rb = TRUE;
+ } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
+ rb = FALSE;
+ } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
+ rb = !pw->panner.rubber_band;
+ } else {
+ XBell (XtDisplay(gw), 0);
+ return;
+ }
+
+ if (rb != pw->panner.rubber_band) {
+ Arg args[1];
+ XtSetArg (args[0], XtNrubberBand, rb);
+ XtSetValues (gw, args, (Cardinal) 1);
+ }
+}
+
+#endif /* MOTIF && USE_PANNER */
diff --git a/Build/source/texk/xdvik/gui/Panner.h b/Build/source/texk/xdvik/gui/Panner.h
new file mode 100644
index 00000000000..7ced64ebcad
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Panner.h
@@ -0,0 +1,108 @@
+/*
+ * $XConsortium: Panner.h,v 1.22 94/04/17 20:12:32 rws Exp $
+ *
+Copyright (c) 1989 X Consortium
+
+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 THE
+X CONSORTIUM 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.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPanner_h
+#define _XawPanner_H
+
+#include <X11/Xaw/Reports.h>
+
+/*****************************************************************************
+ *
+ * Panner Widget (subclass of Simple)
+ *
+ * This widget is used to represent navigation in a 2d coordinate system.
+ *
+ * Parameters:
+ *
+ * Name Class Type Default
+ * ---- ----- ---- -------
+ *
+ * allowOff AllowOff Boolean FALSE
+ * background Background Pixel XtDefaultBackground
+ * backgroundStipple BackgroundStipple String NULL
+ * canvasWidth CanvasWidth Dimension 0
+ * canvasHeight CanvasHeight Dimension 0
+ * defaultScale DefaultScale Dimension 8 percent
+ * foreground Foreground Pixel XtDefaultBackground
+ * internalSpace InternalSpace Dimension 4
+ * lineWidth LineWidth Dimension 0
+ * reportCallback ReportCallback XtCallbackList NULL
+ * resize Resize Boolean TRUE
+ * rubberBand RubberBand Boolean FALSE
+ * shadowColor ShadowColor Pixel XtDefaultForeground
+ * shadowThickness ShadowThickness Dimension 2
+ * sliderX SliderX Position 0
+ * sliderY SliderY Position 0
+ * sliderWidth SliderWidth Dimension 0
+ * sliderHeight SliderHeight Dimension 0
+ *
+ *****************************************************************************/
+
+ /* new instance and class names */
+#ifndef _XtStringDefs_h_
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#endif
+
+#define XtNallowOff "allowOff"
+#define XtCAllowOff "AllowOff"
+#define XtNbackgroundStipple "backgroundStipple"
+#define XtCBackgroundStipple "BackgroundStipple"
+#define XtNdefaultScale "defaultScale"
+#define XtCDefaultScale "DefaultScale"
+#define XtNcanvasWidth "canvasWidth"
+#define XtCCanvasWidth "CanvasWidth"
+#define XtNcanvasHeight "canvasHeight"
+#define XtCCanvasHeight "CanvasHeight"
+#define XtNinternalSpace "internalSpace"
+#define XtCInternalSpace "InternalSpace"
+#define XtNlineWidth "lineWidth"
+#define XtCLineWidth "LineWidth"
+#define XtNrubberBand "rubberBand"
+#define XtCRubberBand "RubberBand"
+#define XtNshadowThickness "shadowThickness"
+#define XtCShadowThickness "ShadowThickness"
+#define XtNshadowColor "shadowColor"
+#define XtCShadowColor "ShadowColor"
+#define XtNsliderX "sliderX"
+#define XtCSliderX "SliderX"
+#define XtNsliderY "sliderY"
+#define XtCSliderY "SliderY"
+#define XtNsliderWidth "sliderWidth"
+#define XtCSliderWidth "SliderWidth"
+#define XtNsliderHeight "sliderHeight"
+#define XtCSliderHeight "SliderHeight"
+
+ /* external declarations */
+extern WidgetClass pannerWidgetClass;
+
+typedef struct _PannerClassRec *PannerWidgetClass;
+typedef struct _PannerRec *PannerWidget;
+
+#endif /* _XawPanner_h */
diff --git a/Build/source/texk/xdvik/gui/PannerP.h b/Build/source/texk/xdvik/gui/PannerP.h
new file mode 100644
index 00000000000..5c8fbc8cee5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/PannerP.h
@@ -0,0 +1,104 @@
+/*
+ * $XConsortium: PannerP.h,v 1.19 94/04/17 20:12:33 jim Exp $
+ *
+Copyright (c) 1989 X Consortium
+
+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 THE
+X CONSORTIUM 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.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPannerP_h
+#define _XawPannerP_h
+
+#include "Panner.h"
+#include <X11/Xaw/SimpleP.h> /* parent */
+
+typedef struct { /* new fields in widget class */
+ int dummy;
+} PannerClassPart;
+
+typedef struct _PannerClassRec { /* Panner widget class */
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ PannerClassPart panner_class;
+} PannerClassRec;
+
+typedef struct { /* new fields in widget */
+ /* resources... */
+ XtCallbackList report_callbacks; /* callback/Callback */
+ Boolean allow_off; /* allowOff/AllowOff */
+ Boolean resize_to_pref; /* resizeToPreferred/Boolean */
+ Pixel foreground; /* foreground/Foreground */
+ Pixel shadow_color; /* shadowColor/ShadowColor */
+ Dimension shadow_thickness; /* shadowThickness/ShadowThickness */
+ Dimension default_scale; /* defaultScale/DefaultScale */
+ Dimension line_width; /* lineWidth/LineWidth */
+ Dimension canvas_width; /* canvasWidth/CanvasWidth */
+ Dimension canvas_height; /* canvasHeight/CanvasHeight */
+ Position slider_x; /* sliderX/SliderX */
+ Position slider_y; /* sliderY/SliderY */
+ Dimension slider_width; /* sliderWidth/SliderWidth */
+ Dimension slider_height; /* sliderHeight/SliderHeight */
+ Dimension internal_border; /* internalBorderWidth/BorderWidth */
+ String stipple_name; /* backgroundStipple/BackgroundStipple */
+ /* private data... */
+ GC slider_gc; /* background of slider */
+ GC shadow_gc; /* edge of slider and shadow */
+ GC xor_gc; /* for doing XOR tmp graphics */
+ double haspect, vaspect; /* aspect ratio of core to canvas */
+ Boolean rubber_band; /* true = rubber band, false = move */
+ struct {
+ Boolean doing; /* tmp graphics in progress */
+ Boolean showing; /* true if tmp graphics displayed */
+ Position startx, starty; /* initial position of slider */
+ Position dx, dy; /* offset loc for tmp graphics */
+ Position x, y; /* location for tmp graphics */
+ } tmp;
+ Position knob_x, knob_y; /* real upper left of knob in canvas */
+ Dimension knob_width, knob_height; /* real size of knob in canvas */
+ Boolean shadow_valid; /* true if rects are valid */
+ XRectangle shadow_rects[2]; /* location of shadows */
+ Position last_x, last_y; /* previous location of knob */
+} PannerPart;
+
+typedef struct _PannerRec {
+ CorePart core;
+ SimplePart simple;
+ PannerPart panner;
+} PannerRec;
+
+#define PANNER_HSCALE(pw,val) ((pw)->panner.haspect * ((double) (val)))
+#define PANNER_VSCALE(pw,val) ((pw)->panner.vaspect * ((double) (val)))
+
+#define PANNER_DSCALE(pw,val) (Dimension) \
+ ((((unsigned long) (val)) * (unsigned long) pw->panner.default_scale) / 100L)
+#define PANNER_DEFAULT_SCALE 8 /* percent */
+
+#define PANNER_OUTOFRANGE -30000
+
+/*
+ * external declarations
+ */
+extern PannerClassRec pannerClassRec;
+
+#endif /* _XawPannerP_h */
diff --git a/Build/source/texk/xdvik/gui/Tip.c b/Build/source/texk/xdvik/gui/Tip.c
new file mode 100644
index 00000000000..76a83f188b9
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Tip.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki 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.
+ *
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "Tip.h"
+#include "xdvi-debug.h"
+#include "util.h"
+
+#ifdef MOTIF /* needed for `make depend' */
+
+#ifndef UNUSED
+#define UNUSED(x) ((void)(x))
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <Xm/XmP.h>
+
+#include <Xm/PushB.h>
+#include <X11/ShellP.h>
+
+#define TIP_NUM 1024 /* FIXME: remove this hard-coded value */
+
+typedef struct {
+ int __empty;
+} TipClassPart;
+
+/* Full class record declaration */
+typedef struct _TipClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ShellClassPart shell_class;
+ OverrideShellClassPart override_shell_class;
+ TipClassPart tip_class;
+} TipClassRec;
+
+/* keep information about each widget we are keeping track of */
+struct tip_context {
+ Widget watched; /* the widget we are watching */
+ Window window; /* Window of the object we are monitoring */
+ TipWidget tw; /* pointer back to the tip widget */
+ Position abs_x, abs_y;
+ Boolean active; /* if False, tip is suppressed */
+ char *text; /* text to display */
+ short size; /* its size */
+};
+
+/* New fields for the widget record */
+typedef struct {
+ /* resources */
+ Pixel foreground;
+ XFontSet fontset; /* the font for text in box */
+ int waitPeriod; /* the delay resource - pointer must be
+ * in watched widget this long before
+ * help is popped up - in millisecs
+ */
+ unsigned int cwp; /* after help is popped down - normal
+ * wait period is cancelled for this
+ * period - in millisecs
+ */
+
+ /* private state */
+ struct tip_context twl[TIP_NUM]; /* list of widgets we are liteClue-ing */
+ Cardinal nr_twl; /* number of widgets we have attached */
+ Dimension font_width; /* width of '1' character */
+ Dimension font_height; /* height of font, rows are spaced using this */
+ Dimension font_baseline; /* relative displacement to baseline from top */
+ GC text_GC; /* for drawing text */
+ XtIntervalId tid; /* holds timer id */
+ Widget isup; /* the help popup is up on this widget */
+ Time HelpPopDownTime; /* the time at which help popup
+ was popped down */
+} TipPart;
+
+/*
+ * Full instance record declaration
+ */
+typedef struct _TipRec {
+ CorePart core;
+ CompositePart composite;
+ ShellPart shell;
+ OverrideShellPart override;
+ TipPart tip;
+} TipRec;
+
+#define CheckWidgetClass(routine) \
+ if (XtClass(w) != tipWidgetClass) \
+ wrong_widget(routine)
+
+static void initialize(Widget, Widget, ArgList, Cardinal *);
+static Boolean set_values(Widget, Widget, Widget, ArgList, Cardinal *);
+static void destroy(Widget);
+
+/*
+ * Widget resources: eg to set tip box background: *tipShell.background: yellow.
+ */
+
+#define offset(field) XtOffsetOf(TipRec, field)
+static XtResource resources[] = {
+ {XtNforeground, XtCForeground,
+ XtRPixel, sizeof(Pixel), offset(tip.foreground),
+ XtRString, "black"},
+ {XtNfontSet, XtCFontSet,
+ XtRFontSet, sizeof(XFontSet), offset(tip.fontset),
+ XtRString, "fixed"},
+ {XmNwaitPeriod, XmCWaitPeriod,
+ XtRInt, sizeof(int), offset(tip.waitPeriod),
+ XtRImmediate, (XtPointer) 800},
+ {XmNcancelWaitPeriod, XmCCancelWaitPeriod,
+ XtRInt, sizeof(int), offset(tip.cwp),
+ XtRImmediate, (XtPointer) 250},
+};
+#undef offset
+
+TipClassRec tipClassRec = {
+ {
+ /* superclass */ (WidgetClass) & overrideShellClassRec,
+ /* class_name */ "Tip",
+ /* widget size */ (Cardinal) sizeof(TipRec),
+ /* class_init */ NULL,
+ /* class_part_init */ (XtWidgetClassProc) NULL,
+ /* class_inited */ (XtEnum) FALSE,
+ /* initialize */ (XtInitProc) initialize,
+ /* init_hook */ (XtArgsProc) NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ (XtActionList) 0,
+ /* num_actions */ (Cardinal) 0,
+ /* resources */ (XtResourceList) resources,
+ /* num_resources */ (Cardinal) XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposur */ (XtEnum) FALSE,
+ /* compress enterleave */ TRUE,
+ /* visibility_interest */ FALSE,
+ /* destroy */ destroy,
+ /* resize */ XtInheritResize,
+ /* expose, */ XtInheritExpose,
+ /* set_values */ (XtSetValuesFunc) set_values,
+ /* set_values_hook */ (XtArgsFunc) NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ (XtArgsProc) NULL,
+ /* accept_focus */ XtInheritAcceptFocus,
+ /* version */ XtVersion,
+ /* callback_private */ (XtPointer) NULL,
+ /* translations */ XtInheritTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ (XtPointer) 0,
+ },
+ /* composite part */
+ {
+ /* geometry_manager */ XtInheritGeometryManager,
+ /* change_managed */ XtInheritChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ },
+ /* Shell */
+ {
+ (XtPointer) NULL,
+ },
+ /* Override Shell */
+ {
+ 0,
+ },
+ /* tip */
+ {
+ 0,
+ }
+};
+
+WidgetClass tipWidgetClass = (WidgetClass) & tipClassRec;
+
+/*
+ * The font_information is derived.
+ */
+static void compute_font_info(TipWidget cw)
+{
+ XRectangle ink;
+ XRectangle logical;
+
+ if (!cw->tip.fontset)
+ return;
+ XmbTextExtents(cw->tip.fontset, "1", 1, &ink, &logical);
+
+ cw->tip.font_baseline = -logical.y; /* y offset from top to baseline, don't
+ know why this is returned as
+ negative */
+
+ cw->tip.font_width = logical.width; /* the width and height of the object */
+
+ cw->tip.font_height = logical.height;
+ TRACE_GUI((stderr, "baseline: %d, width: %d, height: %d\n",
+ cw->tip.font_baseline, cw->tip.font_width, cw->tip.font_height));
+}
+
+/*
+ * Creates the various graphic contexts we will need.
+ */
+static void create_GC(TipWidget cw)
+{
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ valuemask = GCForeground | GCBackground | GCFillStyle;
+ myXGCV.foreground = cw->tip.foreground;
+ myXGCV.background = cw->core.background_pixel;
+ myXGCV.fill_style = FillSolid;
+
+ if (cw->tip.text_GC)
+ XtReleaseGC((Widget) cw, cw->tip.text_GC);
+ cw->tip.text_GC = XtGetGC((Widget) cw, valuemask, &myXGCV);
+}
+
+/*
+ * A routine to halt execution and force a core dump for debugging analysis
+ * when a public routine is called with the wrong class of widget.
+ */
+
+static void wrong_widget(char *routine)
+{
+ XDVI_ABORT((stderr, "Wrong class of widget passed to %s", routine));
+}
+
+/*
+ * Global list of shells for tips that are in use.
+ */
+
+static TipWidget *shells = NULL;
+static int nr_shells = 0;
+
+/****************************************************************************
+ * Widget Methods
+ */
+
+static void initialize(Widget treq, Widget tnew, ArgList args,
+ Cardinal * nargs)
+{
+ TipWidget tw = (TipWidget) tnew;
+
+ UNUSED(treq);
+ UNUSED(args);
+ UNUSED(nargs);
+
+ tw->tip.text_GC = NULL;
+ tw->tip.isup = NULL;
+ tw->tip.HelpPopDownTime = 0;
+ tw->tip.tid = (XtIntervalId) 0;
+ tw->tip.nr_twl = 0;
+ compute_font_info(tw);
+ create_GC(tw);
+
+ /* Add to our list of tip shells.
+ */
+ if (!shells)
+ shells = (TipWidget *)XtMalloc(sizeof(TipWidget));
+ else
+ shells = (TipWidget *)XtRealloc((char *)shells,
+ sizeof(TipWidget) * (nr_shells + 1));
+
+ shells[nr_shells++] = tw;
+}
+
+static Boolean set_values(Widget _current, Widget _request, Widget _new,
+ ArgList args, Cardinal * nargs)
+{
+ TipWidget cw_new = (TipWidget) _new;
+ TipWidget cw_cur = (TipWidget) _current;
+
+ UNUSED(_request);
+ UNUSED(args);
+ UNUSED(nargs);
+
+ /* values of cw_new->tip.cwp and
+ cw_new->tip.waitPeriod are accepted without checking */
+
+ if (cw_new->tip.foreground != cw_cur->tip.foreground
+ || cw_new->core.background_pixel !=
+ cw_cur->core.background_pixel) {
+ create_GC(cw_new);
+ }
+ return FALSE;
+}
+
+static void destroy(Widget w)
+{
+ TipWidget tw = (TipWidget) w;
+ int i;
+ Boolean copy = False;
+
+ /* Remove this tip shell from our global list.
+ */
+ for (i = 0; i < nr_shells; ++i) {
+ if (shells[i] == tw) {
+ copy = True;
+ --nr_shells;
+ }
+ if (copy && nr_shells)
+ shells[i] = shells[i + 1];
+ }
+ if (!nr_shells) {
+ XtFree((char *) shells);
+ shells = NULL;
+ }
+}
+
+/****************************************************************************
+ * Event handlers
+ */
+
+/* callback to popup the tip window
+ */
+static void timeout_event(XtPointer client_data, XtIntervalId *id)
+{
+#define HBorderPix 3
+#define VBorderPix 3
+ struct tip_context *obj = (struct tip_context *) client_data;
+ TipWidget tw = obj->tw;
+ Position abs_x, abs_y;
+ int ptr_x, ptr_y;
+
+ XRectangle ink;
+ XRectangle logical;
+ Position w_height, w_width;
+ Widget w;
+
+ UNUSED(id);
+
+ TRACE_GUI((stderr, "timeout called!"));
+
+ if (tw->tip.tid == (XtIntervalId) 0)
+ return; /* timeout was removed but callback happened
+ anyway */
+
+ tw->tip.tid = (XtIntervalId) 0;
+ if (obj->active == False)
+ return;
+
+ w = obj->watched;
+
+ if (!XtIsManaged(w))
+ return;
+
+ { /* perform additional check that pointer is really still over the widget;
+ else, tooltips will sometimes pop up if window had received an Enter
+ event before (for some reason, not all Enters are followed by Leaves).
+ This is especially apparent when running xdvi from a remote display over
+ a slow connection.
+ */
+ Window root, child;
+ int root_x, root_y;
+ unsigned int keys_buttons;
+ if (!XQueryPointer(DISP, RootWindowOfScreen(SCRN), &root, &child,
+ &root_x, &root_y, &ptr_x, &ptr_y, &keys_buttons))
+ return;
+
+ TRACE_GUI((stderr, "Pointerlocate: %d, %d", root_x, root_y));
+
+ XtVaGetValues(w, XtNheight, &w_height, XtNwidth, &w_width, NULL);
+ XtTranslateCoords(w, 0, 0, &abs_x, &abs_y);
+
+ TRACE_GUI((stderr, "Window: %d,%d - %d,%d",
+ abs_x, abs_y, abs_x + w_width, abs_y + w_height));
+
+ if (root_x < abs_x || root_x > abs_x + w_width
+ || root_y < abs_y || root_y > abs_y + w_height) {
+ TRACE_GUI((stderr, "not really over toolbutton - returning!"));
+ return;
+ }
+ }
+
+ /* position just below the pointer
+ * (NOT the widget, in case the widget is large!)
+ */
+ ptr_y += 20;
+/* abs_x += w_width / 2; */
+/* abs_y += w_height; */
+
+ XmbTextExtents(tw->tip.fontset, obj->text, obj->size, &ink, &logical);
+
+ XtRealizeWidget((Widget)tw); /* so that setting the size etc. works */
+
+ XtResizeWidget((Widget) tw,
+ 2 * HBorderPix + logical.width,
+ 2 * VBorderPix + tw->tip.font_height,
+ tw->core.border_width);
+ TRACE_GUI((stderr, "Popup size: %d x %d (hborder: %d, vborder: %d)\n",
+ 2 * HBorderPix + logical.width, 2 * VBorderPix + tw->tip.font_height,
+ HBorderPix, VBorderPix));
+ XtMoveWidget((Widget)tw, ptr_x, ptr_y);
+
+ XtPopup((Widget) tw, XtGrabNone);
+ tw->tip.isup = obj->watched;
+
+ XmbDrawImageString(XtDisplay((Widget) tw),
+ XtWindow((Widget) tw),
+ tw->tip.fontset,
+ tw->tip.text_GC,
+ HBorderPix,
+ VBorderPix + tw->tip.font_baseline,
+ obj->text, obj->size);
+}
+
+/*
+ * Pointer enters watched widget, set a timer to popup the help.
+ */
+static void enter(struct tip_context *obj, XEvent * xevent,
+ XtAppContext app)
+{
+ TipWidget tw = obj->tw;
+ XEnterWindowEvent *event = &xevent->xcrossing;
+ int current_waitPeriod;
+
+ /* this doesn't help against the Enter/Leave problem mentioned above,
+ so it's not related to Widget creation ... */
+ if (!XtIsManaged(obj->watched)) {
+ TRACE_GUI((stderr, "%s:%d: Not yet managed!", __FILE__, __LINE__));
+ return;
+ }
+
+ TRACE_GUI((stderr, "%s:%d: Enter!", __FILE__, __LINE__));
+
+ if (obj->active == False)
+ return;
+
+ /* check for two enters in a row - happens when widget is
+ exposed under a pop-up */
+ if (tw->tip.tid != (XtIntervalId) 0)
+ return;
+
+ if (event->mode != NotifyNormal)
+ return;
+
+ /* it seems that this makes the tooltips somewhat unpredictable (they
+ don't show when hovering fast over several buttons, then staying on
+ one button); disabled this for the time being. */
+/* if ((event->time - tw->tip.HelpPopDownTime) > tw->tip.cwp) */
+/* current_waitPeriod = tw->tip.waitPeriod; */
+/* else */
+/* current_waitPeriod = 0; */
+
+/* current_waitPeriod = tw->tip.waitPeriod; */
+ current_waitPeriod = resource.tooltips_wait_period;
+ if (current_waitPeriod >= 0) {
+ tw->tip.tid = XtAppAddTimeOut(app, current_waitPeriod, timeout_event,
+ (XtPointer) obj);
+ }
+}
+
+/*
+ * Remove timer if its pending. Then popdown help.
+ */
+static void leave(struct tip_context *obj, XEvent * xevent)
+{
+ TipWidget tw = obj->tw;
+ XEnterWindowEvent *event = &xevent->xcrossing;
+
+ TRACE_GUI((stderr, "%s:%d: Leave!", __FILE__, __LINE__));
+
+ if (tw->tip.tid != (XtIntervalId) 0) {
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: removing timeout %ld\n", __FILE__, __LINE__, tw->tip.tid);
+ XtRemoveTimeOut(tw->tip.tid);
+ tw->tip.tid = (XtIntervalId) 0;
+ }
+
+ if (obj->active == False)
+ return;
+
+ if (tw->tip.isup) {
+ XtPopdown((Widget) tw);
+ tw->tip.isup = NULL;
+ tw->tip.HelpPopDownTime = event->time;
+ }
+}
+
+/****************************************************************************
+ * Public interface implementation.
+ */
+
+void TipAppHandle(XtAppContext app, XEvent *event)
+{
+ int i;
+
+ if (!(event->type == EnterNotify
+ || event->type == MotionNotify
+ || event->type == LeaveNotify
+ || event->type == ButtonPress)) {
+ return;
+ }
+
+ for (i = 0; i < nr_shells; ++i) {
+ unsigned int j;
+
+ for (j = 0; j < shells[i]->tip.nr_twl; ++j) {
+ if (event->xany.window == shells[i]->tip.twl[j].window) {
+ if (event->type == EnterNotify)
+ enter(shells[i]->tip.twl + j, event, app);
+ if (event->xany.type == LeaveNotify
+ || event->xany.type == MotionNotify /* FIXME: this doesn' work? */
+ /* might be useful to popdown tip when mouse is moved */
+ || event->xany.type == ButtonPress) {
+ leave(shells[i]->tip.twl + j, event);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This has to replace the XtAppMainLoop in the application using
+ * tooltips.
+ */
+void TipAppMainLoop(XtAppContext app)
+{
+ XEvent event;
+
+ for (;;) {
+ XtAppNextEvent(app, &event);
+ TipAppHandle(app, &event);
+ XtDispatchEvent(&event);
+ }
+}
+
+/*
+ * Add a widget to be watched for tooltips.
+ *
+ * This function must be called after the widget has been realized!
+ * Further on please make sure that this function will not be called twice
+ * for one button!
+ *
+ * w - tip widget
+ * watch - the widget to give tips for
+ * text - pointer to tip text
+ */
+void TipAddWidget(Widget w, Widget watch, const String text)
+{
+#define ROUTINE "TipAddWidget"
+ TipWidget tw = (TipWidget) w;
+ int i;
+
+ CheckWidgetClass(ROUTINE); /* make sure we are called with a tip widget */
+
+ /* Make internal resource available via resource.tooltips_wait_period(_bak) and
+ * resource.show_tooltips.
+ */
+ resource.tooltips_wait_period_bak = resource.tooltips_wait_period = ABS(tw->tip.waitPeriod);
+ if (tw->tip.waitPeriod < 0) {
+ resource.show_tooltips = False;
+ }
+ else if (!resource.show_tooltips) {
+ if (resource.tooltips_wait_period == 0)
+ resource.tooltips_wait_period = -1;
+ else
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+
+ for (i = 0; i < nr_shells; ++i)
+ if (shells[i] == tw) {
+ struct tip_context *obj;
+
+ if (tw->tip.nr_twl >= TIP_NUM) {
+ XDVI_FATAL((stderr, "Too many tip widgets, cannot add new tip"));
+ return;
+ }
+ obj = tw->tip.twl + tw->tip.nr_twl;
+ obj->text = XtNewString(text);
+ obj->size = strlen(text);
+ obj->watched = watch;
+ obj->window = XtWindow(watch);
+ obj->active = True;
+ obj->tw = tw;
+ tw->tip.nr_twl++;
+ }
+#undef ROUTINE
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/Tip.h b/Build/source/texk/xdvik/gui/Tip.h
new file mode 100644
index 00000000000..b4cb8a957c0
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Tip.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki 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.
+ *
+ */
+
+#ifndef TIP_H_
+#define TIP_H_
+
+#ifdef MOTIF
+/* Tooltip widget handling. This has somewhat of a library character,
+ * but we don't want to go into the trouble of making a library for just
+ * one function.
+ */
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+/* New resource names
+ */
+#define XmNcancelWaitPeriod "cancelWaitPeriod"
+#define XmNwaitPeriod "waitPeriod"
+
+/* New resource classes
+ */
+#define XmCCancelWaitPeriod "CancelWaitPeriod"
+#define XmCWaitPeriod "WaitPeriod"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+ extern WidgetClass tipWidgetClass;
+ typedef struct _TipClassRec *TipWidgetClass;
+ typedef struct _TipRec *TipWidget;
+
+ extern void TipAddWidget(Widget, Widget, const String);
+ extern void TipAppMainLoop(XtAppContext);
+ extern void TipAppHandle(XtAppContext, XEvent *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* MOTIF */
+#endif /* TIP_H_ */
diff --git a/Build/source/texk/xdvik/gui/TipP.h b/Build/source/texk/xdvik/gui/TipP.h
new file mode 100644
index 00000000000..5c2f7daea24
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/TipP.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki 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.
+ *
+ */
+
+#ifndef TIPP_h
+#define TIPP_h
+
+#include <X11/ShellP.h>
+
+#include "Tip.h"
+
+/* Doubly Linked List Processing.
+ */
+struct list_thread_str {
+ struct list_thread_str *forw;
+ struct list_thread_str *back;
+};
+typedef struct list_thread_str ListThread;
+
+typedef struct {
+ int __empty;
+} TipClassPart;
+
+/* Full class record declaration.
+ */
+typedef struct _TipClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ShellClassPart shell_class;
+ OverrideShellClassPart override_shell_class;
+ TipClassPart tip_class;
+} TipClassRec;
+
+extern TipClassRec xmTipClassRec;
+
+/* New fields for the widget record.
+ */
+typedef struct {
+ /* resources */
+ Pixel foreground;
+ XFontSet fontset; /* the font for text in box */
+ int waitPeriod; /* the delay resource - pointer must be
+ in watched widget this long before
+ tooltip is displayed - in milliseconds
+ */
+ int cancelWaitPeriod; /* after help is popped-down - normal
+ wait period is cancelled for this
+ period - in milliseconds
+ */
+
+ /* -------- private state --------- */
+ ListThread widget_list; /* list of widgets we are liteClue-ing */
+ Dimension font_width; /* width of '1' character */
+ Dimension font_height; /* height of font, rows are spaced using this */
+ Dimension font_baseline; /* relative displacement to baseline from top */
+ GC text_GC; /* for drawing text */
+ XtIntervalId tid; /* holds timer id */
+ XtIntervalId pid; /* holds pooler id for insensitive widgets */
+ Widget parent;
+ Widget isup; /* the help popup is up on this widget */
+ Time HelpPopDownTime; /* the time at which help popup was popped down */
+} TipPart;
+
+
+/*
+ * Full instance record declaration
+ */
+typedef struct _TipRec {
+ CorePart core;
+ CompositePart composite;
+ ShellPart shell;
+ OverrideShellPart override;
+ TipPart tip;
+} TipRec;
+
+#endif
diff --git a/Build/source/texk/xdvik/gui/depend.mk b/Build/source/texk/xdvik/gui/depend.mk
new file mode 100644
index 00000000000..2f62ce49923
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/depend.mk
@@ -0,0 +1,528 @@
+help-window.o: help-window.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ message-window.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h ../string-utils.h ../my-vsnprintf.h \
+ topic-window.h help-window.h
+mag.o: mag.c \
+ ../xdvi-config.h ../c-auto.h \
+ ../c-openmx.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/systypes.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h $(kpathsea_srcdir)/types.h \
+ $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h ../dvi-draw.h ../dvi-init.h \
+ statusline.h ../hypertex.h mag.h xm_toolbar.h xm_menu.h menu.h \
+ xaw_menu.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ pagesel.h
+menu.o: menu.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h menu.h xm_menu.h xaw_menu.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h
+message-window.o: message-window.c \
+ ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../string-utils.h ../my-vsnprintf.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h message-window.h
+pagesel.o: pagesel.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xm_toolbar.h xm_menu.h menu.h ../events.h \
+ xaw_menu.h ../x_util.h \
+ message-window.h pagesel.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../string-utils.h ../my-vsnprintf.h \
+ ../dvi-init.h statusline.h print-dialog.h ../search-internal.h \
+ search-dialog.h ../dvisel.h ../print-internal.h ../pagehist.h
+Panner.o: Panner.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../string-utils.h ../my-vsnprintf.h
+print-dialog.o: print-dialog.c \
+ ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../my-vsnprintf.h \
+ print-dialog.h print-log.h ../print-internal.h ../dvi-init.h \
+ ../events.h ../string-utils.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../x_util.h message-window.h pagesel.h \
+ ../my-snprintf.h sfSelFile.h ../dvisel.h xlwradio.h statusline.h \
+ search-dialog.h ../search-internal.h ../special.h
+print-log.o: print-log.c \
+ ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ print-dialog.h print-log.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h xlwradio.h
+search-dialog.o: search-dialog.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h ../dvi-init.h search-dialog.h \
+ ../search-internal.h ../dvisel.h ../print-internal.h print-dialog.h \
+ xlwradio.h statusline.h ../string-utils.h ../my-vsnprintf.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ message-window.h ../x_util.h
+selection.o: selection.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../encodings.h message-window.h selection.h \
+ statusline.h
+sfDir.o: sfDir.c ../xdvi-config.h ../c-auto.h sfDir.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-stat.h
+sfDraw.o: sfDraw.c ../xdvi-config.h ../c-auto.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ sfDraw.h sfDir.h sfPath.h
+sfPath.o: sfPath.c ../xdvi-config.h ../c-auto.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ sfDir.h sfDraw.h sfPath.h sfSelFile.h
+sfSelFile.o: sfSelFile.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../dvi-init.h message-window.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ sfDir.h sfPath.h sfDraw.h sfSelFile.h \
+ ../util.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ ../events.h $(kpathsea_srcdir)/c-fopen.h
+statusline.o: statusline.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ statusline.h xm_menu.h menu.h ../events.h \
+ xaw_menu.h ../x_util.h ../pagehist.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../my-vsnprintf.h
+Tip.o: Tip.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ Tip.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h
+topic-window.o: topic-window.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ topic-window.h ../string-utils.h ../my-vsnprintf.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h
+xaw_bitmaps.o: xaw_bitmaps.c xaw_bitmaps.h
+xaw_menu.o: xaw_menu.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../c-openmx.h ../events.h ../dvi-draw.h \
+ ../dvi-init.h statusline.h pagesel.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../x_util.h xaw_menu.h message-window.h \
+ ../my-snprintf.h ../filehist.h
+xicon.o: xicon.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xicon.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h \
+ ../xdvi.icon ../pixmaps/xdvi32x32.xpm ../pixmaps/xdvi16x16.xpm \
+ ../pixmaps/xdvi48x48.xpm
+xlwradio.o: xlwradio.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h xaw_bitmaps.h xlwradioP.h \
+ xlwradio.h
+xm_colorsel.o: xm_colorsel.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ Tip.h \
+ ../x_util.h xm_colorsel.h xm_prefsP.h \
+ xm_prefs.h ../events.h ../dvi-draw.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ topic-window.h ../search-internal.h \
+ search-dialog.h ../dvisel.h ../dvi-init.h ../print-internal.h \
+ print-dialog.h
+xm_filesel.o: xm_filesel.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ sfSelFile.h ../dvi.h ../string-utils.h \
+ ../my-vsnprintf.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h message-window.h ../dvi-init.h
+xm_menu.o: xm_menu.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xm_menu.h menu.h ../events.h xaw_menu.h \
+ xm_toolbar.h ../my-snprintf.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../x_util.h statusline.h ../pagehist.h \
+ ../dvi-init.h ../filehist.h ../c-openmx.h message-window.h
+xm_prefs_appearance.o: xm_prefs_appearance.c ../xdvi-config.h ../c-auto.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h ../my-snprintf.h xm_colorsel.h \
+ topic-window.h message-window.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h xm_toolbar.h xm_menu.h menu.h \
+ xaw_menu.h statusline.h pagesel.h xm_prefsP.h xm_prefs_appearance.h
+xm_prefs.o: xm_prefs.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ message-window.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h xm_prefsP.h xm_prefs.h \
+ xm_prefs_appearance.h xm_prefs_fonts.h xm_prefs_helpers.h \
+ xm_prefs_page.h xm_prefs_scroll.h ../dvi-draw.h ../search-internal.h \
+ search-dialog.h ../dvisel.h ../dvi-init.h ../print-internal.h \
+ print-dialog.h statusline.h xm_toolbar.h xm_menu.h menu.h xaw_menu.h \
+ pagesel.h
+xm_prefs_fonts.o: xm_prefs_fonts.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../hypertex.h ../my-snprintf.h \
+ xm_prefsP.h xm_prefs_fonts.h
+xm_prefs_helpers.o: xm_prefs_helpers.c ../xdvi-config.h ../c-auto.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../string-utils.h \
+ ../my-vsnprintf.h message-window.h xm_menu.h menu.h xaw_menu.h \
+ xm_prefsP.h xm_prefs.h xm_prefs_helpers.h
+xm_prefs_page.o: xm_prefs_page.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h statusline.h xm_prefsP.h \
+ xm_prefs_page.h ../my-snprintf.h
+xm_prefs_scroll.o: xm_prefs_scroll.c ../xdvi-config.h ../c-auto.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../dvi-init.h statusline.h \
+ xm_prefsP.h xm_prefs_scroll.h ../my-snprintf.h
+xm_toolbar.o: xm_toolbar.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ pagesel.h help-window.h message-window.h \
+ $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/expand.h statusline.h \
+ ../dvi-init.h ../events.h ../dvi-draw.h xm_menu.h menu.h xaw_menu.h \
+ xm_toolbar.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ ../x_util.h Tip.h \
+ ../c-openmx.h ../pixmaps/toolbar.xpm
diff --git a/Build/source/texk/xdvik/gui/help-window.c b/Build/source/texk/xdvik/gui/help-window.c
new file mode 100644
index 00000000000..8f7e6612a0e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/help-window.c
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (c) 2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Help window for xdvik, using the `topics' window framework.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+#if MOTIF
+# include <Xm/Xm.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/Text.h>
+# include <Xm/Protocols.h>
+#else /* MOTIF */
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/AsciiText.h>
+#endif /* MOTIF */
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "message-window.h"
+#include "util.h"
+#include "x_util.h"
+#include "string-utils.h"
+#include "topic-window.h"
+#include "help-window.h"
+
+/* missing features that will be listed in the help window */
+#if !XDVI_XT_TIMER_HACK
+#define HAVE_MISSING_FEATURES 1
+#endif
+
+#if !HAVE_REGEX_H
+#define HAVE_MISSING_FEATURES 1
+#endif
+
+/*
+ * The number of help topics - must larger or equal to actual number of items,
+ * also keep in sync with elements resource.help_* !!!
+ */
+#define NUM_HELP_TOPICS 16
+
+/*
+ * helper routines
+ */
+
+static Widget
+create_help_text(Widget parent, const char *name, const char *value)
+{
+ Widget text;
+#if MOTIF
+ Arg args[20];
+ int n = 0;
+
+ XtSetArg(args[n], XmNeditable, False); n++;
+ XtSetArg(args[n], XmNcursorPositionVisible, False); n++;
+ XtSetArg(args[n], XmNvalue, value); n++;
+ XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
+ XtSetArg(args[n], XmNwordWrap, True); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+/* XtSetArg(args[n], XmNtopWidget, top_widget); n++; */
+/* XtSetArg(args[n], XmNtopOffset, 10); n++; */
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
+ XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmAS_NEEDED); n++;
+
+ text = XmCreateScrolledText(parent, (char *)name, args, n);
+
+ XtManageChild(text);
+#else /* MOTIF */
+ text = XtVaCreateManagedWidget(name, asciiTextWidgetClass, parent,
+ /* XtNfromVert, top_widget, */
+ /* XtNvertDistance, 10, */
+ XtNstring, value,
+ XtNheight, 400,
+ XtNwidth, 500,
+ /* resizing of pane by user isn't needed */
+ XtNshowGrip, False,
+ XtNscrollVertical, XawtextScrollAlways,
+ XtNscrollHorizontal, XawtextScrollNever,
+ XtNeditType, XawtextRead,
+ XtNleftMargin, 5,
+ NULL);
+ XawTextDisplayCaret(text, False);
+#endif /* MOTIF */
+ return text;
+}
+
+
+static void
+get_title_and_summary(const char *str, int len, char **title, char **summary)
+{
+ char *tmp = xmalloc(len + 1);
+ char *ptr;
+
+ memcpy(tmp, str, len);
+ tmp[len] = '\0';
+
+ if ((ptr = strchr(tmp, '\t')) == NULL) {
+ XDVI_WARNING((stderr, "Help resource label `%s' doesn't contain a tab character - ignoring it.", tmp));
+ *title = tmp;
+ *summary = NULL;
+ }
+ else {
+ *ptr++ = '\0';
+ *title = tmp;
+ *summary = ptr;
+ }
+
+ TRACE_GUI((stderr, "Title, Summary: |%s|%s|", *title, *summary));
+}
+
+static void
+init_item(const char *resource, const char **resource_default,
+ struct topic_info *info, size_t idx, Dimension *width)
+{
+ const char *ptr = NULL;
+ char *widget_text = NULL;
+ Widget help_form;
+ Widget text;
+ struct topic_item *item = &(info->items[idx]);
+ char *translation_str = get_string_va("#override \n"
+ "<Key>q:close-topic-window(%p)\n"
+#ifdef MOTIF
+ "<Key>osfCancel:close-topic-window(%p)\n"
+#else
+ "<Key>Escape:close-topic-window(%p)\n"
+#endif
+ "<Key>Return:close-topic-window(%p)",
+ info, info, info);
+
+ if (resource != NULL) {
+ if ((ptr = strchr(resource, '\n')) == NULL) {
+ XDVI_WARNING((stderr, "Help resource text `%s' doesn't contain a newline character.", resource));
+ ptr = resource;
+ }
+ else
+ ptr++;
+ get_title_and_summary(resource, ptr - resource - 1,
+ &(item->topic), &(item->title));
+ }
+ else { /* resource not set; copy resource_default into malloc()ed widget_text: */
+ size_t size = 0, alloc_len = 0, offset;
+ const size_t alloc_step = 1024;
+ int i;
+
+ for (i = 0; resource_default[i] != NULL; i++) {
+ if (i == 0) { /* special case */
+ get_title_and_summary(resource_default[i], strlen(resource_default[i]) - 1,
+ &(item->topic), &(item->title));
+ }
+ else {
+ offset = size;
+ size += strlen(resource_default[i]);
+ /*
+ * allocate chunks of `alloc_step' to avoid frequent calls to malloc.
+ * `alloc_len' is always 1 more than `size', for the terminating NULL character.
+ */
+ while (size + 1 > alloc_len) {
+ alloc_len += alloc_step;
+ widget_text = xrealloc(widget_text, alloc_len);
+ }
+ memcpy(widget_text + offset, resource_default[i], size - offset);
+ }
+ }
+ /* null-terminate string */
+ widget_text[size] = '\0';
+ }
+
+ help_form = XtVaCreateManagedWidget("help_form",
+#if MOTIF
+ xmFormWidgetClass, info->right_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ formWidgetClass, info->right_form,
+ XtNborderWidth, 0,
+ XtNdefaultDistance, 0,
+#endif
+ NULL);
+ item->widget = help_form;
+ if (ptr != NULL) {
+ text = create_help_text(help_form, "help_text", ptr);
+ }
+ else {
+ text = create_help_text(help_form, "help_text", widget_text);
+ free(widget_text);
+ }
+ XtOverrideTranslations(text, XtParseTranslationTable(translation_str));
+ free(translation_str);
+#if !MOTIF
+ {
+ Dimension w;
+ XtVaGetValues(text, XtNwidth, &w, NULL);
+ if (w > *width)
+ *width = w;
+ }
+#else
+ UNUSED(width);
+#endif
+}
+
+static void
+initialize_items(struct topic_info *info)
+{
+ size_t k;
+ Dimension width;
+
+ /*
+ * Define fallbacks: default_xyz is used as fallback text if
+ * X resource xyz isn't specified.
+ *
+ * We use arrays of strings rather than simple strings because of C's
+ * limitations on maximum string length; but since the resource needs to
+ * be a simple `char *', these have to be copied into larger buffers
+ * later on (which is a bit wasteful to space). OTOH, splitting the
+ * strings into smaller pieces would make them hard to deal with as
+ * X resources. They are defined as static so that they are initialized
+ * only once.
+ *
+ * Last elem of each array is NULL for ease of looping through it.
+ *
+ * Advantages of this method vs. putting the help texts into a file:
+ * - couldn't use #ifdef's as easily
+ * - would need to invent our own file format
+ * - file searching is more error-prone (needs to be installed etc.)
+ */
+
+ static const char *default_help_general[] = {
+ "Introduction\tAbout this version of xdvi\n",
+ "This is xdvik, version ",
+ XDVI_TERSE_VERSION_INFO
+ ".\nThe program's homepage is located at:\n",
+ "http://sourceforge.net/projects/xdvi\n",
+ "where you can find updates, report bugs and submit feature requests.\n",
+ "\n",
+ "\n",
+ "Xdvi has many command-line options, too numerous to be listed here;\n",
+ "see the man page for a full description.\n",
+ "\n",
+ "The most important key bindings are listed in the help sections shown\n",
+ "in the left window.\n",
+ "\n",
+ "Note: Unless a key binding also has an uppercase version,\n",
+ "all bindings are case-insensitive.\n\n",
+ "\n",
+ "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",
+ "Built on ",
+ __DATE__,
+ " using these configure options:\n",
+#if MOTIF
+ "- Motif toolkit (",
+ XmVERSION_STRING,
+ ")\n",
+#else
+ "- Athena toolkit\n",
+#endif
+#ifdef A4
+ "- paper: a4, units cm\n",
+#else
+ "- paper: letter, units inches\n",
+#endif
+#ifdef GREY
+ "- anti-aliasing (grey) enabled\n",
+#endif
+#ifdef T1LIB
+ "- T1lib (direct rendering of PS fonts) enabled\n",
+#endif
+#if HAVE_ICONV_H
+ "- Iconv support compiled in\n",
+#if USE_LANGINFO
+ "- Langinfo support compiled in\n",
+#else
+ "- Langinfo support not compiled in\n",
+#endif
+#else
+ "- Iconv/langinfo support not compiled in\n",
+#endif
+#ifdef TEXXET
+ "- left-to-right typesetting (TeXXeT) support enabled\n",
+#endif
+#ifdef USE_GF
+ "- gf file support enabled\n",
+#endif
+#if HAVE_MISSING_FEATURES
+ "\n",
+ "Features not available on this platform:\n",
+#if !XDVI_XT_TIMER_HACK
+ "- Could not redefine XtAppAddTimeOut(); some widgets may\n",
+ " not be updated until the mouse is moved.\n",
+#endif
+#if !HAVE_REGEX_H
+ "- regex.h header not available, regular expression support\n",
+ " in string search is disabled.\n",
+#endif
+#endif /* HAVE_MISSING_FEATURES */
+ NULL
+ };
+
+ static const char *default_help_hypertex[] = {
+ "Hyperlinks\tNavigating links\n",
+ "Whenever the mouse is positioned on a link, the cursor changes\n",
+ "to a `hand' shape and the target of the link is displayed\n",
+ "in the statusline at the bottom of the window.\n",
+ "\n",
+ "The following keybindings are pre-configured:\n",
+ "\n",
+ "Mouse-1\n",
+ " Follow the link at the cursor position.\n",
+ " If the link target is not a DVI file, try to launch\n",
+ " an application to view the file.\n",
+ "Mouse-2\n",
+ " Open a new xdvi window displaying the link\n",
+ " at the cursor position if the link is a DVI file;\n",
+ " else, try to launch an application to view the file.\n",
+ "B",
+#if MOTIF
+ ", toolbar button 9\n",
+#else
+ "\n",
+#endif
+ " Go back to the previous hyperlink in the history.\n",
+ "F",
+#if MOTIF
+ ", toolbar button 10\n",
+#else
+ "\n",
+#endif
+ " Go forward to the next hyperlink in the history.\n",
+ "\n",
+ "By default, the hyperlinks are displayed in the colors \n",
+ "`linkColor' and `visitedLinkColor' (for visited links) and \n",
+ "underlined in the same colors. This can be customized \n",
+ "by setting the resource or command-line option `linkstyle' \n",
+ "to a value between 0 and 3, which have the following meaning:\n",
+ " 0: no highlighting of links,\n",
+ " 1: underline links,\n",
+ " 2: color links,\n",
+ " 3: color and underline links.\n\n",
+ NULL
+ };
+
+ static const char *default_help_othercommands[] = {
+ "Other Commands\tMiscellaneous other commands\n",
+ "Ctrl-f\n",
+ " Opens a dialog window to search for a text string\n",
+ " in the DVI file.\n",
+ "\n",
+ "Ctrl-g\n",
+ " Search for the next string match.\n",
+ "\n",
+ "Ctrl-l\n",
+ " Toggles fullscreen mode (which may not work with your\n",
+ " window manager/desktop).\n",
+ "\n",
+ "Ctrl-o",
+#if MOTIF
+ ", toolbar button 1\n",
+#else
+ "\n",
+#endif
+ " Opens a popup window to select another DVI file.\n",
+ " With a prefix argument `n', the `n'th file from the file history\n",
+ " is opened instead.\n",
+ "\n",
+ "Ctrl-p",
+#if MOTIF
+ ", toolbar button 11\n",
+#else
+ "\n",
+#endif
+ " Opens a popup window for printing the DVI file, or parts of it.\n",
+ "\n",
+ "Ctrl-r or Clear\n",
+ " Redisplays the current page.\n",
+ "\n",
+ "Ctrl-s\n",
+ " Opens a popup window for saving the DVI file, or parts of it.\n",
+ "\n",
+ "G\n",
+ " Toggles the use of greyscale anti-aliasing for\n",
+ " displaying shrunken bitmaps. In addition, the key\n",
+ " sequences `0G' and `1G' clear and set this flag,\n",
+ " respectively. See also the -nogrey option.\n",
+ "\n",
+ "k\n",
+ " Normally when xdvi switches pages, it moves to the home\n",
+ " position as well. The `k' keystroke toggles a `keep-\n",
+ " position' flag which, when set, will keep the same\n",
+ " position when moving between pages. Also `0k' and `1k'\n",
+ " clear and set this flag, respectively. See also the\n",
+ " -keep option.\n",
+ "\n",
+ "M\n",
+ " Sets the margins so that the point currently under the\n",
+ " cursor is the upper left-hand corner of the text in the\n",
+ " page. Note that this command itself does not move the\n",
+ " image at all. For details on how the margins are used,\n",
+ " see the -margins option.\n",
+ "\n",
+ "P\n",
+ " ``This is page number n.'' This can be used to make\n",
+ " the `g' keystroke refer to a different page number.\n",
+ " (See also `Options->Use TeX Page Numbers' and the\n",
+ " `T' keystroke).\n",
+ "\n",
+ "R",
+#if MOTIF
+ ", toolbar button 2\n",
+#else
+ "\n",
+#endif
+ " Forces the DVI file to be reread.\n",
+ "\n",
+ "s\n",
+ " Changes the shrink factor to the given number.\n",
+ " If no number is given, the smallest factor that makes the\n",
+ " entire page fit in the window will be used. (Margins\n",
+ " are ignored in this computation.)\n",
+ "\n",
+ "S\n",
+ " Sets the density factor to be used when shrinking\n",
+ " bitmaps. This should be a number between 0 and 100;\n",
+ " higher numbers produce lighter characters.\n",
+ "\n",
+ "t\n",
+ " Switches to the next unit in a sorted list of TeX dimension\n",
+ " units for the popup magnifier ruler and `Ruler mode' (see the\n",
+ " section `Modes').\n"
+ "\n",
+ "V\n",
+ " Toggles Ghostscript anti-aliasing. Also `0V' and `1V' clear\n",
+ " and enables this mode, respectively. See also the the\n",
+ " -gsalpha option.\n",
+ "\n",
+ "\n",
+ "v\n",
+ " Toggles between several modes of displaying postscript specials:\n",
+ " Display specials, display specials with their bounding box\n",
+ " (if available), and display bounding boxes only (if available).\n",
+ " The prefix arguments 1, 2 and 0 also allow you to select one of\n"
+ " these states directly.\n",
+ "\n",
+ "x\n",
+ " Toggles expert mode (in which ",
+#if MOTIF
+ "the menu bar, the toolbar\n",
+#else
+ "the menu buttons,\n",
+#endif
+ " the page list and the statusline do not appear).\n",
+ " `1x' toggles the display of the statusline at the bottom of the window.\n",
+ " `2x' toggles the scrollbars,\n",
+#if MOTIF
+ " `3x' toggles the page list,\n",
+ " `4x' toggles the toolbar,\n",
+ " `5x' toggles the menu bar.\n",
+#else
+ " `3x' toggles the page list and menu buttons.\n",
+#endif
+ "\n",
+ "Ctrl-+",
+#if MOTIF
+ ", toolbar button 7\n",
+#else
+ "\n",
+#endif
+ " Makes the display of the page larger (zooms in).\n",
+ "\n",
+ "Ctrl-+",
+#if MOTIF
+ ", toolbar button 8\n",
+#else
+ "\n",
+#endif
+ " Makes the display of the page smaller (zooms out).\n",
+ "\n",
+ "Alt-Ctrl-+",
+#if MOTIF
+ ", toolbar button 16\n",
+#else
+ "\n",
+#endif
+ " Makes the fonts darker (by adding to the gamma value).\n",
+ "\n",
+ "Alt-Ctrl--",
+#if MOTIF
+ ", toolbar button 17\n",
+#else
+ "\n",
+#endif
+ " Makes the fonts lighter (by substracting from the gamma\n",
+ " value).\n",
+ "\n",
+ NULL
+ };
+
+ static const char *default_help_marking[] = {
+ "Printing and Saving\tMarking, printing and saving pages\n",
+ "The `Save' and `Print' dialogs allow you to save or print all,\n",
+ "pages, a range of pages, or all marked pages from a DVI file.\n",
+ "\n",
+ "Note that the page numbers for the `From ... to ...' range\n",
+ "refer to physical pages, not TeX pages (compare the option\n",
+ "`Use TeX Page Numbers' and the `T' keystroke).\n",
+ "\n",
+ "To mark a page or a range of pages, use one of the folllowing\n",
+ "methods:\n",
+ "- Click on the page in the page list with Mouse Button 2 to mark\n",
+ " a single page, or drag the mouse while holding down Button 2\n",
+ " to mark a range of pages.\n",
+ "- Use one of the following key combinations:\n",
+ " m: toggle the mark of the current page,\n",
+ " 1m toggle the marks of all odd pages,\n",
+ " 2m toggle the marks of all even pages,\n",
+ " 0m: unmark all pages,\n",
+ " Ctrl-n: toggle mark of current page, then move one page forward,\n",
+ " Ctrl-u: move one page back, then toggle mark of that page.\n",
+#if MOTIF
+ "- Use one of the toobar buttons 12 to 15 to toggle the marks\n",
+ " of odd pages, toggle the marks of even pages, toggle the mark\n",
+ " of the current page, or unmark all pages, respectively.\n",
+#endif
+ "\n",
+ "If the X resource or command line option `paper' has been used,\n",
+ "its value is inserted into the `Dvips Options' field of the printing\n",
+ "dialog so that the appropriate options can be passed to dvips.\n",
+ "This doesn't happen if the paper size has been specified explicitly\n",
+ "in the DVI file (e.g. by using the LaTeX `geometry' package).\n",
+ "Note that not all of the paper options used by xdvi\n",
+ "may be understood by dvips; dvips will ignore the option\n",
+ "in that case, and will use its default paper setting.\n",
+ NULL
+ };
+
+ static const char *default_help_pagemotion[] = {
+ "Page Motion\tMoving around in the document\n",
+ "\n",
+ "[\n",
+ " Moves back one item in the page history. With a prefix\n",
+ " argument n, move back n history items.\n"
+ "\n",
+ "]\n",
+ " Moves forward one item in the page history. With a prefix\n",
+ " argument n, move forward n history items.\n"
+ "\n",
+ "Ctr-[\n",
+ " Deletes current item in the page history and move\n",
+ " to the history item before the deleted one. With a prefix\n",
+ " argument n, delete n previous history items.\n",
+ "\n",
+ "Ctr-]\n",
+ " Deletes current item in the page history and move\n",
+ " to the history item after the deleted one. With a prefix\n",
+ " argument n, delete n next history items.\n",
+ "\n",
+ "n or f or Space or Return or LineFeed or PgDn",
+#if MOTIF
+ ", toolbar button 5\n",
+#else
+ "\n",
+#endif
+ " Moves to the next page (or to the nth next page if a\n",
+ " number is given).\n",
+ "\n",
+ "p or b or Ctrl-h or BackSpace or Del or PgUp",
+#if MOTIF
+ ", toolbar button 4\n",
+#else
+ "\n",
+#endif
+ " Moves to the previous page (or back n pages).\n",
+ "\n",
+ "Up-arrow\n",
+ " Scrolls page up.\n",
+ "\n",
+ "Down-arrow\n",
+ " Scrolls page down.\n",
+ "u\n",
+ " Moves page up two thirds of a window-full.\n",
+ "\n",
+ "d\n",
+ " Moves page down two thirds of a window-full.\n",
+ "\n",
+ "Left-arrow\n",
+ " Scrolls page left.\n",
+ "\n",
+ "Right-arrow\n",
+ " Scrolls page right.\n",
+ "\n",
+ "l\n",
+ " Moves page left two thirds of a window-full.\n",
+ "\n",
+ "r\n",
+ " Moves page right two thirds of a window-full.\n",
+ "\n",
+ "T\n",
+ " Toggle the use of TeX page numbers instead of physical\n",
+ " pages for the page list and the `g' command.\n",
+ " (See also the `Options -> Use TeX Pages' menu.)\n",
+ "\n",
+ "g\n",
+ " Moves to the page with the given number. Initially,\n",
+ " the first page is assumed to be page number 1, but this\n",
+ " can be changed with the `P' keystroke, described in the\n",
+ " section `Other Commands'. If no page number is given,\n",
+ " it moves to the last page.\n",
+ "\n",
+ "<, Ctrl-Home",
+#if MOTIF
+ ", toolbar button 3\n",
+#else
+ "\n",
+#endif
+ " Moves to first page in the document.\n",
+ "\n",
+ ">, Ctrl-End",
+#if MOTIF
+ ", toolbar button 6\n",
+#else
+ "\n",
+#endif
+ " Moves to last page in the document.\n",
+ "\n",
+ "^\n",
+ " Move to the ``home'' position of the page. This is\n",
+ " normally the upper left-hand corner of the page,\n",
+ " depending on the margins set via the -margins option.\n",
+ "\n",
+ "Home\n",
+ " Move to the ``home'' position of the page (the upper\n",
+ " left-hand corner), or to the top of the page if the `keep'\n",
+ " flag is set.\n",
+ "\n",
+ "End\n",
+ " Move to the end position of the page (the lower\n",
+ " right-hand corner), or to the bottom of the page if the\n",
+ " `keep' flag is set.\n",
+ "\n",
+ "c\n",
+ " Moves the page so that the point currently beneath the\n",
+ " cursor is moved to the middle of the window. It also\n",
+ " warps the cursor to the same place.\n",
+ "\n",
+ NULL
+ };
+
+
+ static const char *default_help_mousebuttons[] = {
+ "Mouse Buttons\tActions bound to the mouse buttons\n",
+ "The mouse buttons can be customized just like the keys;\n",
+ "however the bindings cannot be intermixed (since\n",
+ "a mouse event always requires the cursor location\n",
+ "to be present, which a key event doesn't).\n",
+ "The default bindings are as follows:\n"
+ "\n",
+ "Buttons 1-3\n",
+ " Pops up magnifier windows of different sizes.\n",
+ " When the mouse is over a hyperlink, the link overrides\n",
+ " the magnifier. In that case, Button 1 jumps to the link\n",
+ " in the current xdvi window, Button 2 opens the link target\n",
+ " in a new instance of xdvi.\n",
+ " In `Ruler Mode', Button1 shows/drags the ruler instead;\n",
+ " in `Text Selection Mode', Button1 can be used to select\n",
+ " a rectangular region of text from the DVI file.\n",
+ "\n",
+ "Shift-Button1 to Shift-Button3\n",
+ " Drag the page in each direction (Button 1), vertically\n",
+ " only (Button 2) or horizontally only (Button 3).\n",
+ "\n",
+ "Ctrl-Button1\n",
+ " Invoke a reverse search for the text on the cursor\n",
+ " location (see the section SOURCE SPECIALS for more\n",
+ " information on this).\n",
+ "\n",
+ "The buttons 4 and 5 (wheel up and down for wheel mice)\n",
+ "scroll the page up and down respectively, or jump to the\n",
+ "next/previous page when the mouse is over the page list.",
+ "\n",
+ "In the page list, Button 2 toggles the mark a page (see\n",
+ "section `Marking Pages'); moving the mouse while holding\n",
+ "Button 2 lets you toggle a range of pages.\n",
+ "\n",
+ NULL
+ };
+
+ static const char *default_help_sourcespecials[] = {
+ "Source Specials\tNavigating between the TeX and the DVI file\n",
+ "Some TeX implementations have an option to automatically\n",
+ "include so-called `source specials' into a DVI file. These\n",
+ "contain the line number and the filename of the TeX source\n",
+ "and make it possible to go from a DVI file to the\n",
+ "(roughly) corresponding place in the TeX source and back\n",
+ "(this is also called `reverse search' and `forward search').\n",
+ "\n",
+ "On the TeX side, you need a TeX version that supports the `-src'\n",
+ "option (e.g. teTeX >= 2.0) or a macro package like srcltx.sty\n",
+ "to insert the specials into the DVI file.\n",
+ "\n",
+ "Source special mode can be customized for various editors\n",
+ "by using the command line option \"-editor\" or one of the\n",
+ "environment variables \"XEDITOR\", \"VISUAL\" or \"EDITOR\".\n",
+ "See the xdvi man page on the \"-editor\" option for details\n",
+ "and examples.\n",
+ "\n",
+ "Forward search can be performed by a program (i.e. your editor)\n",
+ "invoking xdvi with the \"-sourceposition\" option like this:\n",
+ "xdvi -sourceposition \"<line> <filename>\" <main file>\n",
+ "If there is already an instance of xdvi running that displays\n",
+ "<main file>, it will try to open the page specified by\n",
+ "<line> and <filename> an highlight this location on the page.\n",
+ "Else, a new instance of xdvi will be started that will try to\n",
+ "do the same.\n",
+ "\n",
+ "The following keybindings are pre-configured:\n",
+ "\n",
+ "Ctrl-Mouse1\n",
+ " [source-special()] Invoke the editor (the value\n",
+ " of the \"editor\" resource ) to display the line in the\n",
+ " TeX file corresponding to special at cursor position.\n",
+ "\n",
+ "Ctrl-v\n",
+ " [show-source-specials()] Show bounding boxes for every\n",
+ " source special on the current page, and print the strings\n",
+ " contained in these specials to stderr. With prefix 1,\n",
+ " show every bounding box on the page (for debugging purposes).\n",
+ "\n",
+ "Ctrl-x\n",
+ " [source-what-special()] Display information about the\n",
+ " source special next to the cursor, similar to\n",
+ " \"source-special()\", but without actually invoking\n",
+ " the editor (for debugging purposes).\n",
+ "\n",
+ NULL
+ };
+
+ static const char *default_help_modes[] = {
+ "Mouse Modes\tMagnifier Mode, Ruler Mode and Text Selection Mode\n",
+ "The keystroke Ctrl-m [switch-mode()] switches between\n",
+ "three different bindings for Mouse-1, which can also be\n",
+ "activated via the Modes menu (in Motif, this is a submenu\n",
+ "of the Options menu). The default mode at startup can be\n",
+ "customized via the X resource `mouseMode' or the command-line\n",
+ "option `-mousemode'. The default startup mode is Magnifier Mode.\n",
+ "\n",
+ "Note: The modes are activated by changing the magnifier()\n",
+ "action. Switching the mode will not work if Mouse-1 has\n",
+ "been customized to an action sequence that does not contain\n",
+ "the magnifier() action.\n",
+ "\n",
+ "Magnifier Mode\n",
+ "\n",
+ " In this mode, the mouse buttons 1 to 5 will pop up a\n",
+ " ``magnifying glass'' that shows an unshrunken image of\n",
+ " the page (i.e. an image at the resolution determined by\n",
+ " the option/X resource pixels or mfmode) at varying sizes.\n",
+ " When the magnifier is moved, small ruler-like tick marks\n",
+ " are displayed at the edges of the magnifier (unless\n",
+ " the X resource delayRulers is set to false, in which case\n",
+ " the tick marks are always displayed).\n",
+ "\n",
+ " The unit of the marks is determined by the X resource\n",
+ " `tickUnits' (mm by default). This unit can be changed at\n",
+ " runtime via the action `switch-magnifier-units()', by\n",
+ " default bound to the keystroke `t' (see the description\n",
+ " of that key, and of `switch-magnifier-units()' for more\n",
+ " details on the units available). The length of the tick\n",
+ " marks can be changed via the X resource `tickLength'\n",
+ " (4 by default). A zero or negative value suppresses the\n",
+ " tick marks.\n",
+ "\n",
+ "\n",
+ "Text Selection Mode\n",
+ "\n",
+ " This mode allows you to select a rectangular region of\n",
+ " text in the DVI file by holding down Mouse-1 and moving\n",
+ " the mouse. The text is put into the X primary selection\n",
+ " so that it can be pasted into other X applications with\n",
+ " Mouse-2.\n",
+ "\n",
+ " If xdvi has been compiled with locale, nl_langinfo() and\n",
+ " iconv support, the selected text is converted into the\n",
+ " character set of the current locale (see the output of\n",
+ " `locale -a' for a list of locale settings available on\n",
+ " your system). If nl_langinfo() is not available, but\n",
+ " iconv is, you can specify the input encoding for iconv\n",
+ " via the X resource `textEncoding' (see the output of\n",
+ " `iconv -l' for a list of valid encodings). If iconv support\n",
+ " is not available, only the encodings ISO-8859-1 and UTF-8\n",
+ " are supported (these names are case-insensitive).\n",
+ "\n",
+ " Note that UTF-8 is the only encoding that can render all\n",
+ " characters (e.g. mathematical symbols). If ISO-8859-1 is\n",
+ " active, characters that cannot be displayed are replaced\n",
+ " by `\' followed by the hexadecimal character code. If a\n",
+ " character is not recognized at all, it is replaced by\n",
+ " `?'. For other encodings, such characters may trigger\n",
+ " iconv error messages.\n",
+ "\n",
+ " If you want to extract larger portions of text, you\n",
+ " can also save selected pages or the entire file in\n",
+ " text format from the `File > Save as ...' menu.\n",
+ "\n",
+ "\n",
+ "Ruler Mode\n",
+ "\n",
+ " This mode provides a simple way of measuring distances\n",
+ " on the page. When this mode is activated, the mouse\n",
+ " cursor changes into a thin cross, and a larger, cross-\n",
+ " shaped ruler is drawn in the highlight color at the\n",
+ " mouse location. The ruler doesn't have units attached\n",
+ " to it; instead, the current distance between the ruler\n",
+ " and the mouse cursor is continously printed to the\n",
+ " statusline.\n",
+ "\n",
+ " When activating Ruler Mode, the ruler is at first\n",
+ " attached to the mouse and can be moved around. It can\n",
+ " then be positioned at a fixed place by clicking Mouse-1.\n",
+ " After that, the mouse cursor can be moved to measure the\n",
+ " horizontal (dx), vertical (dy) and direct (shortest)\n",
+ " (dr) distance between the ruler center point and the\n",
+ " mouse.\n",
+ "\n",
+ " Clicking Mouse-1 again will move the ruler to the\n",
+ " current mouse position, and holding down Mouse-1 will\n",
+ " drag the ruler around.\n",
+ "\n",
+ " In Ruler Mode, the following special keybindings extend\n",
+ " or replace the default bindings:\n",
+ "\n",
+ " o [ruler-snap-origin()] Snap the ruler back to\n",
+ " the origin coordinate (0,0).\n",
+ "\n",
+ " t [overrides switch-magnifier-units()] Toggle\n",
+ " between various ruler units, which can be\n",
+ " specified by the X resource tickUnits (`mm'\n",
+ " by default).\n",
+ "\n",
+ " P [overrides declare-page-number()] Print the\n",
+ " distances shown in the statusline to standard\n",
+ " output.\n",
+ NULL
+ };
+
+ static const char *default_help_search[] = {
+ "String Search\tSearching for strings in the DVI file\n",
+ "The keystroke Ctrl-f or the menu entry File->Find ...\n",
+ "opens a dialog window to search for a text string or a\n",
+ "regular expression in the DVI file. The keystroke Ctrl-g\n",
+ "jumps to the next match.\n",
+#ifdef MOTIF
+ "(With Motif, you can also click on the `Binoculars' symbol\n",
+ "in the toolbar.)\n",
+#endif
+ "\n",
+#if HAVE_ICONV_H
+#if USE_LANGINFO
+ "The search term is converted from the character set specified\n",
+ "by the current locale into UTF-8. (See the output of `locale -a'\n",
+ "for a list of locale settings available on your system).\n",
+#else /* USE_LANGINFO */
+ "Since langinfo() support is not available on this platform,\n",
+ "the character set of the search string should be specified\n",
+ "via the X resource/command-line option textEncoding if the\n",
+ "encoding is different from iso_8859-1.\n",
+#endif /* USE_LANGINFO */
+#else /* HAVE_ICONV_H */
+ "Since iconv() support is not available on this platform,\n",
+ "the search term should be a string in the encoding specified\n",
+ "by the X resource/command-line option textEncoding;\n",
+ "currently, only the values iso_8859-1 and utf-8 are suported.\n",
+#endif
+ "Internally, the text in the DVI file is represented in\n",
+ "UTF-8 encoding (you can view the text by saving the DVI\n",
+ "file to a text file in UTF-8 encoding via the `File -> Save As ...'\n",
+ "dialog).\n",
+ "\n",
+ "Ideographic characters from CJKV fonts are treated specially:\n",
+ "All white space (spaces and newlines) before and after such\n",
+ "characters is ignored in the search string and in the DVI file.\n",
+ "\n",
+ "To match a newline character, use `\\n' in the search string;\n",
+ "to match the string `\\n', use `\\\\n'.\n",
+ "\n",
+ "If the checkbox Regular Expression is activated, the\n",
+ "string is teated as a regular expression in extended POSIX\n",
+ "format, with the following properties:\n",
+ "\n",
+ " a? matches a zero or one times\n",
+ "\n",
+ " a* matches a zero or more times\n",
+ "\n",
+ " a+ matches a one or more times. Note that * and + are\n",
+ " greedy, i.e. they match the longest possible\n",
+ " sub string.\n",
+ "\n",
+ " a{n} matches a exactly n times\n",
+ "\n",
+ " a{n,m} matches a at least n and no more than m times\n",
+ "\n",
+ " a|b matches a or b. Brackets can be used for grouping,\n",
+ " e.g.: (a|b)|c.\n",
+ "\n",
+ " The string matched by the nth group can be referenced\n",
+ " by \\n, e.g. \\1 refers to the first match.\n",
+ "\n",
+ " The characters ^ and $ match the beginning and the end\n",
+ " of a line, respectively.\n",
+ "\n",
+ " [abc] matches any of the letters a, b, c, and [a-z]\n",
+ " matches all characters from a to z.\n",
+ "\n",
+ " The patterns . and [...] without an explicit newline\n",
+ " don't match a newline character.\n",
+ "\n",
+ " Each item in a regular expression can also be one of\n",
+ " the following POSIX character classes:\n",
+ " [[:alnum:]] [[:alpha:]] [[:blank:]] [[:cntrl:]] [[:digit:]]\n",
+ " [[:graph:]] [[:lower:]] [[:print:]] [[:space:]] [[:upper:]]\n",
+ "\n",
+ " These can be negated by inserting a ^ symbol after the\n",
+ " first bracket: [^[:alpha:]]\n",
+ "\n",
+ " For more details on POSIX regular expressions, see\n",
+ " e.g. the IEEE Std 1003.1 available online from:\n",
+ "\n",
+ " http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap09.html\n",
+ "\n",
+ " As a non-standard extension, the following Perl-like\n",
+ " abbreviations can be used instead of the POSIX classes:\n",
+ "\n",
+ "\n",
+ " Symbol Meaning POSIX Class\n",
+ "\n",
+ " \\w an alphanumeric character [[:alnum:]]\n",
+ " \\W a non-alphanumeric character [^[:alnum:]]\n",
+ " \\d a digit character [[:digit:]]\n",
+ " \\D a non-digit character [^[:digit:]]\n",
+ " \\s a whitespace character [[:space:]]\n",
+ " \\S a non-whitespace character [^[:space:]]\n",
+ "\n",
+ " The following characters are special symbols; they\n",
+ " need to be escaped with \\ in order to match them\n",
+ " literally: ( ) [ ] . * ? + ^ $ \\.\n",
+ "\n",
+ "The dialog also provides checkboxes to search backwards,\n",
+ "to match in a case-sensitive manner (the default is to\n",
+ "ignore case, i.e. a search string Test will match both\n",
+ "the strings test and TEST in the DVI file) and to ignore\n",
+ "newlines and hyphens in the DVI file.\n",
+ "\n",
+ NULL
+ };
+
+ k = width = 0;
+
+ init_item(resource.help_general, default_help_general, info, k++, &width);
+ init_item(resource.help_pagemotion, default_help_pagemotion, info, k++, &width);
+ init_item(resource.help_othercommands, default_help_othercommands, info, k++, &width);
+ init_item(resource.help_hypertex, default_help_hypertex, info, k++, &width);
+ init_item(resource.help_mousebuttons, default_help_mousebuttons, info, k++, &width);
+ init_item(resource.help_modes, default_help_modes, info, k++, &width);
+ init_item(resource.help_search, default_help_search, info, k++, &width);
+ init_item(resource.help_pagemotion, default_help_marking, info, k++, &width);
+ init_item(resource.help_sourcespecials, default_help_sourcespecials, info, k++, &width);
+
+ ASSERT(k < NUM_HELP_TOPICS, "Too many elements in help topics!");
+
+ /* NULL-terminate items info */
+ info->items[k].widget = 0;
+ info->items[k].topic = info->items[k].title = NULL;
+
+ /* adjust width of topics label to longest text */
+#if !MOTIF
+ XtVaSetValues(info->topic_label, XtNwidth, width, NULL);
+#endif
+}
+
+
+
+/*
+ * Pops up the help window. If topic != NULL, also selects the topic.
+ */
+void
+show_help(Widget toplevel, const char *topic)
+{
+ size_t i;
+ static Widget help_shell = 0;
+ static struct topic_info info;
+ static struct topic_item items[NUM_HELP_TOPICS];
+ static Boolean first_time = True;
+
+ if (help_shell == 0) { /* called 1st time; create widget */
+
+ /* no special callbacks for OK/Cancel buttons */
+ info.ok_callback = NULL;
+ info.cancel_callback = NULL;
+ info.items = items;
+/* info.items_size = NUM_HELP_TOPICS; */
+
+ help_shell = create_topic_window(toplevel,
+ "xdvik: Help",
+ "help_window",
+ &info,
+ initialize_items,
+ "Close",
+ /* no Cancel button needed */
+ NULL);
+ info.shell = help_shell;
+
+ center_window(help_shell, globals.widgets.top_level);
+ }
+
+#if MOTIF
+ { /* check if resources are set properly */
+ Dimension w, h;
+ XtVaGetValues(help_shell, XtNwidth, &w, XtNheight, &h, NULL);
+ if (h < 200 || w < 400) {
+ XDVI_WARNING((stderr, "Initial help window size too small (%dx%d); overriding size.\n"
+ "Please check/update your application defaults file, and set both of\n"
+ "`XDvi*help_text.rows' and `XDvi*help_text.columns' to a realistic value.",
+ h, w));
+ XtVaSetValues(help_shell, XtNwidth, 620, XtNheight, 520, NULL);
+ }
+ }
+#endif
+ XtPopup(help_shell, XtGrabNone);
+
+ if (topic != NULL) {
+ Boolean matched = False;
+ for (i = 0; info.items[i].topic != NULL; i++) {
+ if (strcmp(info.items[i].topic, topic) == 0) { /* match */
+ select_topic(&info, i);
+ matched = True;
+ }
+ }
+ if (!matched) {
+ XBell(DISP, 0);
+ popup_message(help_shell,
+ MSG_WARN,
+ NULL,
+ "Shouldn't happen: Could not find topic `%s' in help list!\n"
+ REPORT_XDVI_BUG_TEMPLATE,
+ topic);
+ }
+ }
+ else if (first_time) {
+ first_time = False;
+ select_topic(&info, 0);
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/help-window.h b/Build/source/texk/xdvik/gui/help-window.h
new file mode 100644
index 00000000000..5464756395f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/help-window.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef HELP_WINDOW_H_
+#define HELP_WINDOW_H_
+
+extern void show_help(Widget parent, const char *topic);
+
+#endif /* HELP_WINDOW_H_ */
diff --git a/Build/source/texk/xdvik/gui/mag.c b/Build/source/texk/xdvik/gui/mag.c
new file mode 100644
index 00000000000..1df6cd92cab
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/mag.c
@@ -0,0 +1,861 @@
+/*
+ * 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 in
+ * xdvi.c.
+ *
+ */
+
+/*
+ * Implementation of the magnifier window.
+ */
+
+#include <math.h>
+
+#include "xdvi-config.h"
+/* one of the following should define OPEN_MAX: */
+#include <limits.h>
+#include "c-openmx.h"
+
+#include "xdvi.h"
+
+#ifdef MOTIF
+#include <Xm/Xm.h>
+#endif
+
+#include "events.h"
+#include "dvi-draw.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "hypertex.h"
+#include "mag.h"
+#include "xm_toolbar.h"
+#include "xm_menu.h" /* for get_last_ungrab() */
+#include "util.h"
+#include "pagesel.h"
+
+/* to measure distance of pointer from ruler in ruler mode */
+static int g_ruler_pos_x = 0, g_ruler_pos_y = 0;
+
+struct WindowRec magnifier = { (Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0 };
+
+/*
+ * Mechanism to keep track of the magnifier window. The problems are,
+ *
+ * - if the button is released while the window is being drawn, this could
+ * cause an X error if we continue drawing in it after it is destroyed, and
+ *
+ * - creating and destroying the window too quickly confuses the window
+ * manager, which is avoided by waiting for an expose event before destroying
+ * it.
+ */
+
+short magnifier_stat; /* 1 = wait for expose, -1 = destroy upon expose */
+
+static Position main_x;
+static Position main_y;
+
+static Position mag_x = 0;
+static Position mag_y = 0;
+
+/* Under Motif the following two remain always constant */
+static int mag_conv_x = 0;
+static int mag_conv_y = 0;
+
+static Position new_mag_x = 0;
+static Position new_mag_y = 0;
+
+static void
+can_exposures(struct WindowRec *windowrec)
+{
+ windowrec->min_x = windowrec->min_y = MAXDIM;
+ windowrec->max_x = windowrec->max_y = 0;
+}
+
+static void
+mag_motion(XEvent * event)
+{
+ MYTRACE((stderr, "mag_motion!\n"));
+ new_mag_x = event->xmotion.x + mag_conv_x;
+ main_x = event->xmotion.x_root - new_mag_x;
+ new_mag_y = event->xmotion.y + mag_conv_y;
+ main_y = event->xmotion.y_root - new_mag_y;
+
+ if (new_mag_x != mag_x || new_mag_y != mag_y)
+ globals.ev.flags |= EV_MAG_MOVE;
+ else
+ globals.ev.flags &= ~EV_MAG_MOVE;
+}
+
+void
+mag_release(XEvent * event)
+{
+ UNUSED(event);
+ if (magnifier.win != (Window) 0) {
+ if (magnifier_stat) {
+ magnifier_stat = -1; /* destroy upon expose */
+ }
+ else {
+ XDestroyWindow(DISP, magnifier.win);
+ if (drawing_mag) {
+ globals.ev.flags |= EV_MAG_GONE;
+ }
+ magnifier.win = (Window) 0;
+ mouse_motion = mouse_release = null_mouse;
+ globals.ev.flags &= ~EV_MAG_MOVE;
+ globals.cursor.flags &= ~CURSOR_MAG;
+ globals.ev.flags |= EV_CURSOR;
+ can_exposures(&magnifier);
+ /*
+ Workaround for bug #703304:
+ For obscure reasons, XFree 3.3.5 (and apparently also Solaris 8)
+ doesn't generate an expose event after the magnifier has beed
+ destroyed. But only a redraw() event caused by expose would reset
+ currwin.win back to mane.win, which is needed e.g. for getting the
+ hyperlink info updated (otherwise, the mouse will not become active
+ over a hyperlink).
+
+ Forcing a redraw with
+ redraw(&mane);
+ may cause a `BadDrawable' X error with color material (e.g. from #702288),
+ or a `draw_part: shouldn't happen: POST encountered' error. Neither do
+ the following work:
+ globals.ev.flags |= EV_EXPOSE; (doesn't fix the bug)
+ draw_page(); (same effect as redraw(&mane))
+ globals.ev.flags |= EV_NEWPAGE; (works, but is crude and causes flicker)
+
+ So I decided to use expose() for the time being, which
+ sets mane.min_x to the current x point (which doesn't happen
+ with EV_EXPOSE; this causes the test for `mane.min_x < MAXDIM'
+ to fail in events.c; look for `see comment in mag.c').
+ */
+/* fprintf(stderr, "========triggering expose!\n"); */
+ expose(&mane, event->xbutton.x_root, event->xbutton.y_root, 10, 10);
+ }
+ }
+}
+
+static int
+tick_scale(int k)
+{
+ if (k == 0)
+ return 3;
+ else if ((k % 1000) == 0)
+ return 7;
+ else if ((k % 500) == 0)
+ return 6;
+ else if ((k % 100) == 0)
+ return 5;
+ else if ((k % 50) == 0)
+ return 4;
+ else if ((k % 10) == 0)
+ return 3;
+ else if ((k % 5) == 0)
+ return 2;
+ else
+ return 1;
+}
+
+static void
+draw_ticks(unsigned int width, unsigned int height, GC ourGC)
+{
+ int k; /* tick counter */
+ double old_pixels_per_tick;
+ double pixels_per_tick;
+ int scale;
+ int tick_offset; /* offset along axes */
+ int x; /* coordinates of top-left popup */
+ int y; /* window corner */
+ double xx; /* coordinates of tick */
+ double yy; /* coordinates of tick */
+ static char *last_tick_units = ""; /* memory of last tick units */
+
+ if (resource.tick_length <= 0) /* user doesn't want tick marks */
+ return;
+
+ x = 0; /* the pop-up window always has origin (0,0) */
+ y = 0;
+
+ /* We need to clear the existing window to remove old rulers. I think
+ that this could be avoided if draw_ticks() could be invoked earlier.
+ The expose argument in XClearArea() must be True to force redrawing
+ of the text inside the popup window. Also, it would be better to draw
+ the rulers before painting the text, so that rulers would not
+ overwrite the text, but I haven't figured out yet how to arrange
+ that. */
+
+ XClearArea(DISP, magnifier.win, x, y, width, height, True);
+
+ /* The global resource.pixels_per_inch tells us how to find the ruler
+ scale. For example, 300dpi corresponds to these TeX units:
+
+ 1 TeX point (pt) = 4.151 pixels
+ 1 big point (bp) = 4.167 pixels
+ 1 pica (pc) = 49.813 pixels
+ 1 cicero (cc) = 53.501 pixels
+ 1 didot point (dd) = 4.442 pixels
+ 1 millimeter (mm) = 11.811 pixels
+ 1 centimeter (cm) = 118.110 pixels
+ 1 inch (in) = 300.000 pixels
+ 1 scaled point (sp) = 0.00006334 pixels
+
+ The user can select the units via a resource (e.g. XDvi*tickUnits: bp),
+ or a command-line option (e.g. -xrm '*tickUnits: cm'). The length of
+ the ticks can be controlled by a resource (e.g. XDvi*tickLength: 10), or
+ a command-line option (e.g. -xrm '*tickLength: 10000'). If the tick
+ length exceeds the popup window size, then a graph-paper grid is drawn
+ over the whole window. Zero, or negative, tick length completely
+ suppresses rulers. */
+
+ pixels_per_tick = (double)resource.pixels_per_inch;
+ if (strcmp(resource.tick_units, "pt") == 0)
+ pixels_per_tick /= 72.27;
+ else if (strcmp(resource.tick_units, "bp") == 0)
+ pixels_per_tick /= 72.0;
+ else if (strcmp(resource.tick_units, "in") == 0)
+ /* NO-OP */ ;
+ else if (strcmp(resource.tick_units, "cm") == 0)
+ pixels_per_tick /= 2.54;
+ else if (strcmp(resource.tick_units, "mm") == 0)
+ pixels_per_tick /= 25.4;
+ else if (strcmp(resource.tick_units, "dd") == 0)
+ pixels_per_tick *= (1238.0 / 1157.0) / 72.27;
+ else if (strcmp(resource.tick_units, "cc") == 0)
+ pixels_per_tick *= 12.0 * (1238.0 / 1157.0) / 72.27;
+ else if (strcmp(resource.tick_units, "pc") == 0)
+ pixels_per_tick *= 12.0 / 72.27;
+ else if (strcmp(resource.tick_units, "sp") == 0)
+ pixels_per_tick /= (65536.0 * 72.27);
+ else if (strcmp(resource.tick_units, "px") == 0)
+ pixels_per_tick = 10;
+ else {
+ XDVI_WARNING((stderr, "Unrecognized tickUnits [%s]: defaulting to TeX points [pt]",
+ resource.tick_units));
+ resource.tick_units = "pt";
+ pixels_per_tick /= 72.27;
+ }
+
+ /* To permit accurate measurement in the popup window, we can reasonably
+ * place tick marks about 3 to 10 pixels apart, so we scale the computed
+ * pixels_per_tick by a power of ten to bring it into that range.
+ */
+
+ old_pixels_per_tick = pixels_per_tick; /* remember the original scale */
+ while (pixels_per_tick < 3.0)
+ pixels_per_tick *= 10.0;
+ while (pixels_per_tick > 30.0)
+ pixels_per_tick /= 10.0;
+
+ /* tell user what the ruler scale is, but only when it changes */
+ if (strcmp(last_tick_units, resource.tick_units) != 0) {
+ if (old_pixels_per_tick != pixels_per_tick)
+ printf("Ruler tick interval adjusted to represent %.2f%s\n",
+ pixels_per_tick / old_pixels_per_tick, resource.tick_units);
+ else if (globals.debug & DBG_EVENT)
+ printf("Ruler tick interval represents 1%s\n", resource.tick_units);
+ }
+
+ /* In order to make the ruler as accurate as possible, given the coarse
+ * screen resolution, we compute tick positions in floating-point
+ * arithmetic, then round to nearest integer values.
+ */
+
+ /* draw vertical ticks on top and bottom */
+ for (k = 0, xx = 0.0; xx < (double)width; k++, xx += pixels_per_tick) {
+ tick_offset = (int)(0.5 + xx); /* round to nearest pixel */
+ scale = tick_scale(k);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x + tick_offset, y, x + tick_offset, y + scale * resource.tick_length);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x + tick_offset, y + height,
+ x + tick_offset, y + height - scale * resource.tick_length);
+ }
+
+ /* draw horizontal ticks on left and right */
+ for (k = 0, yy = 0.0; yy < (double)height; k++, yy += pixels_per_tick) {
+ tick_offset = (int)(0.5 + yy); /* round to nearest pixel */
+ scale = tick_scale(k);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x, y + tick_offset, x + scale * resource.tick_length, y + tick_offset);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x + width, y + tick_offset,
+ x + width - scale * resource.tick_length, y + tick_offset);
+ }
+
+ last_tick_units = resource.tick_units;
+
+ XFlush(DISP); /* bring window up-to-date */
+}
+
+static void
+compute_mag_pos(int *xp, int *yp)
+{
+ int t;
+
+ t = mag_x + main_x - magnifier.width / 2;
+ if (t > WidthOfScreen(SCRN) - (int)magnifier.width - 2 * MAGBORD)
+ t = WidthOfScreen(SCRN) - (int)magnifier.width - 2 * MAGBORD;
+ if (t < 0)
+ t = 0;
+ *xp = t;
+ t = mag_y + main_y - magnifier.height / 2;
+ if (t > HeightOfScreen(SCRN) - (int)magnifier.height - 2 * MAGBORD)
+ t = HeightOfScreen(SCRN) - (int)magnifier.height - 2 * MAGBORD;
+ if (t < 0)
+ t = 0;
+ *yp = t;
+}
+
+static void
+scroll_window(struct WindowRec *windowrec, int x0, int y0)
+{
+ int x, y;
+ int x2 = 0, y2 = 0;
+ int ww, hh;
+
+ x = x0 - windowrec->base_x;
+ y = y0 - windowrec->base_y;
+ ww = windowrec->width - x;
+ hh = windowrec->height - y;
+ windowrec->base_x = x0;
+ windowrec->base_y = y0;
+ if (currwin.win == windowrec->win) {
+ currwin.base_x = x0;
+ currwin.base_y = y0;
+ }
+ windowrec->min_x -= x;
+ if (windowrec->min_x < 0)
+ windowrec->min_x = 0;
+ windowrec->max_x -= x;
+ if ((unsigned int)windowrec->max_x > windowrec->width)
+ windowrec->max_x = windowrec->width;
+ windowrec->min_y -= y;
+ if (windowrec->min_y < 0)
+ windowrec->min_y = 0;
+ windowrec->max_y -= y;
+ if ((unsigned int)windowrec->max_y > windowrec->height)
+ windowrec->max_y = windowrec->height;
+ if (x < 0) {
+ x2 = -x;
+ x = 0;
+ ww = windowrec->width - x2;
+ }
+ if (y < 0) {
+ y2 = -y;
+ y = 0;
+ hh = windowrec->height - y2;
+ }
+ if (ww <= 0 || hh <= 0) {
+ XClearWindow(DISP, windowrec->win);
+ windowrec->min_x = windowrec->min_y = 0;
+ windowrec->max_x = windowrec->width;
+ windowrec->max_y = windowrec->height;
+ }
+ else {
+ XCopyArea(DISP, windowrec->win, windowrec->win, globals.gc.copy,
+ x, y, (unsigned int)ww, (unsigned int)hh, x2, y2);
+ if (x > 0)
+ clearexpose(windowrec, ww, 0, (unsigned int)x, windowrec->height);
+ if (x2 > 0)
+ clearexpose(windowrec, 0, 0, (unsigned int)x2, windowrec->height);
+ if (y > 0)
+ clearexpose(windowrec, 0, hh, windowrec->width, (unsigned int)y);
+ if (y2 > 0)
+ clearexpose(windowrec, 0, 0, windowrec->width, (unsigned int)y2);
+ }
+}
+
+static void
+do_movemag(int x, int y)
+{
+ int xx, yy;
+
+ mag_x = x;
+ mag_y = y;
+ if (mag_x == new_mag_x && mag_y == new_mag_y)
+ globals.ev.flags &= ~EV_MAG_MOVE;
+ compute_mag_pos(&xx, &yy);
+ XMoveWindow(DISP, magnifier.win, xx, yy);
+ scroll_window(&magnifier,
+ (x + mane_base_x) * mane.shrinkfactor - (int)magnifier.width / 2,
+ (y + mane_base_y) * mane.shrinkfactor - (int)magnifier.height / 2);
+ draw_ticks(magnifier.width, magnifier.height, globals.gc.ruler);
+}
+
+extern jmp_buf next_env;
+
+void
+show_distance_from_ruler(XEvent *event, Boolean to_stdout)
+{
+ int loc_x, loc_y;
+ int precision = 2;
+ double factor;
+
+ if (event == NULL) /* when option is toggled */
+ return;
+
+ loc_x = event->xbutton.x;
+ loc_y = event->xbutton.y;
+ if (event->xbutton.window != mane.win) {
+ Window ww;
+ (void)XTranslateCoordinates(DISP,
+ RootWindowOfScreen(SCRN), mane.win,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ &loc_x,
+ &loc_y,
+ &ww); /* throw away last argument */
+ }
+
+ /* map everything below 0 to the origin */
+ if (loc_x < 0)
+ loc_x = 0;
+ if (loc_y < 0)
+ loc_y = 0;
+
+ if (strcmp(resource.tick_units, "pt") == 0) {
+ factor = 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "bp") == 0) {
+ factor = 72.0 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "in") == 0) {
+ factor = currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "cm") == 0) {
+ factor = 2.54 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ precision = 3;
+ }
+ else if (strcmp(resource.tick_units, "mm") == 0) {
+ factor = 25.4 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "dd") == 0) {
+ factor = 72.27 / (1238.0 / 1157.0) * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "cc") == 0) {
+ factor = 72.27 / (12.0 * (1238.0 / 1157.0)) * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "pc") == 0) {
+ factor = 72.27 / 12.0 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "sp") == 0) {
+ factor = 65536.0 * 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ precision = 1;
+ }
+ else if (strcmp(resource.tick_units, "px") == 0) { /* pixel units */
+ factor = 1;
+ }
+ else {
+ XDVI_WARNING((stderr, "Unrecognized tickUnits [%s]: defaulting to TeX points [pt]",
+ resource.tick_units));
+ resource.tick_units = "pt";
+ factor = 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+
+ if (mouse_release != null_mouse) {
+ if (to_stdout) {
+ XDVI_INFO((stdout, "Ruler/Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
+ loc_x, loc_y,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units));
+ }
+ else {
+ statusline_print(STATUS_FOREVER,
+ "Ruler/Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dt: %.*f %s",
+ loc_x, loc_y,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units);
+ }
+ }
+ else {
+ int d_x = loc_x - g_ruler_pos_x;
+ int d_y = loc_y - g_ruler_pos_y;
+ double d_z = sqrt((double)d_x * d_x + (double)d_y * d_y);
+ double unit_x = (double)d_x * factor;
+ double unit_y = (double)d_y * factor;
+ double unit_z = d_z * factor;
+ if (to_stdout) {
+ XDVI_INFO((stdout, "Ruler: %d,%d, Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
+ g_ruler_pos_x, g_ruler_pos_y, loc_x, loc_y,
+ precision, unit_x, resource.tick_units,
+ precision, unit_y, resource.tick_units,
+ precision, unit_z, resource.tick_units));
+ }
+ else {
+ statusline_print(STATUS_FOREVER,
+ "Ruler: %d,%d, Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
+ g_ruler_pos_x, g_ruler_pos_y, loc_x, loc_y,
+ precision, unit_x, resource.tick_units,
+ precision, unit_y, resource.tick_units,
+ precision, unit_z, resource.tick_units);
+ }
+ }
+}
+
+void
+move_magnifier(void)
+{
+ if (magnifier.win == (Window) 0)
+ globals.ev.flags &= ~EV_MAG_MOVE;
+ else if (abs(new_mag_x - mag_x) > 2 * abs(new_mag_y - mag_y))
+ do_movemag(new_mag_x, mag_y);
+ else if (abs(new_mag_y - mag_y) > 2 * abs(new_mag_x - mag_x))
+ do_movemag(mag_x, new_mag_y);
+ else
+ do_movemag(new_mag_x, new_mag_y);
+}
+
+static void
+Act_href(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int x, y;
+ Window dummy;
+
+ UNUSED(w);
+ UNUSED(num_params);
+ UNUSED(params);
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE)
+ return;
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &x, &y, &dummy);
+ if (htex_handleref(x, y, False)) {
+ block_next_mouse_event();
+ }
+}
+
+static void
+Act_href_newwindow(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int x, y;
+ Window dummy;
+
+ UNUSED(w);
+ UNUSED(num_params);
+ UNUSED(params);
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE)
+ return;
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &x, &y, &dummy);
+ if (htex_handleref(x, y, True)) {
+ block_next_mouse_event();
+ }
+}
+
+void
+clear_ruler(void)
+{
+ /* maybe we should do this only for mouse-1? */
+ clearexpose(&mane, 0, g_ruler_pos_y,
+ ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2, 1);
+ clearexpose(&mane, g_ruler_pos_x, 0,
+ 1, ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2);
+}
+
+void
+show_ruler(XEvent *event)
+{
+ if (mouse_release == null_mouse) {
+ if (mouse_release != null_mouse && mouse_release != drag_ruler_release)
+ return;
+ if (mouse_release == null_mouse) {
+ mouse_motion = drag_ruler_motion;
+ mouse_release = drag_ruler_release;
+ }
+ drag_ruler_motion(event);
+ }
+}
+
+static void
+draw_ruler(int x, int y)
+{
+ /* don't draw if outside page region (will be clipped automatically by Motif,
+ but not by Xaw, where draw widget is entire window) */
+ if (x > (int)ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 1
+ || y > (int)ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 1)
+ return;
+
+ XFillRectangle(DISP, mane.win, globals.gc.high,
+ 0, y,
+ ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2, 1);
+ XFillRectangle(DISP, mane.win, globals.gc.high,
+ x, 0,
+ 1, ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2);
+}
+
+
+/* snap ruler back to origing (0,0) */
+void
+ruler_snap_origin(XEvent *event)
+{
+ clear_ruler();
+ g_ruler_pos_x = g_ruler_pos_y = 0;
+ draw_ruler(g_ruler_pos_x, g_ruler_pos_y);
+ /* deactivate mouse dragging */
+ mouse_motion = mouse_release = null_mouse;
+ show_distance_from_ruler(event, False);
+}
+
+void
+redraw_ruler(void)
+{
+ draw_ruler(g_ruler_pos_x, g_ruler_pos_y);
+}
+
+void
+drag_ruler_motion(XEvent *event)
+{
+ int loc_x, loc_y;
+ if (event == NULL) { /* toggled via menu */
+ /* hack to avoid redrawing ruler at last g_* positions when mode is
+ toggled on via menu, then off via keystroke */
+ g_ruler_pos_x = g_ruler_pos_y = 0;
+ return;
+ }
+
+ loc_x = event->xbutton.x;
+ loc_y = event->xbutton.y;
+
+ if (event->xbutton.window != mane.win) {
+ Window dummy;
+ (void)XTranslateCoordinates(DISP,
+ RootWindowOfScreen(SCRN), mane.win,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ &loc_x,
+ &loc_y,
+ &dummy);
+ }
+
+ /* map everything below 0 to the origin */
+ if (loc_x < 0)
+ loc_x = 0;
+ if (loc_y < 0)
+ loc_y = 0;
+
+ clear_ruler();
+ draw_ruler(loc_x, loc_y);
+ g_ruler_pos_x = loc_x;
+ g_ruler_pos_y = loc_y;
+}
+
+void
+drag_ruler_release(XEvent *event)
+{
+ UNUSED(event);
+ mouse_motion = mouse_release = null_mouse;
+}
+
+/****************************************************************************
+ * Actions specific to the handling of the magnifier
+ */
+
+static void
+Act_magnifier(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ const char *p;
+ int x, y;
+ XSetWindowAttributes attr;
+#ifndef MOTIF
+ Window throwaway;
+#endif
+ UNUSED(w);
+
+ MYTRACE((stderr, "magnifier!\n"));
+
+ if (block_this_mouse_event())
+ return;
+ else if (dvi_file_changed()) {
+ globals.ev.flags |= EV_RELOAD;
+ return;
+ }
+
+#ifdef MOTIF
+ /* see xm_menu.c for an explanation of this */
+ if (pulldown_menu_active(event->xany.serial)) {
+ return;
+ }
+#endif
+
+ if (bg_current == NULL) {
+ /*
+ HACK ALERT: we can arrive here after loading a new file via the file selector
+ for which not all fonts have been generated. In that case, dereferencing
+ bg_current would bomb. Try to recover by simply returning here.
+ */
+ return;
+ }
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE && event->xbutton.button == 1) {
+ show_ruler(event);
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.rule);
+ show_distance_from_ruler(event, False);
+ return;
+ }
+ else if (resource.mouse_mode == MOUSE_TEXT_MODE && event->xbutton.button == 1) {
+ text_selection_start(event);
+ text_motion(event);
+ return;
+ }
+
+ if (event->type != ButtonPress || mouse_release != null_mouse
+ || magnifier.win != (Window)0 || mane.shrinkfactor == 1 || *num_params != 1) {
+ XBell(DISP, 0);
+ if (mane.shrinkfactor == 1) {
+ statusline_print(STATUS_SHORT,
+ "No magnification available at shrink factor 1");
+ }
+ return;
+ }
+
+ p = *params;
+ if (*p == '*') {
+ int n = atoi(p + 1) - 1;
+
+ if (n < 0 || n >= (int)get_magglass_items() || get_magglass_width(n) <= 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ magnifier.width = get_magglass_width(n);
+ magnifier.height = get_magglass_height(n);
+ }
+ else {
+ magnifier.width = magnifier.height = atoi(p);
+ p = strchr(p, 'x');
+ if (p != NULL) {
+ magnifier.height = atoi(p + 1);
+ if (magnifier.height == 0)
+ magnifier.width = 0;
+ }
+ if (magnifier.width == 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ }
+#ifndef MOTIF
+ XTranslateCoordinates(DISP, event->xbutton.window, mane.win,
+ 0, 0, &mag_conv_x, &mag_conv_y, &throwaway);
+#endif
+
+ globals.cursor.flags |= CURSOR_MAG;
+ globals.ev.flags |= EV_CURSOR;
+
+ mag_x = event->xbutton.x + mag_conv_x;
+ mag_y = event->xbutton.y + mag_conv_y;
+ main_x = event->xbutton.x_root - mag_x;
+ main_y = event->xbutton.y_root - mag_y;
+ compute_mag_pos(&x, &y);
+ magnifier.base_x = (mag_x + mane_base_x) * mane.shrinkfactor - magnifier.width / 2;
+ magnifier.base_y = (mag_y + mane_base_y) * mane.shrinkfactor - magnifier.height / 2;
+ attr.save_under = True;
+ attr.border_pixel = resource.rule_pixel;
+#if COLOR
+ attr.background_pixel = bg_current->pixel;
+#else
+ attr.background_pixel = resource.back_Pixel;
+#endif
+ attr.override_redirect = True;
+#ifdef GREY
+ attr.colormap = G_colormap;
+#endif
+ magnifier.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
+ x, y, magnifier.width, magnifier.height, MAGBORD,
+ G_depth, InputOutput, G_visual,
+ CWSaveUnder | CWBorderPixel | CWBackPixel |
+#ifdef GREY
+ CWColormap |
+#endif
+ CWOverrideRedirect, &attr);
+ XSelectInput(DISP, magnifier.win, ExposureMask);
+ XMapWindow(DISP, magnifier.win);
+
+ /*
+ * This call will draw the point rulers when the magnifier first pops up,
+ * if the XDvi*delayRulers resource is false. Some users may prefer rulers
+ * to remain invisible until the magnifier is moved, so the default is
+ * true. Rulers can be suppressed entirely by setting the XDvi*tickLength
+ * resource to zero or negative.
+ */
+
+ if (!resource.delay_rulers)
+ draw_ticks(magnifier.width, magnifier.height, globals.gc.ruler);
+
+ magnifier_stat = 1; /* waiting for exposure */
+ mouse_motion = mag_motion;
+ mouse_release = mag_release;
+}
+
+static void
+Act_switch_magnifier_units(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ size_t k = 0;
+ static char *TeX_units[] = {
+ "mm", "pt", "in", "sp", "bp", "cc", "dd", "pc", "px",
+ };
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ for (k = 0; k < XtNumber(TeX_units); ++k)
+ if (strcmp(resource.tick_units, TeX_units[k]) == 0)
+ break;
+ k++;
+ if (k >= XtNumber(TeX_units))
+ k = 0;
+ resource.tick_units = TeX_units[k];
+ if (resource.mouse_mode != MOUSE_RULER_MODE) {
+ statusline_print(STATUS_SHORT, "Ruler units: %s\n", resource.tick_units);
+ }
+ else {
+ show_distance_from_ruler(event, False);
+ }
+}
+
+XtActionsRec mag_actions[] = {
+ {"magnifier", Act_magnifier},
+ {"do-href", Act_href},
+ {"do-href-newwindow", Act_href_newwindow},
+ {"switch-magnifier-units", Act_switch_magnifier_units},
+};
+
+/*
+ * This isn't creating the actual magnifier. It is created lazily on demand
+ * if one of the corresponding actions is taken. Therefore we are here
+ * just adding the record of actions related to magnifier handling to the
+ * application.
+ */
+
+void
+create_magnifier(void)
+{
+ XtAppAddActions(app, mag_actions, XtNumber(mag_actions));
+}
diff --git a/Build/source/texk/xdvik/gui/mag.h b/Build/source/texk/xdvik/gui/mag.h
new file mode 100644
index 00000000000..608019f3ac2
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/mag.h
@@ -0,0 +1,45 @@
+/*
+ * 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 in
+ * xdvi.c.
+ *
+ */
+
+#ifndef MAG_H_
+#define MAG_H_
+
+#define MAGBORD 1 /* border size for magnifier */
+
+extern void show_distance_from_ruler(XEvent *event, Boolean to_stdout);
+extern void drag_ruler_motion(XEvent *event);
+extern void drag_ruler_release(XEvent *event);
+extern void clear_ruler(void);
+extern void show_ruler(XEvent *event);
+extern void redraw_ruler(void);
+extern void ruler_snap_origin(XEvent *event);
+
+extern void mag_release(XEvent * event);
+extern void move_magnifier(void);
+extern void create_magnifier(void);
+
+#endif /* MAG_H_ */
+
diff --git a/Build/source/texk/xdvik/gui/menu.c b/Build/source/texk/xdvik/gui/menu.c
new file mode 100644
index 00000000000..575ef162f9b
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/menu.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Common code for Xaw and Motif menu bar creation.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "events.h"
+#include "menu.h"
+#include "util.h"
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+
+#ifdef MOTIF
+# include <Xm/RowColumn.h>
+# include <Xm/ToggleB.h>
+#else
+# include <X11/Intrinsic.h>
+# include <X11/Xatom.h>
+# include <X11/StringDefs.h>
+# include <X11/Xaw/Label.h>
+#endif
+
+
+/* translate string argument into corresponding buttonTypeT */
+static buttonTypeT
+get_type(const char *str)
+{
+ if (strcmp(str, "PUSH") == 0)
+ return BT_PUSH;
+ else if (strcmp(str, "RADIO") == 0)
+ return BT_RADIO;
+ else if (strcmp(str, "CHECK") == 0)
+ return BT_CHECK;
+ else if (strcmp(str, "SEP") == 0)
+ return BT_SEP;
+ else
+ return BT_INVALID;
+}
+
+static struct button_info *m_button_info = NULL; /* toplevel node of pulldown menu structure */
+
+
+static void
+set_menu_info(void *val, XtActionProc proc, Boolean (*cmp)(), struct button_info *item)
+{
+ size_t i;
+ ASSERT(item != NULL, "item in set_menu_info musn't be NULL!");
+ for (i = 0; i < item->size; i++) {
+ if ((item->elems[i].type == BT_RADIO || item->elems[i].type == BT_CHECK)
+ && item->elems[i].action != NULL
+ && item->elems[i].action->proc != NULL
+ && item->elems[i].action->proc == proc
+ && item->elems[i].action->param != NULL) {
+ Boolean on;
+ ASSERT(cmp != NULL, "comparison function musn't be NULL!");
+ on = cmp(val, item->elems[i].action->param);
+#ifdef MOTIF
+ ASSERT(item->elems[i].widget != 0, "Widget musn't be NULL!");
+ XmToggleButtonSetState(item->elems[i].widget, on, False);
+#else
+#ifdef NEW_MENU_CREATION
+ ASSERT(item->elems[i].widget != 0, "Widget musn't be NULL!");
+ xaw_set_button_state(item->elems + i, on);
+#else
+ static Arg args = { XtNleftBitmap, (XtArgVal) 0 };
+ if (on)
+ args.value = (XtArgVal) menu_check_bitmap;
+ else
+ args.value = (XtArgVal) menu_uncheck_bitmap;
+ XtSetValues(item->elems[i].widget, &args, 1);
+#endif /* NEW_MENU_CREATION */
+#endif
+ }
+ if (item->elems[i].submenu != NULL) { /* invoke it recursively */
+ set_menu_info(val, proc, cmp, item->elems[i].submenu);
+ }
+ }
+}
+
+
+/* set a menu according to val and the compare function cmp */
+void
+set_menu(void *val, XtActionProc proc, Boolean (*cmp)())
+{
+ /* non-standard cast function ptr -> void ptr */
+ /* TRACE_GUI((stderr, "set_menu_info: %d, %p, %p", *(int *)val, (void *)proc, (void *)cmp)); */
+ set_menu_info(val, proc, cmp, m_button_info);
+}
+
+static void
+initialize_menus(void)
+{
+ int use_gs;
+ int shrinkval;
+
+ /* initialize tickmarks for all possible actions */
+ use_gs = resource.postscript;
+#ifdef PS_GS
+ if (!resource.useGS)
+ use_gs = 0;
+#endif
+
+ set_menu(&use_gs, Act_set_ps, check_int);
+ set_menu(&resource.gs_alpha, Act_set_gs_alpha, check_toggle);
+ set_menu(&resource.keep_flag, Act_set_keep_flag, check_toggle);
+ shrinkval = resource.pixels_per_inch / mane.shrinkfactor;
+ set_menu(&shrinkval, Act_shrink_to_dpi, check_int);
+ set_menu(&mane.shrinkfactor, Act_set_shrink_factor, check_int);
+ set_menu(&resource.use_tex_pages, Act_use_tex_pages, check_toggle);
+ set_menu((char *)resource.paper, Act_set_paper_landscape, check_paper_landscape);
+ set_menu((char *)resource.paper, Act_set_papersize, check_papersize);
+ set_menu(&resource.mouse_mode, Act_switch_mode, check_int);
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+}
+
+static void
+free_items(char **items, size_t len)
+{
+ size_t curr = 0;
+ while(curr < len) {
+ free(items[curr++]);
+ }
+ free(items);
+}
+
+#if 0
+static void
+show_items(char *descr, char **items, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%s %d: |%s|\n", descr, i, items[i]);
+ }
+}
+#endif
+
+static void
+add_info(struct button_info **info, buttonTypeT bt_type,
+ char mnemonic, const char *title,
+ const char *accelerator, struct xdvi_action *action)
+{
+/* fprintf(stderr, "creating new item for info %p: |%s|\n", *info, title); */
+ size_t idx = (*info)->size++;
+ (*info)->elems = xrealloc((*info)->elems, (*info)->size * sizeof *((*info)->elems));
+ (*info)->elems[idx].title = xstrdup(title);
+ (*info)->elems[idx].type = bt_type;
+ if (accelerator == NULL || accelerator[0] == '\0')
+ (*info)->elems[idx].accelerator = NULL;
+ else
+ (*info)->elems[idx].accelerator = xstrdup(accelerator);
+ (*info)->elems[idx].mnemonic = mnemonic;
+ (*info)->elems[idx].action = action;
+ (*info)->elems[idx].widget = 0;
+ (*info)->elems[idx].submenu = NULL;
+}
+
+static void
+insert_items(struct button_info **info, char **items, size_t num_items,
+ const char *button_type, const char *accelerator, const char *action)
+{
+ const char ENTRY_SEP = '|';
+ size_t i = 0;
+ size_t entry_len;
+ size_t entry_count = 0;
+ char **entry_items = NULL;
+ size_t idx;
+
+ Boolean found = False;
+ Boolean have_error = False;
+
+/* fprintf(stderr, "------ insert_items called for |%s|, %p, |%s|\n", *items, *info, action); */
+
+ if (*items == NULL) {
+ /* should be a separator, which is treated as a special case since
+ there's no menu title: */
+ if (strcmp (button_type, "SEP") == 0)
+ add_info(info, BT_SEP, '\0', "SEP", NULL, NULL);
+ else
+ XDVI_WARNING((stderr, "Shouldn't happen: items == NULL!"));
+ return;
+ }
+
+ entry_len = strlen(items[0]);
+ entry_items = split_line(items[0], ENTRY_SEP, 0, entry_len, &entry_count);
+
+ if (entry_count < 2) {
+ XDVI_WARNING((stderr, "Missing Mnemonic in button info `%s'\n", items[0]));
+ entry_count++;
+ entry_items = xrealloc(entry_items, entry_count * sizeof *entry_items);
+ entry_items[1] = xstrdup("");
+ entry_items[2] = NULL;
+ }
+
+ for (i = 0; i < (*info)->size; i++) {
+ if (strcmp(entry_items[0], (*info)->elems[i].title) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ idx = i;
+
+ if (!found) { /* new item, resize info and add this item */
+ struct xdvi_action *my_action = NULL;
+ buttonTypeT my_type = BT_NONE;
+
+ /* if it's a `leaf' in the menu hierarchy, compile the action and set the button type */
+ if (num_items == 1) {
+/* fprintf(stderr, "button_type: |%s|\n", button_type); */
+
+ char *fmt = strchr(entry_items[0], '$');
+ if (fmt != NULL
+ && (fmt == entry_items[0] || (fmt > entry_items[0] && *(fmt - 1) != '\\'))
+ && (fmt[1] == '#' || fmt[1] == '%' ||fmt[1] == '_')) {
+ XDVI_WARNING((stderr, "Xdvik doesn't support format characters in button labels; "
+ "skipping button \"%s\"", items[0]));
+ have_error = True;
+ }
+
+ if (strlen(action) == 0
+ || (my_action = compile_action(action)) == NULL) {
+ XDVI_WARNING((stderr, "Invalid action \"%s\" for button \"%s\" (skipping this line).",
+ action, items[0]));
+ have_error = True;
+ }
+
+ if ((my_type = get_type(button_type)) == BT_INVALID) {
+ XDVI_WARNING((stderr, "Invalid type \"%s\" for button \"%s\" (skipping this line).",
+ button_type, items[0]));
+ have_error = True;
+ }
+ }
+
+ if (!have_error) {
+ add_info(info, my_type, entry_items[1][0], entry_items[0], accelerator, my_action);
+ }
+ }
+ free_items(entry_items, entry_count);
+
+ if (num_items > 1 || (num_items == 1 && strcmp(button_type, "SEP") == 0)) { /* not a leaf, invoke recursivly for next level */
+/* fprintf(stderr, "invoking recursively for %d, %p\n", idx, (*info)->elems[idx].submenu); */
+ if ((*info)->elems[idx].submenu == NULL) { /* submenu didn't exist yet, create it */
+ struct button_info *new_submenu = xmalloc(sizeof *new_submenu);
+ new_submenu->elems = NULL;
+ new_submenu->size = 0;
+ (*info)->elems[idx].submenu = new_submenu;
+ }
+ insert_items(&((*info)->elems[idx].submenu), items + 1, num_items - 1, button_type, accelerator, action);
+ }
+}
+
+static void
+show_button_info(int depth, struct button_info *info)
+{
+ size_t i;
+ for (i = 0; i < info->size; i++) {
+ TRACE_GUI((stderr, "%*c-->%s; type=%d; mnemonic=%c; accel=%s; submenu=%p; w=%lu; action: %p",
+ depth, ' ',
+ info->elems[i].title,
+ info->elems[i].type,
+ info->elems[i].mnemonic,
+ info->elems[i].accelerator ? info->elems[i].accelerator : "<NULL>",
+ (void *)info->elems[i].submenu,
+ (unsigned long)info->elems[i].widget,
+ (void *)info->elems[i].action));
+ if (info->elems[i].submenu != NULL) {
+ show_button_info(depth + 3, info->elems[i].submenu);
+ }
+ }
+}
+
+static void
+parse_button_translations(struct button_info **info)
+{
+ const char *curr_p, *end_p;
+
+ const char LINE_SEP = ':';
+ const char MENU_SEP = '>';
+
+ for (curr_p = resource.menu_translations;
+ curr_p != NULL && *curr_p != '\0';
+ curr_p = end_p + 1) {
+ end_p = strchr(curr_p, '\n');
+ if (end_p != NULL) {
+ size_t line_len = end_p - curr_p;
+ size_t line_count = 0;
+ char **line_items;
+ line_items = split_line(curr_p, LINE_SEP, 0, line_len, &line_count);
+/* fprintf(stderr, "length of line: %d; %d items\n", line_len, line_count); */
+/* show_items("LINE", line_items, line_count); */
+ if (line_count != 4) { /* error */
+ XDVI_WARNING((stderr, "Wrong number of items (%lu) in translations line:\n\"%.*s\" "
+ "(skipping this line).\n",
+ (unsigned long)line_count, (int)line_len, curr_p));
+ free_items(line_items, line_count);
+ continue;
+ }
+ else { /* split first elem into menu description */
+ size_t menu_len = strlen(line_items[0]);
+ size_t menu_count = 0;
+ char **menu_items;
+ if (menu_len == 0) { /* error */
+ XDVI_WARNING((stderr, "Menu description (1st item) mustn't be empty:\n\"%.*s\" "
+ "(skipping this line).\n",
+ (int)line_len, curr_p));
+ free_items(line_items, line_count);
+ continue;
+ }
+ menu_items = split_line(line_items[0], MENU_SEP, 0, menu_len, &menu_count);
+/* show_items(" MENU", menu_items, menu_count); */
+
+ insert_items(info, menu_items, menu_count, line_items[1], line_items[2], line_items[3]);
+ free_items(menu_items, menu_count);
+ }
+ free_items(line_items, line_count);
+ }
+ }
+ show_button_info(0, *info);
+}
+
+/*
+ Top-level routine: creates the pulldown menu buttons for Motif and Xaw.
+ For Motif, sets *globals.widgets.menu_bar to the address of the new widget created,
+ for Xaw, sets *width to the width of the button panel created.
+*/
+void
+create_menu_buttons(Widget parent,
+#ifdef MOTIF
+ Widget *menu_bar
+#else
+ int *width
+#endif
+ )
+{
+#ifdef MOTIF
+ Widget menu = 0;
+#else /* MOTIF */
+ Widget panel = 0;
+ Boolean first_time = True;
+ int menu_depth = 0;
+#endif
+ size_t i;
+
+ m_button_info = xmalloc(sizeof *m_button_info);
+ m_button_info->elems = NULL;
+ m_button_info->size = 0;
+
+#ifdef MOTIF
+ *menu_bar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
+ parse_button_translations(&m_button_info);
+/* menu = xm_create_menu(*menu_bar, m_button_info); */
+ for (i = 0; i < m_button_info->size; i++) {
+ menu = xm_create_menu(*menu_bar,
+ m_button_info->elems[i].title,
+ m_button_info->elems[i].mnemonic,
+ m_button_info->elems[i].submenu);
+ }
+ if (menu != 0) {
+ XtVaSetValues(*menu_bar, XmNmenuHelpWidget, menu, NULL);
+ }
+#else /* MOTIF */
+ if (first_time) {
+ first_time = False;
+ xaw_initialize_menu_bitmaps();
+ panel = xaw_create_menu_widgets(parent);
+ parse_button_translations(&m_button_info);
+ }
+ xaw_create_menu(m_button_info, panel, menu_depth, width);
+#endif /* MOTIF */
+ initialize_menus();
+}
+#endif /* NEW_MENU_CREATION || MOTIF */
diff --git a/Build/source/texk/xdvik/gui/menu.h b/Build/source/texk/xdvik/gui/menu.h
new file mode 100644
index 00000000000..3c5f4487f1f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/menu.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Common code for Xaw and Motif menu bar creation.
+ */
+#ifndef MENU_H_
+#define MENU_H_
+
+#include "xdvi-config.h"
+#include "events.h"
+#include "xdvi.h"
+
+typedef enum {
+ BT_INVALID = -1, /* error code */
+ BT_NONE = 0,
+ BT_PUSH, /* pushbutton */
+ BT_RADIO, /* radio button (1 of n) */
+ BT_CHECK, /* check button (m of n) */
+ BT_SEP /* separator */
+} buttonTypeT;
+
+
+/* structures for menu data */
+struct button_elems {
+ char *title; /* menu item label string */
+ buttonTypeT type; /* button type */
+ char mnemonic; /* 0 if none */
+ char *accelerator; /* NULL if none */
+ struct button_info *submenu;/* submenu, or NULL */
+ Widget widget; /* the widget in this item, for later use, or 0 */
+ struct xdvi_action *action; /* translated action, for later use, or NULL */
+};
+
+struct button_info {
+ size_t size;
+ struct button_elems *elems;
+};
+
+#include "xm_menu.h"
+#include "xaw_menu.h"
+
+extern void create_menu_buttons(Widget parent,
+#ifdef MOTIF
+ Widget *child
+#else
+ int *ret_panel_width
+#endif
+ );
+
+extern void set_menu(void *val, XtActionProc proc, Boolean (*cmp)());
+
+#endif /* MENU_H_ */
diff --git a/Build/source/texk/xdvik/gui/message-window.c b/Build/source/texk/xdvik/gui/message-window.c
new file mode 100644
index 00000000000..55e148daa1b
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/message-window.c
@@ -0,0 +1,1207 @@
+/*------------------------------------------------------------
+message-window.c: message popups for xdvi.
+
+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.
+
+------------------------------------------------------------*/
+
+
+
+/*
+
+============================================
+Suggested Policy for using the GUI messages:
+============================================
+
+- Use the statusline for shorter messages, a message window for more
+ important messages or such where you'd like to give further help info
+ (see the `helptext' argument of popup_message()). When in doubt,
+ prefer the statusline (excessive use of popup windows is a nuisance
+ for the user).
+
+- Don't use any of the GUI messages to report internal workings of
+ the program; for important internal information, there should be a
+ debugging setting to print it to stderr. Use the GUI messages
+ only in situations such as the following:
+
+ - to give the user feedback on actions that (s)he initiated
+
+ - to indicate that an internal action causes a delay perceptible
+ by the user (as a rough guide: a delay of more than half a second)
+
+ - to report situations that might require new actions by the user.
+
+*/
+
+#include <ctype.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "string-utils.h"
+
+/* Xaw specific stuff */
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#ifdef MOTIF
+# include <Xm/DialogS.h>
+# include <Xm/MessageB.h>
+# include <Xm/PushB.h>
+# include <Xm/Label.h>
+# include <Xm/Form.h>
+# include <Xm/MenuShell.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#else
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/MenuButton.h>
+# include <X11/Xaw/SimpleMenu.h>
+# include <X11/Xaw/Sme.h>
+# include <X11/Xaw/SmeBSB.h>
+# include <X11/Xaw/AsciiText.h>
+# include <X11/Xaw/Dialog.h>
+#endif
+
+#include "kpathsea/c-vararg.h"
+#include "xdvi.h"
+#include "util.h"
+#include "string-utils.h"
+#include "x_util.h"
+#include "message-window.h"
+
+/* have no more than MAX_POPUPS open simultaneously */
+#define MAX_POPUPS 10
+
+/* offset for cascading popups */
+#define POPUP_OFFSET ((my_popup_num * 20))
+
+#ifdef MOTIF
+/* wrap messages after MSG_WRAP_LEN characters at whitespace */
+#define MSG_WRAP_LEN 60
+#endif
+
+/* array of active popups: */
+static int g_popup_array[MAX_POPUPS];
+
+static Atom WM_DELETE_WINDOW;
+
+/* arrays for saving the widgets of multiple popups;
+ * same index as in g_popup_array:
+ */
+#ifdef MOTIF
+static Widget popup_window[MAX_POPUPS], dialog[MAX_POPUPS];
+#else
+static Widget popup_window[MAX_POPUPS], message_box[MAX_POPUPS],
+ message_text[MAX_POPUPS], message_paned[MAX_POPUPS],
+ message_ok[MAX_POPUPS], message_help[MAX_POPUPS], message_not_ok[MAX_POPUPS];
+#endif
+
+/* map popupMessageT's to strings/motif dialog elements */
+static struct message_map {
+ char *window_title;
+#ifdef MOTIF
+ int motif_msg_type;
+#endif
+} my_msg_map[] = {
+ { "Xdvi Question"
+#ifdef MOTIF
+ , XmDIALOG_QUESTION
+#endif
+ }, /* MSG_QUESTION */
+ { "Xdvi Help"
+#ifdef MOTIF
+ , XmDIALOG_INFORMATION
+#endif
+ }, /* MSG_HELP */
+ { "Xdvi Info"
+#ifdef MOTIF
+ , XmDIALOG_INFORMATION
+#endif
+ }, /* MSG_INFO */
+ { "Xdvi Warning"
+#ifdef MOTIF
+ , XmDIALOG_WARNING
+#endif
+ }, /* MSG_WARN */
+ { "Xdvi Error"
+#ifdef MOTIF
+ , XmDIALOG_ERROR
+#endif
+ }, /* MSG_ERR */
+};
+
+struct ok_or_cancel_cb {
+ message_cbT callback; /* callback function */
+ XtPointer arg; /* arg for callback function */
+};
+
+struct pre_ok_or_cancel_cb {
+ pre_message_cbT callback; /* callback function */
+ XtPointer arg; /* arg for callback function */
+};
+
+static struct ok_or_cancel_cb yes_callbacks[MAX_POPUPS];
+static struct ok_or_cancel_cb no_callbacks[MAX_POPUPS];
+static struct ok_or_cancel_cb cancel_callbacks[MAX_POPUPS];
+static struct pre_ok_or_cancel_cb pre_callbacks[MAX_POPUPS];
+
+
+static void
+popdown_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ size_t idx;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(*num_params == 1, "Wrong number of parameters in callback");
+ idx = strtoul(*params, (char **)NULL, 10);
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ /* invoke the callback if present */
+ if (cancel_callbacks[idx].callback != NULL) {
+ cancel_callbacks[idx].callback(cancel_callbacks[idx].arg);
+ }
+}
+
+#ifndef MOTIF
+static void
+xaw_popdown(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ size_t idx;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(*num_params == 1, "Wrong number of parameters in callback");
+ idx = strtoul(*params, (char **)NULL, 10);
+
+ /*
+ NOTE: first pop down window and mark its position as free, then
+ invoke the callback. The reason for this is that the callback
+ may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+}
+
+#endif
+
+static XtActionsRec popdown_actions[] = {
+ {"close-popup-cancel", popdown_cancel },
+#if !MOTIF
+ {"WM_popdown", popdown_cancel },
+ {"close-popup", xaw_popdown },
+#endif
+};
+
+static void
+ok_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int idx = -1;
+
+ UNUSED(call_data);
+
+#if MOTIF
+ UNUSED(client_data);
+ XtVaGetValues(w, XmNuserData, &idx, NULL);
+ ASSERT(idx >= 0, "Couldn't get idx from XmNuserData!");
+#else
+ UNUSED(w);
+ idx = (int)client_data;
+#endif
+
+#if DEBUG
+ fprintf(stderr, "quit_action called for popup %d\n", idx);
+#endif
+ ASSERT(idx >= 0 && idx < MAX_POPUPS, "Invalid widget index in ok_action()");
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ if (yes_callbacks[idx].callback != NULL) {
+ yes_callbacks[idx].callback(yes_callbacks[idx].arg);
+ }
+}
+
+/*------------------------------------------------------------
+ * help_action
+ *
+ * Arguments:
+ * Widget w, XtPointer call_data
+ * - (ignored)
+ * XtPointer client_data
+ * - the help string
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Callback for the `Help' button; opens another window
+ * containing the help text. The new window won't have
+ * another `Help' button.
+ *------------------------------------------------------------*/
+
+static void
+help_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(call_data);
+
+ /* open another window with the help text */
+ popup_message(get_matching_parent(w, globals.widgets.top_level, "message_popup", NULL), MSG_HELP, NULL, client_data);
+}
+
+
+/*
+ * Callback for cancel button in choice_dialog.
+*/
+static void
+cancel_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int idx = -1;
+
+ UNUSED(call_data);
+
+#if MOTIF
+ /* for motif, the index is in XmNuserData */
+ UNUSED(client_data);
+ if (strcmp(XtName(w), Xdvi_MESSAGE_SHELL_NAME) == 0) {
+ /* invoked by the WM, get the messagebox child */
+ Widget child;
+ if (get_widget_by_name(&child, w, Xdvi_MESSAGE_DIALOG_NAME, True)) {
+ XtVaGetValues(child, XmNuserData, &idx, NULL);
+ }
+ }
+ else {
+ XtVaGetValues(w, XmNuserData, &idx, NULL);
+ }
+ ASSERT(idx >= 0, "Couldn't get idx from XmNuserData!");
+#else
+ UNUSED(w);
+ idx = (int)client_data;
+#endif
+ ASSERT(idx >= 0 && idx < MAX_POPUPS, "Invalid widget index in cancel_action()");
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ /* invoke the callback if present */
+ if (cancel_callbacks[idx].callback != NULL) {
+ cancel_callbacks[idx].callback(cancel_callbacks[idx].arg);
+ }
+}
+
+#if MOTIF
+static void
+not_ok_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ /* Note: unmanage the parent of the button */
+ int idx = -1;
+
+ UNUSED(client_data);
+
+ UNUSED(call_data);
+ XtVaGetValues(w, XmNuserData, &idx, NULL);
+ ASSERT(idx >= 0, "Couldn't get idx from XmNuserData!");
+ ASSERT(idx >= 0 && idx < MAX_POPUPS, "Invalid widget index in ok_action()");
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ if (no_callbacks[idx].callback != NULL) {
+ no_callbacks[idx].callback(no_callbacks[idx].arg);
+ }
+}
+#endif /* MOTIF */
+
+/*------------------------------------------------------------
+ * create_dialogs
+ *
+ * Arguments:
+ * Widget toplevel - parent for the dialog window
+ *
+ * helptext - if not-NULL, create an additional
+ * `help' button
+ *
+ * cnt - number of current popup dialog
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Create message dialog widgets
+ *------------------------------------------------------------*/
+
+static Widget
+create_dialogs(popupMessageSizeHintT size,
+ Widget parent,
+ int cnt,
+ const char *helptext,
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_button, message_cbT yes_cb, XtPointer yes_arg,
+ const char *no_button, message_cbT no_cb, XtPointer no_arg,
+ const char *cancel_button, message_cbT cancel_cb, XtPointer cancel_arg)
+{
+ Widget new_popup_window;
+ char *translations_str = NULL;
+#ifdef MOTIF
+ Widget new_dialog;
+ UNUSED(size);
+#else
+ char *key_translations_str = NULL;
+ int msg_w = 400, msg_h = 100;
+ Widget new_message_paned, new_message_text, new_message_box, new_message_ok,
+ new_message_help = 0, new_message_not_ok;
+ XtTranslations wm_translations, key_translations;
+#endif
+
+ /* save callbacks to global arrays */
+ pre_callbacks[cnt].callback = pre_cb;
+ pre_callbacks[cnt].arg = arg;
+
+ yes_callbacks[cnt].callback = yes_cb;
+ yes_callbacks[cnt].arg = yes_arg;
+
+ no_callbacks[cnt].callback = no_cb;
+ no_callbacks[cnt].arg = no_arg;
+
+ cancel_callbacks[cnt].callback = cancel_cb;
+ cancel_callbacks[cnt].arg = cancel_arg;
+
+ XtAddActions(popdown_actions, XtNumber(popdown_actions));
+
+#ifndef MOTIF
+ /* get index into WM_popdown arg */
+ translations_str = get_string_va("<Message>WM_PROTOCOLS: WM_popdown(%d)", cnt);
+ wm_translations = XtParseTranslationTable(translations_str);
+ free(translations_str);
+#endif
+
+ if (!XtIsRealized(globals.widgets.top_level)) {
+ /* If toplevel window hasn't been realized yet, create a new toplevel shell
+ (otherwise, setting visual/color map wouldn't work); use same application names
+ so that resource settings will also apply to this window.
+ */
+ new_popup_window = XtVaAppCreateShell("xdvi", "Xdvi",
+ transientShellWidgetClass, DISP,
+ NULL);
+ }
+ else {
+ new_popup_window = XtVaCreatePopupShell(Xdvi_MESSAGE_SHELL_NAME,
+#ifdef MOTIF
+ xmDialogShellWidgetClass, parent,
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+#else
+ transientShellWidgetClass, parent,
+ XtNx, 60,
+ XtNy, 80,
+ XtNtranslations, wm_translations,
+ XtNaccelerators, G_accels_cr,
+#endif
+ XtNtransientFor, parent,
+ XtNmappedWhenManaged, False,
+ NULL);
+ }
+
+#ifdef MOTIF
+
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(new_popup_window), "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(new_popup_window, WM_DELETE_WINDOW, cancel_action, NULL);
+
+ /* We also need to override the default ESC binding to use our internal
+ housekeeping functions */
+ translations_str = get_string_va("#override\n<Key>osfCancel:close-popup-cancel(%d)", cnt);
+/* { */
+/* XtTranslations xlats; */
+/* char *translation_str = get_string_va("<Key>osfCancel:close-popup-cancel(%d)", cnt); */
+/* xlats = XtParseTranslationTable(translation_str); */
+/* free(translation_str); */
+/* XtOverrideTranslations(new_dialog, xlats); */
+/* } */
+
+ new_dialog = XtVaCreateWidget(Xdvi_MESSAGE_DIALOG_NAME, xmMessageBoxWidgetClass, new_popup_window,
+ XmNdialogType, XmDIALOG_WARNING, /* default */
+ XmNtraversalOn, True,
+ XmNhighlightOnEnter, True,
+ XmNuserData, cnt,
+ XmNtranslations, XtParseTranslationTable(translations_str),
+ NULL);
+ free(translations_str);
+ XtAddCallback(new_dialog, XmNokCallback, ok_action, NULL);
+
+ if (no_button != NULL) {
+ Arg args[4];
+ Widget b;
+ XmString b_str = XmStringCreateLocalized((char *)no_button);
+ XtSetArg(args[0], XmNlabelString, b_str);
+ b = XmCreatePushButton(new_dialog, "no_button", args, 1);
+ XtAddCallback(b, XmNactivateCallback, not_ok_action, NULL);
+ XtManageChild(b);
+ }
+
+ if (cancel_button != NULL) {
+ XmString cancel_label = XmStringCreateLtoR((char *)cancel_button, G_charset);
+ XtVaSetValues(XmMessageBoxGetChild(new_dialog, XmDIALOG_CANCEL_BUTTON),
+ XmNlabelString, cancel_label, NULL);
+ XmStringFree(cancel_label);
+ XtAddCallback(new_dialog, XmNcancelCallback, cancel_action, NULL);
+ }
+ else {
+ XtUnmanageChild(XmMessageBoxGetChild(new_dialog, XmDIALOG_CANCEL_BUTTON));
+ }
+ XtInstallAllAccelerators(new_dialog,
+ XmMessageBoxGetChild(new_dialog, XmDIALOG_OK_BUTTON));
+
+ if (helptext != NULL) {
+ XtAddCallback(new_dialog, XmNhelpCallback, help_action, (XtPointer)helptext);
+ }
+ else {
+ XtUnmanageChild(XmMessageBoxGetChild(new_dialog, XmDIALOG_HELP_BUTTON));
+ }
+
+ if (yes_button != NULL) { /* change `OK' button label */
+ XmString yes_label;
+ yes_label = XmStringCreateLtoR((char *)yes_button, G_charset);
+ XtVaSetValues(XmMessageBoxGetChild(new_dialog, XmDIALOG_OK_BUTTON),
+ XmNlabelString, yes_label, NULL);
+ XmStringFree(yes_label);
+ }
+
+ /* insert the new widgets into the global arrays */
+ dialog[cnt] = new_dialog;
+
+#else /* MOTIF */
+ switch (size) {
+ case SIZE_SMALL:
+ msg_w = 300;
+ msg_h = 100;
+ break;
+ case SIZE_MEDIUM:
+ msg_w = 430;
+ msg_h = 160;
+ break;
+ case SIZE_LARGE:
+ msg_w = 450;
+ msg_h = 180;
+ break;
+ }
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(new_popup_window), "WM_DELETE_WINDOW", False);
+
+ new_message_paned = XtVaCreateManagedWidget("message_paned", panedWidgetClass, new_popup_window,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ new_message_text = XtVaCreateManagedWidget("message_text", asciiTextWidgetClass, new_message_paned,
+/* XtNheight, 100, */
+/* XtNwidth, 400, */
+ XtNwidth, msg_w,
+ XtNheight, msg_h,
+ /* wrap horizontally instead of scrolling
+ * TODO: this won't work for the first widget instance?
+ */
+ XtNwrap, XawtextWrapWord,
+ XtNscrollVertical, XAW_SCROLL_ALWAYS,
+ XtNeditType, XawtextRead,
+ XtNinput, True,
+ XtNdisplayCaret, False,
+ XtNleftMargin, 5,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ /* box for the OK/Cancel button */
+ new_message_box = XtVaCreateManagedWidget("message_box", formWidgetClass, new_message_paned,
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the text widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ new_message_ok = XtVaCreateManagedWidget(yes_button == NULL ? "OK" : yes_button,
+ commandWidgetClass, new_message_box,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ /* add quit_action callback for the "OK" button */
+ /* FIXME: how to make accelerators be accepted by new_popup_window as well? */
+ key_translations_str = get_string_va("<Key>q:close-popup-cancel(%d)\n"
+ "<Key>Return:close-popup-cancel(%d)\n"
+ "<Key>Escape:close-popup-cancel(%d)\n",
+ cnt, cnt, cnt);
+ key_translations = XtParseTranslationTable(key_translations_str);
+ free(key_translations_str);
+ XtOverrideTranslations(new_popup_window, key_translations);
+ XtOverrideTranslations(new_message_paned, key_translations);
+ XtOverrideTranslations(new_message_text, key_translations);
+
+ XtInstallAllAccelerators(new_message_box, new_message_ok);
+ XtAddCallback(new_message_ok, XtNcallback, ok_action, (XtPointer)cnt);
+
+ /* we create additional buttons in any case,
+ to make the sizing more consistent */
+ new_message_help = XtVaCreateManagedWidget("Help", commandWidgetClass, new_message_box,
+ XtNtop, XtChainTop,
+ XtNfromHoriz, new_message_ok,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ message_help[cnt] = new_message_help;
+
+ /* add cancel button */
+ new_message_not_ok = XtVaCreateManagedWidget(cancel_button == NULL ? "Cancel" : cancel_button,
+ commandWidgetClass, new_message_box,
+ XtNtop, XtChainTop,
+ XtNfromHoriz, new_message_ok,
+ XtNbottom, XtChainBottom,
+ XtNleft, helptext == NULL ? XtChainRight : XtChainLeft,
+ XtNright, helptext == NULL ? XtChainRight : XtChainLeft,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ message_not_ok[cnt] = new_message_not_ok;
+
+ if (no_button != NULL) {
+ ASSERT(0, "third button not yet implemented in Xaw!!!");
+ }
+
+
+ { /* set all buttons to same size */
+ Dimension w1, w2, w3, max;
+ XtVaGetValues(new_message_ok, XtNwidth, &w1, NULL);
+ XtVaGetValues(new_message_help, XtNwidth, &w2, NULL);
+ XtVaGetValues(new_message_not_ok, XtNwidth, &w3, NULL);
+ max = w1;
+ if (w2 > max)
+ max = w2;
+ if (w3 > max)
+ max = w3;
+ XtVaSetValues(new_message_ok, XtNwidth, max, NULL);
+ XtVaSetValues(new_message_help, XtNwidth, max, NULL);
+ XtVaSetValues(new_message_not_ok, XtNwidth, max, NULL);
+ }
+ /* if helptext argument is not-NULL, add help_action callback,
+ else unmanage help button */
+ if (helptext != NULL) {
+ XtAddCallback(new_message_help, XtNcallback, help_action, (XtPointer)helptext);
+ }
+ else {
+ XtUnmanageChild(new_message_help);
+ }
+
+ if (cancel_button != NULL) {
+ XtAddCallback(new_message_not_ok, XtNcallback, cancel_action, (XtPointer)cnt);
+ }
+ else {
+ XtUnmanageChild(new_message_not_ok);
+ }
+ /* insert the new widgets into the global arrays */
+ message_box[cnt] = new_message_box;
+ message_paned[cnt] = new_message_paned;
+ message_text[cnt] = new_message_text;
+ message_ok[cnt] = new_message_ok;
+
+#endif /* MOTIF */
+ popup_window[cnt] = new_popup_window;
+
+ return new_popup_window;
+}
+
+
+/*
+ * Popup a window with wrapped text in it.
+ * For Motif, the text is explicitly wrapped inside this method.
+ */
+static Widget
+internal_popup_window(Widget parent,
+ popupMessageSizeHintT size,
+ popupMessageT type,
+ int x_coord, int y_coord,
+ const char *helptext,
+ char *msg_buf,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_button, message_cbT yes_cb, XtPointer yes_arg,
+ const char *no_button, message_cbT no_cb, XtPointer no_arg,
+ const char *cancel_button, message_cbT cancel_cb, XtPointer cancel_arg)
+{
+ char win_title[64];
+ int my_popup_num = 0;
+#ifdef MOTIF
+ XmString str;
+#endif
+ Widget ret;
+
+ ASSERT(type < (sizeof my_msg_map / sizeof my_msg_map[0]), "too few elements in my_msg_map");
+ sprintf(win_title, my_msg_map[type].window_title);
+
+#if DEBUG
+ fprintf(stderr, "internal_popup_window called with prompt: \"%s\"\n", msg_buf);
+#endif
+
+ if (globals.widgets.top_level == 0) {
+ /* If toplevel window hasn't been create yet, dump messages to STDERR and return.
+ All text must be passed as arguments to fprintf (NOT puts), since they are
+ supposed to be printf-format strings (i.e. with doubled `%' to escape them)
+ */
+ fprintf(stderr, "\n%s:\n", my_msg_map[type].window_title);
+ fprintf(stderr, msg_buf);
+ fprintf(stderr, "\n");
+ if (helptext) {
+ fprintf(stderr, "---------- helptext ----------\n");
+ fprintf(stderr, helptext);
+ fprintf(stderr, "\n---------- end of helptext ----------\n");
+ }
+ return NULL;
+ }
+ /* search for first free position in g_popup_array */
+ while (my_popup_num < MAX_POPUPS && (g_popup_array[my_popup_num] == 1)) {
+ my_popup_num++;
+ }
+ if (my_popup_num == MAX_POPUPS) {
+ /* already enough popups on screen, just dump it to stderr */
+ fprintf(stderr, "%s:\n", win_title);
+ fprintf(stderr, msg_buf);
+ /* Note: If a mad function continues to open popups, this will
+ * stop after MAX_POPUPS, but open a new window for each
+ * window the user pops down. Maybe we ought to do something
+ * about this.
+ */
+ return NULL;
+ }
+ else {
+ /* mark it as non-free */
+ g_popup_array[my_popup_num] = 1;
+ }
+#if DEBUG
+ fprintf(stderr, "first free position in g_popup_array: %d\n", my_popup_num);
+#endif
+
+ /* just to make sure ... */
+ if (parent == NULL)
+ parent = globals.widgets.top_level;
+
+ /* create a new set of widgets for the additional popup. */
+ ret = create_dialogs(size, parent,
+ my_popup_num,
+ helptext,
+ pre_cb, arg,
+ yes_button, yes_cb, yes_arg,
+ no_button, no_cb, no_arg,
+ cancel_button, cancel_cb, cancel_arg);
+#ifdef MOTIF
+ XtVaSetValues(popup_window[my_popup_num], XmNtitle, win_title, NULL);
+ XtVaSetValues(dialog[my_popup_num], XmNdialogType, my_msg_map[type].motif_msg_type, NULL);
+ { /* wrap message at space before MSG_WRAP_LEN */
+ char *testwrap = msg_buf;
+ int ctr;
+ for (ctr = 0; *testwrap++; ctr++) {
+ if (*testwrap == '\n') {
+ ctr = 0;
+ }
+ else if (ctr > MSG_WRAP_LEN) {
+ size_t before_len = 0, after_len = 0;
+ char *before_ptr, *after_ptr;
+ before_ptr = after_ptr = testwrap;
+ /* try to find shortest sequence before or after point to wrap at;
+ this seems to give the most pleasing results.
+ */
+ while (before_ptr > msg_buf && !isspace((int)*--before_ptr)) {
+ before_len++;
+ }
+ while (*after_ptr != '\0' && !isspace((int)*++after_ptr)) {
+ after_len++;
+ }
+
+ if (before_len < after_len && isspace((int)*before_ptr)) {
+ /* use last in sequence of multiple spaces */
+ while (isspace((int)*++before_ptr)) { ; }
+ /* back up, and wrap */
+ *--before_ptr = '\n';
+ ctr = 0;
+ }
+ else if (isspace((int)*after_ptr)) {
+ /* use last in sequence of multiple spaces */
+ while (isspace((int)*++after_ptr)) { ; }
+ /* back up, and wrap */
+ *--after_ptr = '\n';
+ ctr = 0;
+ }
+ }
+ }
+ }
+ str = XmStringCreateLtoR((char *)msg_buf, G_charset);
+ XtVaSetValues(dialog[my_popup_num],
+ XmNmessageString, str,
+ XmNtraversalOn, True,
+ XmNhighlightOnEnter, True,
+ NULL);
+ XmStringFree(str);
+
+ XtManageChild(dialog[my_popup_num]);
+
+ if (x_coord > 0 && y_coord > 0) {
+ position_window(XtParent(dialog[my_popup_num]), (Position)x_coord, (Position)y_coord);
+ }
+
+ XtPopup(XtParent(dialog[my_popup_num]), XtGrabNone);
+/* XtPopup(XtParent(dialog[my_popup_num]), XtGrabExclusive); */
+
+#else /* MOTIF */
+
+ /* add a binding of xaw_ret_action_str to <Return> to relevant widgets.
+ The callbacks (xaw_ret_action_str) are responsible for parsing the
+ passed arguments (pointers, or empty arguments).
+ */
+ if (xaw_ret_action_str != NULL) {
+ XtTranslations xlats;
+ char *translation_str;
+
+ if (yes_arg != NULL)
+ translation_str = get_string_va("<Key>Return:close-popup(%d)%s(%p)",
+ my_popup_num, xaw_ret_action_str, yes_arg);
+ else
+ translation_str = get_string_va("<Key>Return:close-popup(%d)%s()",
+ my_popup_num, xaw_ret_action_str);
+
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+ XtOverrideTranslations(popup_window[my_popup_num], xlats);
+ XtOverrideTranslations(message_paned[my_popup_num], xlats);
+ XtOverrideTranslations(message_text[my_popup_num], xlats);
+ }
+
+ XtVaSetValues(popup_window[my_popup_num], XtNtitle, win_title, NULL);
+ XtVaSetValues(message_text[my_popup_num], XtNstring, msg_buf, NULL);
+ XtRealizeWidget(popup_window[my_popup_num]);
+
+ XSetWMProtocols(XtDisplay(popup_window[my_popup_num]), XtWindow(popup_window[my_popup_num]),
+ &WM_DELETE_WINDOW, 1);
+
+ if (x_coord <= 0 || y_coord <= 0)
+ center_window(popup_window[my_popup_num], parent);
+ else
+ position_window(popup_window[my_popup_num], (Position)x_coord, (Position)y_coord);
+
+ if (my_popup_num > 0) {
+ /* some window managers position new windows exactly above the
+ existing one; to prevent this, move it with some offset
+ from the previous one: */
+ Position x = 0, y = 0;
+ XtVaGetValues(popup_window[my_popup_num-1], XtNx, &x, XtNy, &y, NULL);
+ XtVaSetValues(popup_window[my_popup_num], XtNx, x + POPUP_OFFSET, XtNy, y + POPUP_OFFSET, NULL);
+
+ }
+ XtPopup(popup_window[my_popup_num], XtGrabNone);
+/* XtPopup(XtParent(popup_window[my_popup_num]), XtGrabExclusive); */
+ if (XtIsManaged(message_not_ok[my_popup_num]) && XtIsManaged(message_help[my_popup_num])) {
+ /* center the help button. This is something of a sham, since it won't
+ survive resizing; but in general most users won't resize dialogs ;-) */
+ Position x1, x2, bw;
+ int w, dist;
+
+ XtVaGetValues(message_ok[my_popup_num], XtNx, &x1, XtNwidth, &w, XtNborderWidth, &bw, NULL);
+ XtVaGetValues(message_help[my_popup_num], XtNx, &x2, NULL);
+ /* following formula is measured, not calculated -
+ I have no idea why it's e.g. 2 * w, not 1.5 * w ... */
+ dist = (x2 - x1 - 2 * w) / 2 - 2 * bw;
+ XtVaSetValues(message_not_ok[my_popup_num], XtNhorizDistance, dist, NULL);
+ }
+
+#endif /* MOTIF */
+ return ret;
+}
+
+
+/*------------------------------------------------------------
+ * popup_message
+ *
+ * Arguments:
+ * popupMessageT - info, warning, error etc; see message-window.h for details
+ *
+ * char *helptext
+ * - if not-null, this will add a `Help'
+ * button to the message widget that pops
+ * up another message widget containing
+ * <helptext>.
+ *
+ *
+ * char *msg, ...
+ * - format string followed by a variable
+ * number of arguments to be formatted.
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Pop up a message window containing <msg>.
+ * If there are already n popups open, will open
+ * a new one unless n >= MAX_POPUPS.
+ *------------------------------------------------------------*/
+
+Widget
+popup_message(Widget parent, popupMessageT type, const char *helptext, const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ NULL,
+#endif
+ /* no special callbacks here */
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+popup_message_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT sizehint,
+ const char *helptext,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ sizehint,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ NULL,
+#endif
+ /* empty callbacks */
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+positioned_popup_message(Widget parent,
+ popupMessageT type,
+ int x, int y,
+ const char *helptext, const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ x, y, /* position at these coordinates */
+ helptext, msg_buf,
+#ifndef MOTIF
+ NULL,
+#endif
+ /* empty callbacks */
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+choice_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ xaw_ret_action_str,
+#endif
+ pre_cb, arg,
+ ok_label, ok_cb, ok_arg,
+ NULL, NULL, NULL,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+
+#if MOTIF
+Widget
+choice3_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_label, message_cbT yes_cb, XtPointer yes_arg,
+ const char *no_label, message_cbT no_cb, XtPointer no_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+ pre_cb, arg,
+ yes_label, yes_cb, yes_arg,
+ no_label, no_cb, no_arg,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+#endif
+
+Widget
+choice_dialog_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT sizehint,
+ const char *helptext,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ sizehint,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ xaw_ret_action_str,
+#endif
+ pre_cb, arg,
+ ok_label, ok_cb, ok_arg,
+ NULL, NULL, NULL,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+positioned_choice_dialog(Widget parent,
+ popupMessageT type,
+ int x_pos, int y_pos,
+ const char *helptext,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ x_pos, y_pos,
+ helptext, msg_buf,
+#ifndef MOTIF
+ xaw_ret_action_str,
+#endif
+ pre_cb, arg,
+ ok_label, ok_cb, ok_arg,
+ NULL, NULL, NULL,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+
+void
+warn_overstrike(void)
+{
+ static Boolean warned_overstrike = False;
+
+ if (!warned_overstrike) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ /* helptext */
+ "Greyscaling is running in copy mode; this will cause overstrike characters to "
+ "appear incorrectly, and may result in poor display quality. "
+ "Possible fixes are:\n"
+ "- Use the ``-thorough'' command-line option.\n"
+ "- Quit some other color-hungry applications (e.g. Netscape).\n"
+ "- Use the ``-install'' command-line option.\n"
+ "See the section ``GREYSCALING AND COLORMAPS'' in the "
+ "xdvi manual page for more details.",
+ /* text */
+ "Couldn't allocate enough colors - expect low display quality.");
+ warned_overstrike = True;
+ }
+}
+
+Boolean
+is_message_window(Widget w)
+{
+ int i;
+ for (i = 0; i < MAX_POPUPS; i++) {
+ if (w == popup_window[i])
+ return True;
+ }
+ return False;
+}
+
+Boolean
+kill_message_window(Widget w)
+{
+ int i;
+ for (i = 0; i < MAX_POPUPS; i++) {
+ if (g_popup_array[i] != 0 && XtIsRealized(popup_window[i]) && w == popup_window[i]) {
+ g_popup_array[i] = 0;
+ XtPopdown(popup_window[i]);
+ XtDestroyWidget(popup_window[i]);
+ XSync(DISP, True);
+ return True;
+ }
+ }
+ return False;
+}
+
+/*
+ Raise any popups that currently exist; return True iff such popups
+ exist, else False.
+*/
+Boolean
+raise_message_windows(void)
+{
+ int i;
+ Boolean have_popups = False;
+
+ for (i = 0; i < MAX_POPUPS; i++) {
+ if (g_popup_array[i] != 0 && XtIsRealized(popup_window[i])) {
+ XRaiseWindow(DISP, XtWindow(popup_window[i]));
+ have_popups = True;
+ }
+ }
+
+ return have_popups;
+}
diff --git a/Build/source/texk/xdvik/gui/message-window.h b/Build/source/texk/xdvik/gui/message-window.h
new file mode 100644
index 00000000000..7e38197abbc
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/message-window.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef MESSAGE_WINDOW_H_
+#define MESSAGE_WINDOW_H_
+
+#define Xdvi_MESSAGE_DIALOG_NAME "dialog"
+#define Xdvi_MESSAGE_SHELL_NAME "message_popup"
+
+
+/*
+ * Callback before the message window is closed. It is passed
+ * the message window widget ID, and the next XtPointer argument
+ * in the message dialog calls.
+ */
+typedef void (*pre_message_cbT)(Widget w, XtPointer arg);
+/*
+ * Additional callbacks passed in as argument. It is passed
+ * the next XtPointer argument in the message dialog calls.
+ */
+typedef void (*message_cbT)(XtPointer arg);
+
+/* preferred size of dialogs, only used for Xaw ... not really hints, but
+ hard-coded values ;-) */
+typedef enum popupMessageSizeHintT_ { SIZE_SMALL, SIZE_MEDIUM, SIZE_LARGE } popupMessageSizeHintT;
+typedef enum popupMessageT_ { MSG_QUESTION, MSG_HELP, MSG_INFO, MSG_WARN, MSG_ERR } popupMessageT;
+
+extern Widget popup_message(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+ const char *format, ...);
+
+extern Widget popup_message_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT size,
+ const char *helptext,
+ const char *format, ...);
+
+extern Widget positioned_popup_message(Widget parent,
+ popupMessageT type,
+ int x, int y,
+ const char *helptext, const char *format, ...);
+
+extern Widget choice_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+#ifndef MOTIF
+ const char *ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+
+#if MOTIF
+/* 3 buttons currently only implemented for Motif */
+extern Widget choice3_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_label, message_cbT yes_cb, XtPointer yes_args,
+ const char *no_label, message_cbT no_cb, XtPointer no_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+#endif
+
+extern Widget choice_dialog_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT size,
+ const char *helptext,
+#ifndef MOTIF
+ const char *ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+
+extern Widget positioned_choice_dialog(Widget parent,
+ popupMessageT type,
+ int x_pos, int y_pos,
+ const char *helptext,
+#ifndef MOTIF
+ const char *ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+extern void warn_overstrike(void);
+extern Boolean raise_message_windows(void);
+extern Boolean is_message_window(Widget w);
+extern Boolean kill_message_window(Widget w);
+
+/* XawtextScrollWhenNeeded has been ditched in Xaw7
+ (e.g. Xfree >= 4.x); from the man page:
+
+ The value XawtextScrollWhenNeeded (and whenNeeded, recognized by
+ the converter), is accepted for backwards compatibilty with
+ resource specifications written for the Xaw6 Text widget, but
+ ignored (effectively treated as XawtextScrollNever).
+
+ So we're forced to use `scrollAlways' here.
+*/
+#define XAW_SCROLL_ALWAYS XawtextScrollAlways
+
+/* the reconfig stuff has been fixed
+ in XFree 4.1.0, vendor release 6510 (Slackware 8.0) */
+#define BROKEN_RECONFIG (( \
+ (strstr(ServerVendor(DISP), "XFree") != NULL) \
+ && VendorRelease(DISP) >= 4000 \
+ && VendorRelease(DISP) < 4002 \
+ ))
+
+#endif /* MESSAGE_WINDOW_H_ */
diff --git a/Build/source/texk/xdvik/gui/pagesel.c b/Build/source/texk/xdvik/gui/pagesel.c
new file mode 100644
index 00000000000..b3db730e481
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/pagesel.c
@@ -0,0 +1,1591 @@
+/*
+ * Page selector for xdvi
+ *
+ * Copyright (c) 2001-2004 xdvik development team
+ *
+ * This code is derived from the page selector in xdvik-j, and
+ * parts of it are Copyright (c) 1993, 1995
+ * MATSUURA Syun syun@fuka.info.waseda.ac.jp
+ * HIRAHARA Atsushi hirahara@fuka.info.waseda.ac.jp
+ * ONO Kouichi onono@fuka.info.waseda.ac.jp
+ * All rights reserved.
+ *
+ *
+ * (SU: I was unsure how to interpret the `All rights reserved' in the
+ * previous line, so emailed Ono Kouichi about this. Here's a
+ * verbatim quote of the relevant part of his answer (which was CC'ed
+ * to Hirahara Atsushi - all three of them had left Waseda university
+ * around '95):
+ *
+ * You can modify, embed, copy and distribute a part of or the
+ * entire of our source code when you specify our copyright in your
+ * xdvik version.
+ *
+ * IANAL, but I think this is compatible with the X consortium
+ * license, which follows.)
+ *
+ * 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.
+ *
+ */
+
+/*
+ BUGS:
+
+ - with Xaw, the highlighting for the selected page (XawListHighlight)
+ vanishes when mouse is dragged outside the widget and then released
+ (but the respective page is selected, which is IMHO the desired behaviour).
+
+ - with Xaw, scrolling the list with PgUp/PgDown until the current page
+ gets `out of focus' should un-highlight the current page number
+
+ - The ASCII-based marks are *ugly*. Pixmaps (for the marked state)
+ would be better. The viewer gv has one (but it's Xaw only). Some
+ file directory widgets like
+ e.g. http://ftp.xfree86.org/pub/X.Org/contrib/widgets/ListTree-3.0b3.tar.gz
+ also have facilities for that, but most suffer from other
+ inadequacies (e.g. no such ting as browseSelection) and all kinds
+ of bitrot ... Another alternative would be using XmContainer
+ (see e.g. the `filemanager' example in demos/programs/filemanagers
+ in the openmotif distribution), but that's available for Motif >= 2.1 only.
+
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+
+#include "xm_toolbar.h"
+#include "xm_menu.h"
+#include "xaw_menu.h"
+
+#include "x_util.h"
+
+#ifdef MOTIF
+# include <Xm/Xm.h>
+# include <Xm/List.h>
+# include <Xm/ScrollBar.h> /* for XmScrollBarGetValues */
+#else /* MOTIF */
+# include <X11/Xaw/Dialog.h>
+# include <X11/Xaw/Cardinals.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/List.h>
+# include <X11/Xaw/Viewport.h>
+#endif /* MOTIF */
+
+#include "message-window.h"
+#include "pagesel.h"
+#include "util.h"
+#include "string-utils.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "events.h"
+#include "print-dialog.h"
+#include "search-internal.h"
+#include "pagehist.h"
+
+#define PAGENUMLEN 128
+#define SCROLL_LIST_SCROLLBAR 0
+
+#ifndef MAX_PAGE
+# define MAX_PAGE (1024)
+#endif /* MAX_PAGE */
+
+#define LONGESTPAGENUM 55
+
+
+/* for saving the GC of the pagelist widget
+ (when un-highlighting items in highlight_page_callback, and
+ drawing the `current' marker)
+*/
+static struct page_gc {
+ GC fore;
+ GC back;
+} m_page_gc;
+
+#define MOTIF_IDX_OFFSET 1 /* motif index starts at 1, not 0 */
+#if !defined(LESSTIF_VERSION)
+static Boolean my_list_pos_to_bounds(Widget widget, int idx, Position *x, Position *y, Dimension *w, Dimension *h);
+static void refresh_highlight_marker(Widget widget, GC gc, Position x, Position y, Dimension w, Dimension h);
+#endif /* !defined(LESSTIF_VERSION) */
+
+
+
+#ifdef MOTIF
+
+/* make button2 mark instead of drag&drop */
+static void xm_list_set_mark(Widget widget, XEvent *event, String *params, Cardinal *num_params);
+static void xm_list_drag_mark(Widget widget, XEvent *event, String *params, Cardinal *num_params);
+static XtActionsRec CustomListActions[] = {
+ { "ListSetMark", xm_list_set_mark },
+ { "ListDragMark", xm_list_drag_mark },
+};
+static char *motif_custom_translations =
+ "#override \n"
+ "s <Btn2Down>: ListDragMark(ListButtonMotion)\n"
+ "<Btn2Motion>: ListSetMark(ListButtonMotion)\n"
+ "<Btn2Up>: ListSetMark(ListButtonMotion)\n"
+ "<Btn2Down>: ListSetMark(ListButtonMotion)\n"
+/* /\* "s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginExtend)\n" *\/ */
+/* /\* "s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndExtend)\n" *\/ */
+/* /\* "~c ~s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginSelect)\n" *\/ */
+/* /\* "~c ~s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndSelect)\n" *\/ */
+/* /\* "c ~s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginToggle)\n" *\/ */
+/* /\* "c ~s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndToggle)\n" *\/ */
+/* /\* "c ~s ~m a <Btn2Down>: ListProcessDrag()\n" *\/ */
+/* /\* "~c s ~m a <Btn2Down>: ListProcessDrag()\n" *\/ */
+;
+
+#define LIST_WIDGET page_list
+/* motif pagenumber is a string */
+static const char* const pageno_format = "%c %s ";
+
+#else /* MOTIF */
+
+static int view_y;
+extern Widget panel_widget;
+static Widget list_widget = NULL;
+static Widget viewport = NULL;
+#define LIST_WIDGET list_widget
+/* Xaw pagenumber is an integer, and we need to left-pad it */
+static const char* const pageno_format = "%c %*d ";
+
+static int xaw_maybe_scroll_pagelist(int new_page, Boolean force_recenter, int old);
+
+#define REDRAW_CURRENT_MARKER_HACK 1
+
+
+/*
+ The following hack tries to address the following 2 bugs with the
+ self-made page highlighting marker:
+
+ - the marker overlaps with the ordinary XawListHighlight marker;
+ when un-highlighting a page, 1 pixel (vertically) at the edge of
+ the ordinary marker is overdrawn.
+
+ - When the XawListHighlight crosses the self-drawn rectangle,
+ the vertical bars remain visible, but the horizontal bars
+ are erased.
+
+ The hack just redraws the appropriate items whenever one of
+ the above can happen, i.e. when the two markers are 2 or less
+ pages apart from each other.
+*/
+#if REDRAW_CURRENT_MARKER_HACK
+/* Store index of currently marked (with our own marker) list
+ item, or -1 if none is marked. */
+static int g_current_highlighted = -1;
+
+/* redraw the default Xaw list highlight (XawListHighlight()) */
+static void
+xaw_maybe_redraw_highlight(int idx)
+{
+ XawListReturnStruct *ret;
+ int high;
+
+ if (LIST_WIDGET == NULL)
+ return;
+
+ ret = XawListShowCurrent(LIST_WIDGET);
+ high = ret->list_index;
+ if (high != XAW_LIST_NONE && abs(idx - (high + MOTIF_IDX_OFFSET)) <= 2) {
+ /* re-highlight it */
+ XawListHighlight(LIST_WIDGET, high);
+ }
+ g_current_highlighted = -1;
+}
+
+/* redraw our own rectangle highlight marker: */
+static void
+xaw_maybe_redraw_current_marker(int idx)
+{
+ Position x, y;
+ Dimension w, h;
+
+/* fprintf(stderr, "idx: %d, high: %d; diff: %d\n", idx + MOTIF_IDX_OFFSET, g_current_highlighted, */
+/* abs(idx + MOTIF_IDX_OFFSET - g_current_highlighted)); */
+ if (abs((idx + MOTIF_IDX_OFFSET) - g_current_highlighted) <= 2
+ && my_list_pos_to_bounds(LIST_WIDGET, g_current_highlighted, &x, &y, &w, &h)) {
+ refresh_highlight_marker(LIST_WIDGET, m_page_gc.fore, x, y, w, h);
+ }
+}
+#endif /* REDRAW_CURRENT_MARKER_HACK */
+
+#endif /* MOTIF */
+
+/*
+ * Table of page offsets in DVI file, indexed by page number - 1,
+ * marked pages, and page sizes.
+ * Initialized in prepare_pages().
+ */
+struct page_index {
+ long offset;
+ int number;
+ Boolean marked;
+ unsigned int pw, ph; /* page size */
+ unsigned int ww, wh; /* window size */
+};
+
+struct page_index_info {
+ struct page_index *index; /* above struct */
+ size_t index_size; /* size of currently allocated index */
+ char **page_labels; /* label strings */
+};
+
+static struct page_index_info page_info;
+
+/* access functions used by dvi-draw.c and dvi-init.c */
+long
+pageinfo_get_offset(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+/* fprintf(stderr, "offset for page %d is %ld\n", page, page_info.index[page].offset); */
+ return page_info.index[page].offset;
+}
+
+/* access functions used by dvi-draw.c and dvi-init.c */
+unsigned int
+pageinfo_get_page_width(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].pw;
+}
+
+unsigned int
+pageinfo_get_page_height(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].ph;
+}
+
+unsigned int
+pageinfo_get_window_width(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].ww;
+}
+
+unsigned int
+pageinfo_get_window_height(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].wh;
+}
+
+void
+pageinfo_set_page_width(int page, unsigned int width)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].pw = width;
+}
+
+void
+pageinfo_set_page_height(int page, unsigned int height)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].ph = height;
+}
+
+void
+pageinfo_set_window_width(int page, unsigned int width)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].ww = width;
+}
+
+void
+pageinfo_set_window_height(int page, unsigned int height)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].wh = height;
+}
+
+int
+pageinfo_get_number(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].number;
+}
+
+/* search for page with TeX number `number', and return its index, or -1 if it's not found. */
+int
+pageinfo_get_index_of_number(int number)
+{
+ size_t i;
+ for (i = 0; i < page_info.index_size - 1; i++) {
+ if (number == page_info.index[i].number)
+ return i;
+ }
+ return -1;
+}
+
+void
+pageinfo_set_offset(int index, long offset)
+{
+ ASSERT(index >= 0 && index < (int)page_info.index_size, "");
+ page_info.index[index].offset = offset;
+}
+
+void
+pageinfo_set_number(int index, int number)
+{
+ ASSERT(index >= 0 && index < (int)page_info.index_size, "");
+ page_info.index[index].number = number;
+}
+
+void
+pageinfo_allocate(int total_pages)
+{
+ int i;
+ page_info.index = xmalloc(total_pages * sizeof *(page_info.index));
+ for (i = 0; i < total_pages; i++) {
+ page_info.index[i].marked = False;
+ }
+ /* following initializations are handled by the respective Motif/Xaw functions */
+ page_info.page_labels = NULL;
+ page_info.index_size = total_pages;
+}
+
+/*
+ Deallocate page_info. NOTE: We mustn't free the page_labels here,
+ since the page list might survive quite some time (e.g. while fonts
+ for the new file are being generated) and needs the labels.
+*/
+void
+pageinfo_deallocate(void)
+{
+ free(page_info.index);
+ page_info.index_size = 0;
+ page_info.index = NULL;
+}
+
+#ifdef MOTIF
+void
+toggle_pagelist(void)
+{
+ Dimension curr_w, curr_x;
+ XtVaGetValues(globals.widgets.main_window,
+ XmNwidth, &curr_w,
+ XmNx, &curr_x,
+ NULL);
+
+ if ((resource.expert_mode & XPRT_SHOW_PAGELIST) != 0) {
+ XtManageChild(XtParent(page_list));
+ XtManageChild(page_list);
+
+ curr_x += resource.pagelist_width;
+ curr_w -= resource.pagelist_width;
+ XtVaSetValues(globals.widgets.main_window,
+ XtNwidth, curr_w,
+ XtNx, curr_x,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, XtParent(page_list),
+ NULL);
+ }
+ else {
+ XtUnmanageChild(XtParent(page_list));
+ XtUnmanageChild(page_list);
+
+ curr_x -= resource.pagelist_width;
+ curr_w += resource.pagelist_width;
+ XtVaSetValues(globals.widgets.main_window,
+ XmNwidth, curr_w,
+ XmNx, curr_x,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ }
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+#else
+ set_show_pagelist_option();
+#endif
+}
+#endif
+
+
+Boolean
+pageinfo_have_marked_pages(void)
+{
+ int i;
+ for (i = 0; i < total_pages; i++) {
+ if (page_info.index[i].marked) {
+ return True;
+ }
+ }
+ return False;
+}
+
+
+/* return True if page i is marked, False else */
+Boolean
+pageinfo_is_marked(int i)
+{
+ ASSERT(i <= (int)page_info.index_size, "");
+ return page_info.index[i].marked;
+}
+
+
+typedef enum { SCROLL_UP, SCROLL_DOWN, CLICK } saveCmdT;
+
+
+static void internal_process_button2(Widget widget, XEvent *event);
+static int get_item_index(Widget w, int mouse_y);
+
+static int
+get_page_size(void)
+{
+ int offset = 0;
+ int min_page = 0;
+ int max_page = 0;
+ int min_pageno_len = 0;
+ int max_pageno_len = 0;
+ int i;
+
+ if (globals.dvi_file.bak_fp == NULL)
+ return 0;
+
+ for (i = 0; i < total_pages; i++) {
+ max_page = MAX(page_info.index[i].number, max_page);
+ min_page = MIN(page_info.index[i].number, min_page);
+ }
+
+ if (min_page >= 0) {
+ offset = 0; /* plus symbol is hidden */
+ } else {
+ offset = 1; /* offset for minus symbol */
+ min_page = -min_page;
+ }
+ for (min_pageno_len = offset; min_page > 0;
+ min_page /= 10, min_pageno_len++);
+
+ if (max_page >= 0) {
+ offset = 0; /* plus symbol is hidden */
+ } else {
+ offset = 1; /* offset for minus symbol */
+ max_page = -max_page;
+ }
+ for (max_pageno_len = offset; max_page > 0;
+ max_page /= 10, max_pageno_len++);
+
+ return MAX(min_pageno_len, max_pageno_len);
+ /* Plus 1 for minus symbol */
+}
+
+#if !defined(LESSTIF_VERSION)
+/* draw or erase highlight marker at position x, y with widht w an height h,
+ using suitable offsets (for sake of consistency of the latter, and because
+ of the differences Xaw/Motif, this is a separate function).
+ */
+static void
+refresh_highlight_marker(Widget widget, GC gc,
+ Position x, Position y, Dimension w, Dimension h)
+{
+ XDrawRectangle(XtDisplay(widget), XtWindow(widget), gc,
+#ifdef MOTIF
+ x + 1, y + 1, w - 3, h - 3
+#else
+ x + 2, y, w - 1, h - 1
+#endif
+ );
+}
+#endif /* !defined(LESSTIF_VERSION) */
+
+#ifndef MOTIF
+
+/* update (redisplay) the list, saving the currently highlighted item.
+ * This is invoked whenever marking the page, and the re-construction of the
+ * entire list causes considerable flicker; but I guess that's unavoidable
+ * with the current simplistic labelling scheme (with changing the list items
+ * themselves). Gv does this considerably better (using custom widgets).
+ */
+static void
+xaw_update_list(void)
+{
+ static int pagelist_width = -1;
+ static int total_pages_bak = -1;
+
+ XawListReturnStruct *ret;
+ int idx, button_width;
+
+ if (pagelist_width == -1 || total_pages != total_pages_bak) {
+ pagelist_width = xaw_get_pagelist_size();
+ total_pages_bak = total_pages;
+ }
+
+ /* save selected item */
+ ret = XawListShowCurrent(LIST_WIDGET);
+ idx = ret->list_index;
+ button_width = get_panel_width() - 2 * (resource.btn_side_spacing + resource.btn_border_width);
+ /* delete and re-create list */
+ ASSERT(total_pages <= (int)page_info.index_size, "");
+ XawListChange(LIST_WIDGET, page_info.page_labels, 0,
+ MAX(button_width, pagelist_width), False);
+ /* restore selected item */
+ if (idx != XAW_LIST_NONE) {
+ XawListHighlight(LIST_WIDGET, idx);
+ }
+}
+
+/*
+ return height of a row in the list widget, and the initial offset of XtNinternalHeight
+ in parameters row_height and internal_h
+*/
+static void
+xaw_get_row_height(Widget w, Dimension *row_height, Dimension *internal_h)
+{
+ Dimension row_space;
+ XFontStruct *font;
+ Arg arglist[5];
+ int i = 0;
+
+ if (w == NULL || !XtIsRealized(w))
+ return;
+
+ XtSetArg(arglist[i], XtNfont, &font); ++i;
+ XtSetArg(arglist[i], XtNrowSpacing, &row_space); ++i;
+ XtSetArg(arglist[i], XtNinternalHeight, internal_h); i++;
+ XtGetValues(w, arglist, i);
+ *row_height = font->max_bounds.ascent + font->max_bounds.descent + row_space;
+}
+
+/*
+ * Get pagelist width.
+ */
+int
+xaw_get_pagelist_size(void)
+{
+ Widget w;
+ XFontStruct *font;
+
+ w = XtVaCreateWidget("list", listWidgetClass, globals.widgets.top_level, NULL);
+ XtVaGetValues(w, XtNfont, &font, NULL);
+ XtDestroyWidget(w);
+
+ /* have space for max. pageno + space + current-marker,
+ plus a few pixels for right margin */
+ return (get_page_size() + 2) * get_avg_font_width(font) + 6;
+}
+
+/* auto-scroll pagelist when mouse-1 is down and moved above top or below bottom of
+ page list.
+*/
+static void
+xaw_drag_page_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont)
+{
+ int y, idx, actual_idx = 0;
+
+ UNUSED(data);
+ UNUSED(cont);
+
+ if (event->xany.type == ButtonPress || ((event->xbutton.state & Button1Mask) == 0))
+ return;
+ if (event->xany.type == MotionNotify)
+ y = (int)event->xmotion.y;
+ else
+ y = (int)event->xbutton.y;
+
+ idx = get_item_index(widget, y);
+
+ if (idx <= 0) {
+ idx = 1;
+ }
+ else if (idx > total_pages) {
+ idx = total_pages;
+ }
+
+ actual_idx = xaw_maybe_scroll_pagelist(idx, False, actual_idx);
+ XawListHighlight(LIST_WIDGET, idx - MOTIF_IDX_OFFSET);
+
+/* if (event->xany.type == ButtonRelease) { */
+/* fprintf(stderr, "1\n"); */
+/* page_history_insert(idx - MOTIF_IDX_OFFSET); */
+/* goto_page(idx - MOTIF_IDX_OFFSET, resource.keep_flag ? NULL : home); */
+/* search_signal_page_changed(); */
+/* } */
+}
+
+static void
+xaw_SendReportProc(Widget w, XtPointer closure, XtPointer call_data)
+{
+ XawPannerReport *rep = (XawPannerReport *) call_data;
+
+ UNUSED(w);
+ UNUSED(closure);
+
+ view_y = rep->slider_y;
+}
+
+#endif /* not MOTIF */
+
+
+
+/* returns the index of the current item in `Motif'-style, i.e. first item has index 1, not 0 */
+static int
+get_item_index(Widget w, int mouse_y)
+{
+#ifdef MOTIF
+ return XmListYToPos(w, mouse_y);
+#else
+ Dimension row_height, internal_height;
+
+ xaw_get_row_height(w, &row_height, &internal_height);
+ return (mouse_y - internal_height) / row_height + MOTIF_IDX_OFFSET;
+#endif
+}
+
+#if !defined(LESSTIF_VERSION)
+/* idx is Motif-style index, i.e. 1 for 1st item, not 0 */
+static Boolean
+my_list_pos_to_bounds(Widget widget, int idx, Position *x, Position *y, Dimension *w, Dimension *h)
+{
+#ifdef MOTIF
+ Position x1, y1;
+ Dimension w1, h1;
+ if (XmListPosToBounds(widget, idx, &x1, &y1, &w1, &h1)) {
+ *x = x1;
+ *y = y1;
+ *w = w1;
+ *h = h1;
+ return True;
+ }
+ return False;
+#else
+ Dimension row_height, internal_height;
+ /* FIXME: Remove this hard-coded offset! */
+ const int X_OFFSET = 9;
+ const int RULE_OFFSET = 2;
+
+ if (idx <= 0 || idx > total_pages) {
+ return False;
+ }
+
+ if (viewport != NULL && XtIsRealized(viewport))
+ XtVaGetValues(viewport, XtNx, x, NULL);
+ xaw_get_row_height(widget, &row_height, &internal_height);
+ XtVaGetValues(widget, XtNwidth, w, NULL);
+
+ *x -= X_OFFSET;
+ *y = row_height * idx + internal_height - row_height - 1;
+ *w -= RULE_OFFSET;
+ *h = row_height + RULE_OFFSET;
+
+ return True;
+#endif
+}
+#endif /* !defined(LESSTIF_VERSION) */
+
+/* it seems that in order to support scrolling of the page list with wheel mice,
+ we need to program this explicitly.
+ */
+static void
+wheel_scroll_list_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont)
+{
+ int button = event->xbutton.button;
+
+ UNUSED(widget);
+ UNUSED(data);
+ UNUSED(cont);
+
+ if (event->xany.type == ButtonPress && (button == 4 || button == 5)) {
+#if SCROLL_LIST_SCROLLBAR
+ Widget vert = XtNameToWidget(viewport, "vertical");
+ static Dimension row_height = 0, dummy = 0;
+ int diff_y = 0;
+
+ if (row_height == 0)
+ xaw_get_row_height(LIST_WIDGET, &row_height, &dummy);
+
+ if (vert == NULL) {
+ XDVI_WARNING((stderr, "Couldn't get name of pagelist viewport widget!"));
+ return;
+ }
+ if (button == 5) {
+ diff_y = row_height;
+ }
+ else {
+ diff_y = -row_height;
+ }
+ XtCallCallbacks(vert, XtNscrollProc, (XtPointer)diff_y);
+#else
+ int pageno = current_page;
+ if (button == 5) {
+ if (current_page >= total_pages - 1) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Last page of DVI file");
+ return;
+ }
+ pageno++;
+ }
+ else {
+ if (current_page == 0) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "First page of DVI file");
+ return;
+ }
+ pageno--;
+ }
+ goto_page(check_goto_page(pageno), resource.keep_flag ? NULL : home, False);
+ search_signal_page_changed();
+#endif
+ }
+}
+
+
+#if !defined(LESSTIF_VERSION)
+/* draw a hightlight rectangle around the page the mouse is currently over, to
+ make e.g. marking easier.
+ */
+static void
+highlight_page_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont)
+{
+ int curr_idx = get_item_index(widget, event->xmotion.y);
+ Position x, y;
+ Dimension w, h;
+ static int idx_bak = -1;
+
+ UNUSED(data);
+ UNUSED(cont);
+
+ switch(event->xany.type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ /* might need to un-highlight previous one */
+ if (idx_bak >= 0 && idx_bak != curr_idx
+ && my_list_pos_to_bounds(widget, idx_bak, &x, &y, &w, &h)) {
+/* fprintf(stderr, "index: %d, %d, h: %d, w: %d\n", x, y, h, w); */
+ refresh_highlight_marker(widget, m_page_gc.back, x, y, w, h);
+#if REDRAW_CURRENT_MARKER_HACK
+ xaw_maybe_redraw_highlight(curr_idx);
+#endif
+ }
+ idx_bak = curr_idx;
+ /* redraw unless out of bounds (when pagelist is shorter than view area) */
+ if (my_list_pos_to_bounds(widget, curr_idx, &x, &y, &w, &h)) {
+ refresh_highlight_marker(widget, m_page_gc.fore, x, y, w, h);
+#if REDRAW_CURRENT_MARKER_HACK
+ g_current_highlighted = curr_idx;
+#endif
+ }
+ break;
+ case LeaveNotify:
+ /* this might look overly complicated, but is neccessary to cover all
+ cases of 1-pixel movement up/down before leaving the list, or no
+ movement at all before leaving it. */
+ if ((idx_bak >= 0 && idx_bak != curr_idx && my_list_pos_to_bounds(widget, idx_bak, &x, &y, &w, &h))
+ || my_list_pos_to_bounds(widget, curr_idx, &x, &y, &w, &h)) {
+ refresh_highlight_marker(widget, m_page_gc.back, x, y, w, h);
+#if REDRAW_CURRENT_MARKER_HACK
+ xaw_maybe_redraw_highlight(curr_idx);
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+}
+#endif /* !defined(LESSTIF_VERSION) */
+
+/*
+ * invoked on Button-1 Down.
+ */
+static void
+select_page_callback(Widget w, XtPointer closure, XtPointer call_data)
+{
+#ifdef MOTIF
+ XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
+ int new = cbs->item_position;
+
+ UNUSED(w);
+ UNUSED(closure);
+
+ maybe_scroll_pagelist(new - MOTIF_IDX_OFFSET, False);
+ page_history_insert(new - MOTIF_IDX_OFFSET);
+ goto_page(new - MOTIF_IDX_OFFSET, resource.keep_flag ? NULL : home, False);
+#else
+ XawListReturnStruct *item = (XawListReturnStruct *) call_data;
+ int new = item->list_index;
+
+ UNUSED(w);
+ UNUSED(closure);
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "got: button-1 for `%d'\n", new);
+
+#if 0
+ fprintf(stderr, "select page: %d\n", new);
+#endif
+ maybe_scroll_pagelist(new, False);
+ page_history_insert(new);
+ goto_page(new, resource.keep_flag ? NULL : home, False);
+#endif
+ search_signal_page_changed();
+}
+
+
+static void
+init_pagelabels(int start, int end)
+{
+ int i;
+ char s[PAGENUMLEN];
+#if 0
+ fprintf(stderr, "===== init_pagelabels from %d to %d\n", start, end);
+#endif
+ ASSERT(end < (int)page_info.index_size, "");
+
+ page_info.page_labels = xrealloc(page_info.page_labels, sizeof *(page_info.page_labels) * (end + 2));
+ for (i = start; i < end; i++) {
+ if (page_info.index[i].marked)
+ sprintf(s, "* %*d ", get_page_size(),
+ resource.use_tex_pages ? page_info.index[i].number : i + 1);
+ else
+ sprintf(s, " %*d ", get_page_size(),
+ resource.use_tex_pages ? page_info.index[i].number : i + 1);
+
+ page_info.page_labels[i] = xstrdup(s);
+ }
+ page_info.page_labels[i] = NULL; /* terminate - important for creating the widget. */
+}
+
+
+#ifdef MOTIF
+
+
+static int
+xm_get_top_visible(int start)
+{
+ int top = start;
+ while (top < total_pages && !XmListPosToBounds(LIST_WIDGET, top, NULL, NULL, NULL, NULL))
+ top++;
+ return top;
+}
+
+static int
+xm_get_bottom_visible(int start)
+{
+ int bot = start;
+ while (bot < total_pages && XmListPosToBounds(LIST_WIDGET, bot, NULL, NULL, NULL, NULL))
+ bot++;
+ bot--;
+ return bot;
+}
+
+/* Scroll pagelist down or up if needed, and update top_visible and
+ bot_visible. List is always scrolled so that 1 element is still
+ visible below or above pointer, to make it possible to flip through
+ document by repeatedly clicking on first/last.
+ */
+static void
+xm_maybe_scroll_pagelist(int current, saveCmdT curr_cmd, int *top_visible, int *bot_visible)
+{
+#if 0
+ fprintf(stderr, "topmost visible: %d, bottom: %d, current: %d, total: %d\n",
+ top_visible, bottom_visible, current, total_pages);
+#endif
+
+ if (current < *top_visible && curr_cmd != SCROLL_DOWN) {
+ XmListSetPos(LIST_WIDGET,
+ current < 1
+ ? 1
+ : current);
+ (*top_visible)--;
+ (*bot_visible)--;
+ }
+ else if (current + MOTIF_IDX_OFFSET >= *bot_visible && curr_cmd != SCROLL_UP) {
+ XmListSetBottomPos(LIST_WIDGET,
+ current + MOTIF_IDX_OFFSET >= total_pages
+ ? current + MOTIF_IDX_OFFSET
+ : current + MOTIF_IDX_OFFSET + 1);
+ (*top_visible)++;
+ (*bot_visible)++;
+ }
+}
+
+static void
+xm_set_page_labels(void)
+{
+ int i;
+ char buf[PAGENUMLEN];
+
+ XmString *motif_page_labels = xmalloc((total_pages + 2) * sizeof *motif_page_labels);
+
+ for (i = 0; i < total_pages; ++i) {
+ sprintf(buf, pageno_format, ' ', page_info.page_labels[i]);
+ motif_page_labels[i] = XmStringCreateLocalized(buf);
+ }
+ XmListDeleteAllItems(LIST_WIDGET);
+ XmListAddItems(LIST_WIDGET, motif_page_labels, total_pages, 0);
+
+ XmListSelectPos(LIST_WIDGET, current_page + MOTIF_IDX_OFFSET, False);
+ for (i = 0; i < total_pages; ++i) {
+ XmStringFree(motif_page_labels[i]);
+ }
+ free(motif_page_labels);
+}
+
+static void
+xm_toggle_label(Widget widget, int idx, Boolean update)
+{
+ /* TODO: use `update' to update all labels at once when toggling multiple */
+ XmString str;
+ char *mark_font, buf[128];
+
+ if (widget == NULL)
+ return;
+
+ UNUSED(update);
+
+/* ensure_labelinfo_size(idx); */
+ ASSERT(idx < (int)page_info.index_size, "");
+ if (!page_info.index[idx].marked) {
+ sprintf(buf, pageno_format, '*', page_info.page_labels[idx]);
+ mark_font = "MARKED";
+ page_info.index[idx].marked = True;
+ }
+ else {
+ sprintf(buf, pageno_format, ' ', page_info.page_labels[idx]);
+ mark_font = "UNMARKED";
+ page_info.index[idx].marked = False;
+ }
+/* str = XmStringCreateLocalized(buf); */
+ str = XmStringCreateLtoR(buf, mark_font);
+ XmListReplaceItemsPos(widget, &str, 1, idx + MOTIF_IDX_OFFSET);
+ XmStringFree(str);
+}
+
+
+#else /* MOTIF */
+
+static void
+mark_page_callback(Widget w, XtPointer data, XEvent *event, Boolean *cont)
+{
+ UNUSED(data);
+ UNUSED(cont);
+
+ /* moving button2 generates MotionNotify events for button0 */
+ if (event->type == MotionNotify || event->xbutton.button == Button2)
+ internal_process_button2(w, event);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+
+}
+
+void
+xaw_create_pagelist_widgets(Dimension height, Dimension width, Position y, Widget parent)
+{
+ viewport = XtVaCreateWidget("viewport",
+ viewportWidgetClass, parent,
+ XtNallowVert, True,
+ /* this is not related to the scroll bar: */
+ /* XtNforceBars, True, */
+ XtNx, resource.btn_side_spacing,
+ XtNy, y,
+ XtNheight, height,
+ XtNwidth, width,
+ NULL);
+ LIST_WIDGET = XtVaCreateWidget("list",
+ listWidgetClass, viewport,
+ XtNlist, page_info.page_labels,
+ XtNdefaultColumns, 1,
+ XtNforceColumns, True,
+ XtNx, 10,
+ XtNy, 10,
+ XtNheight, height,
+ XtNwidth, width - 10,
+ XtNlongest, LONGESTPAGENUM,
+ XtNverticalList, True,
+ NULL);
+ XtManageChild(LIST_WIDGET);
+ XtManageChild(viewport);
+ XtAddCallback(LIST_WIDGET, XtNcallback, select_page_callback,
+ (XtPointer) NULL);
+ /* for scrolling the list */
+ XtAddCallback(viewport, XtNreportCallback, xaw_SendReportProc,
+ (XtPointer) NULL);
+ XtAddEventHandler(LIST_WIDGET,
+ ButtonPressMask | ButtonReleaseMask | Button2MotionMask,
+ False, mark_page_callback, (XtPointer)NULL);
+
+ if (resource.pagelist_highlight_current)
+ XtAddEventHandler(LIST_WIDGET,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask,
+ False, highlight_page_callback, (XtPointer)NULL);
+
+
+ XtAddEventHandler(LIST_WIDGET, ButtonPressMask | ButtonReleaseMask,
+ False, wheel_scroll_list_callback, (XtPointer)NULL);
+
+
+ XtAddEventHandler(LIST_WIDGET,
+ /* FIXME: We should add PointerMotionMask here, but handling PointerMotionMask
+ currently doesn't work with the Xaw list widget: the auto-scrolling code doesn't
+ realize when the mouse direction of the pointer movement changes, and continues
+ to scroll into the same direction. This will be rather annoying for users, so
+ we disabled PointerMotionMask for the time being.
+ */
+ ButtonReleaseMask /* | PointerMotionMask */ | Button1MotionMask,
+ False, xaw_drag_page_callback, (XtPointer)NULL);
+}
+
+static void
+xaw_toggle_label(Widget w, int idx, Boolean update)
+{
+ if (w == NULL)
+ return;
+
+/* ensure_labelinfo_size(idx); */
+ ASSERT(idx < (int)page_info.index_size, "");
+ if (!page_info.index[idx].marked) {
+/* sprintf(toc[idx], "* %*d ", get_page_size(), page_index[idx].number); */
+ sprintf(page_info.page_labels[idx], pageno_format, '*', get_page_size(),
+ resource.use_tex_pages ? page_info.index[idx].number : idx + 1);
+ page_info.index[idx].marked = True;
+ }
+ else {
+ sprintf(page_info.page_labels[idx], pageno_format, ' ', get_page_size(),
+ resource.use_tex_pages ? page_info.index[idx].number : idx + 1);
+/* sprintf(toc[idx], " %*d ", get_page_size(), page_index[idx].number); */
+ page_info.index[idx].marked = False;
+ }
+
+ if (update)
+ xaw_update_list();
+}
+
+static int
+xaw_maybe_scroll_pagelist(int new_page, Boolean force_recenter, int idx_bak)
+{
+ Position x;
+ Position y, new_y, bot_y;
+ Dimension view_height, row_height, internal_height;
+ /* Dimension clip_height; */
+ /* static Widget list_clip = 0; */
+
+ if (LIST_WIDGET == NULL || (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0)
+ return idx_bak;
+
+/* if (list_clip == 0) { */
+/* list_clip = XtNameToWidget(viewport, "clip"); */
+/* } */
+/* if (XtIsRealized(list_clip)) */
+/* XtVaGetValues(list_clip, XtNheight, &clip_height, XtNx, &cx, XtNy, &y1, NULL); */
+ if (viewport != NULL && XtIsRealized(viewport))
+ XtVaGetValues(viewport, XtNheight, &view_height, XtNx, &x, NULL);
+/* fprintf(stderr, "diff: %d, %d, %d, %d, %d\n", cx - x, clip_height, view_height, y1, (int)y2); */
+ xaw_get_row_height(LIST_WIDGET, &row_height, &internal_height);
+ y = row_height * new_page;
+
+#if DEBUG
+ fprintf(stderr, "###### xaw_maybe_scroll_pagelist: y %d, view_y %d, view_height %d, row_height %d, internal_height %d; actual %d\n",
+ y, view_y, view_height, row_height, internal_height, idx_bak);
+#endif
+ /*FIXME: when page list is destroyed, view_y will be 0 until user scrolls page list */
+ bot_y = view_y + view_height;
+ if (force_recenter || ((y >= bot_y - row_height))) {
+#if DEBUG
+ fprintf(stderr, "scrolled below bottom; incrementing %d to %d\n", view_y, view_y + row_height);
+#endif
+ y += row_height;
+ XawViewportSetCoordinates(viewport, x, y - view_height > 0 ? y - view_height : 0);
+ return new_page + 1;
+ }
+ else if (force_recenter || ((y <= view_y + row_height + internal_height))) {
+#if DEBUG
+ fprintf(stderr, "scrolled over top; new_y: %d\n", y - row_height);
+#endif
+ new_y = y - 2 * row_height;
+ XawViewportSetCoordinates(viewport, x, new_y);
+ return new_page - 1;
+ }
+ /* not scrolled */
+ return -2;
+}
+
+#endif /* MOTIF */
+
+
+/* idx is C-style index (0-based), not Motif one (1-based) */
+static void
+toggle_label(Widget widget, int idx, Boolean update)
+{
+ if (idx >= total_pages)
+ return;
+ ASSERT(idx < total_pages, "");
+ ASSERT(idx >= 0, "");
+#ifdef MOTIF
+ xm_toggle_label(widget, idx, update);
+#else
+ xaw_toggle_label(widget, idx, update);
+#endif
+}
+
+
+void
+list_toggle_marks(int arg)
+{
+
+ int i;
+
+ if (arg < 0) { /* mark all */
+ for (i = 0; i < total_pages; i++) {
+ ASSERT(i < (int)page_info.index_size, "");
+/* ensure_labelinfo_size(i); */
+ if (!page_info.index[i].marked) {
+ toggle_label(LIST_WIDGET, i, False);
+ }
+ }
+ }
+ else if (arg == 0) { /* unmark all */
+ for (i = 0; i < total_pages; i++) {
+ ASSERT(i < (int)page_info.index_size, "");
+/* ensure_labelinfo_size(i); */
+ if (page_info.index[i].marked) {
+ toggle_label(LIST_WIDGET, i, False);
+ }
+ }
+ }
+ else { /* toggle odd/even */
+ if (arg == 2) /* toggle even */
+ arg = 0;
+ for (i = 0; i < total_pages; i++) {
+ if ((i + 1) % 2 == arg) {
+ toggle_label(LIST_WIDGET, i, False);
+ }
+ }
+ }
+ /* TODO: update widget once for Motif as well! */
+#ifndef MOTIF
+ xaw_update_list();
+#endif
+}
+
+static Boolean PagelistInitialized = False;
+
+#ifndef MOTIF
+void
+handle_pagelist_resize(void)
+{
+ /* TODO: the following will mess up the geometry of the list
+ (doesn't increase height, and incrementally decreases width):
+ if (list_widget) {
+ Dimension height;
+ --- without the (un)manage, I get an X Error:
+ XtMakeGeometryRequest - parent has no geometry manager
+ ---
+ XtUnmanageChild(viewport);
+ XtUnmanageChild(LIST_WIDGET);
+ XtVaGetValues(globals.widgets.clip_widget, XtNheight, &height, NULL);
+ height -= resource.btn_top_spacing + resource.btn_border_width + global_y_pos;
+ XtVaSetValues(viewport, XtNheight, height, NULL);
+ XtManageChild(LIST_WIDGET);
+ XtManageChild(viewport);
+ }
+ ... so we use brute force instead: */
+ handle_destroy_pagelist(LIST_WIDGET, NULL, NULL);
+ create_pagelist();
+}
+
+void
+handle_destroy_pagelist(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (viewport != NULL) {
+ XtDestroyWidget(viewport);
+ viewport = NULL;
+ LIST_WIDGET = NULL;
+ }
+ PagelistInitialized = False;
+}
+#endif /* MOTIF */
+
+void
+create_pagelist(void)
+{
+ Pixel background, foreground;
+#ifdef MOTIF
+
+/* items = xrealloc(items, sizeof *items * (total_pages + 2)); */
+ init_pagelabels(0, total_pages);
+ xm_set_page_labels();
+ if (!PagelistInitialized) {
+ XtAppContext app;
+
+ XtVaGetValues(LIST_WIDGET, XmNforeground, &foreground, XmNbackground, &background, NULL);
+ m_page_gc.back = set_or_make_gc(NULL, GXcopy, background, foreground);
+ m_page_gc.fore = set_or_make_gc(NULL, GXcopy, foreground, background);
+ XtManageChild(LIST_WIDGET);
+
+ XtAddCallback(LIST_WIDGET, XmNbrowseSelectionCallback, select_page_callback, NULL);
+#if !defined(LESSTIF_VERSION)
+ /*
+ Don't use the highlighting hack with LessTif, since its XmListPosToBounds()
+ is too broken to be usable (as of 0.93.36):
+ - it returns generally too low values, apparently it doesn't take
+ XmNlistSpacing into account;
+ - it doesn't take scrollbar position into account.
+ */
+ if (resource.pagelist_highlight_current)
+ XtAddEventHandler(LIST_WIDGET,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask,
+ False, highlight_page_callback, (XtPointer)NULL);
+#endif /* !defined(LESSTIF_VERSION) */
+ XtAddEventHandler(LIST_WIDGET, ButtonPressMask | ButtonReleaseMask,
+ False, wheel_scroll_list_callback, (XtPointer)NULL);
+
+ app = XtWidgetToApplicationContext(globals.widgets.top_level);
+ XtAppAddActions(app, CustomListActions, XtNumber(CustomListActions));
+ XtOverrideTranslations(LIST_WIDGET, XtParseTranslationTable(motif_custom_translations));
+ PagelistInitialized = True;
+ }
+#else /* MOTIF */
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
+ PagelistInitialized = False; /* might need to re-create widgets in this case */
+ return;
+ }
+
+ if (globals.debug & DBG_GUI)
+ fprintf(stderr, "allocating list with %d pages\n", total_pages);
+
+ init_pagelabels(0, total_pages);
+ if (!PagelistInitialized) {
+ xaw_create_pagelist();
+ XtVaGetValues(LIST_WIDGET, XtNforeground, &foreground, XtNbackground, &background, NULL);
+ m_page_gc.back = set_or_make_gc(NULL, GXcopy, background, foreground);
+ m_page_gc.fore = set_or_make_gc(NULL, GXcopy, foreground, background);
+ PagelistInitialized = True;
+ }
+#endif /* MOTIF */
+ /* scroll to the current page if needed */
+ maybe_scroll_pagelist(current_page, False);
+}
+
+#ifndef MOTIF
+static void
+free_pagelabels(void)
+{
+ int i;
+ for (i = 0; page_info.page_labels != NULL && page_info.page_labels[i] != NULL; i++) {
+ free(page_info.page_labels[i]);
+ }
+ free(page_info.page_labels);
+ page_info.page_labels = NULL;
+}
+#endif /* not MOTIF */
+
+
+void
+refresh_pagelist(int newsize, int newpage)
+{
+ if (
+#ifndef MOTIF
+ (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0 ||
+#endif
+ !XtIsRealized(globals.widgets.top_level))
+ return;
+
+#ifdef DEBUG
+ fprintf(stderr, "=== refresh_pagelist: newsize %d, newpage %d\n", newsize, newpage);
+#endif
+#ifdef MOTIF
+/* items = xrealloc(items, sizeof *items * (newsize + 2)); */
+ init_pagelabels(0, newsize);
+ xm_set_page_labels();
+#else /* MOTIF */
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0)
+ return;
+
+ /* FIXME - is this really neccessary?? The alternative:
+ XawListChange(LIST_WIDGET, page_info.page_labels, newsize, 0, True);
+ has problems when freeing the page labels afterwards.
+ */
+ handle_destroy_pagelist(LIST_WIDGET, NULL, NULL);
+
+ free_pagelabels();
+ init_pagelabels(0, newsize);
+
+ xaw_create_pagelist();
+#endif /* MOTIF */
+ /* `True' since the pagelist is newly created */
+ maybe_scroll_pagelist(newpage, True);
+}
+
+void
+maybe_scroll_pagelist(int newpage, Boolean force_recenter)
+{
+#ifdef MOTIF
+ int top_visible, bot_visible;
+ UNUSED(force_recenter);
+#endif
+
+ if (
+#ifndef MOTIF
+ (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0 ||
+#endif
+ !XtIsRealized(globals.widgets.top_level))
+ return;
+
+#ifdef MOTIF
+ XmListSelectPos(LIST_WIDGET, newpage + MOTIF_IDX_OFFSET, False);
+
+ top_visible = xm_get_top_visible(1);
+ bot_visible = xm_get_bottom_visible(top_visible);
+
+ xm_maybe_scroll_pagelist(newpage, CLICK, &top_visible, &bot_visible);
+#if HAVE_XPM
+ tb_check_navigation_sensitivity(current_page);
+#endif
+#else
+
+ if (LIST_WIDGET == NULL)
+ return;
+
+ (void)xaw_maybe_scroll_pagelist(newpage + 1, force_recenter, 0);
+
+ XawListHighlight(LIST_WIDGET, newpage);
+#if REDRAW_CURRENT_MARKER_HACK
+ /* if the XawListHighlight happens adjacent to the page that was
+ last highlighted with our home-made `current selected'
+ rectangle, it might overdraw that rectangle. In this case,
+ restore it:
+ */
+ xaw_maybe_redraw_current_marker(newpage);
+#endif
+#endif
+}
+
+#ifdef MOTIF
+static void
+set_all_marks(int from, int to)
+{
+ int i;
+ for (i = from; i < to; i++) {
+/* ensure_labelinfo_size(i); */
+ page_info.index[i].marked = True;
+ toggle_label(LIST_WIDGET, i, False);
+ }
+}
+
+static void
+internal_process_button2_drag(Widget widget, XEvent *event)
+{
+ int i, idx, min = total_pages, max = 0;
+ idx = get_item_index(widget, event->xbutton.y);
+
+ for (i = 0; i < total_pages; i++) {
+/* ensure_labelinfo_size(i); */
+ if (page_info.index[i].marked && i > max)
+ max = i;
+ }
+ for (i = total_pages; i > 0; i--) {
+/* ensure_labelinfo_size(i); */
+ if (page_info.index[i].marked && i < min)
+ min = i;
+ }
+
+ if (min == total_pages)
+ min = 0;
+ if (max == 0)
+ max = total_pages;
+
+ if (idx < min) {
+ set_all_marks(idx, min);
+ }
+ else if (idx > max) {
+ set_all_marks(max + 1, idx);
+ }
+ else {
+ set_all_marks(0, idx);
+ }
+}
+#endif /* MOTIF */
+
+static void
+internal_process_button2(Widget widget, XEvent *event)
+{
+ int curr_idx;
+ static int prev_idx = 0;
+#ifndef MOTIF
+ static int actual_idx = -2;
+#endif
+ static int top_visible = 0, bot_visible = 0;
+ static int prev_y = 0, curr_y = 0;
+ static saveCmdT prev_cmd = 0; /* previous command (CLICK/SCROLL_UP/SCROLL_DOWN) */
+ static saveCmdT curr_cmd = 0; /* current command (CLICK/SCROLL_UP/SCROLL_DOWN) */
+ static saveCmdT bak_cmd = 0; /* last command that started inside the pagelist (CLICK/SCROLL_UP/SCROLL_DOWN) */
+ static Boolean change_scroll_direction = False;
+
+ switch(event->xany.type) {
+ case ButtonPress:
+ prev_y = event->xbutton.y;
+ prev_idx = curr_idx = get_item_index(widget, prev_y);
+#ifdef MOTIF
+ top_visible = xm_get_top_visible(1);
+ bot_visible = xm_get_bottom_visible(top_visible);
+#endif
+ toggle_label(widget, curr_idx - 1, True);
+ prev_cmd = CLICK;
+#ifdef MOTIF
+ xm_maybe_scroll_pagelist(curr_idx - 1, CLICK, &top_visible, &bot_visible);
+#else
+ actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx);
+#endif
+ break;
+ case ButtonRelease:
+ prev_cmd = CLICK;
+ break;
+ case MotionNotify:
+ curr_y = (int)event->xmotion.y;
+ curr_idx = get_item_index(widget, event->xmotion.y);
+#ifndef MOTIF
+ if (actual_idx > 0) {
+ curr_idx = actual_idx;
+ }
+#endif
+
+ if (curr_y < prev_y)
+ curr_cmd = SCROLL_UP;
+ else if (curr_y > prev_y)
+ curr_cmd = SCROLL_DOWN;
+ prev_y = curr_y;
+
+ if (prev_cmd != CLICK && curr_cmd != prev_cmd)
+ change_scroll_direction = True;
+
+ if ((curr_idx != prev_idx && !change_scroll_direction)
+ || (change_scroll_direction
+ /* last or first visible are always spared, unless they are really
+ the first or last page; this way, always 1 more page is visible
+ than is currently marked/selected
+ */
+ && !(curr_idx == top_visible) && !(curr_idx == bot_visible))) {
+ if (curr_idx <= 0) {
+ /* When user has scrolled off, mark this by setting curr_idx to 1 more or less
+ than the pagelist has so that the last/first page don't oscillate between
+ marked/unmarked state when user continues to scroll.
+ Also, we continue scrolling as long as user drags in the same direction as
+ the last `real' scrolling event (saved as bak_cmd).
+ */
+ if (curr_cmd == SCROLL_DOWN && bak_cmd == SCROLL_DOWN && prev_idx <= total_pages) {
+ curr_idx = prev_idx + 1;
+ }
+ else if (curr_cmd == SCROLL_UP && bak_cmd == SCROLL_UP && prev_idx > 0) {
+ curr_idx = prev_idx - 1;
+ }
+ }
+
+
+ if (curr_idx > 0 && curr_idx <= total_pages) {
+ toggle_label(widget, curr_idx - 1, True);
+#ifdef MOTIF
+ xm_maybe_scroll_pagelist(curr_idx - 1, curr_cmd, &top_visible, &bot_visible);
+#else
+ actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx);
+#endif
+ prev_idx = curr_idx;
+ bak_cmd = curr_cmd;
+ change_scroll_direction = False;
+ }
+ else {
+#ifndef MOTIF
+ if (curr_idx > total_pages)
+ actual_idx = -2;
+ else
+ actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx);
+#endif
+ }
+ prev_cmd = curr_cmd;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+list_toggle_current(int arg)
+{
+ toggle_label(LIST_WIDGET, arg, True);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+}
+
+#ifdef MOTIF
+
+static void
+xm_list_set_mark(Widget widget,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ UNUSED(params);
+
+ if ((*num_params != 1) || !XmIsList(widget))
+ return;
+
+ internal_process_button2(widget, event);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+}
+
+static void
+xm_list_drag_mark(Widget widget,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ UNUSED(params);
+
+ if ((*num_params != 1) || !XmIsList(widget))
+ return;
+
+ internal_process_button2_drag(widget, event);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+}
+
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/pagesel.h b/Build/source/texk/xdvik/gui/pagesel.h
new file mode 100644
index 00000000000..aad1b591456
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/pagesel.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * Page selector for xdvi
+ *
+ * Copyright (c) 1993, 1995
+ * MATSUURA Syun syun@fuka.info.waseda.ac.jp
+ * HIRAHARA Atsushi hirahara@fuka.info.waseda.ac.jp
+ * ONO Kouichi onono@fuka.info.waseda.ac.jp
+ *
+ * All rights reserved.
+ */
+
+/* SU: I was unsure how to interpret the `All rights reserved' in the
+ * previous line, so emailed Ono Kouichi about this. Here's (the
+ * relevant part of) his answer (which was CC'ed to Hirahara Atsushi -
+ * all three of them had left Waseda university around '95):
+ *
+ * You can modify, embed, copy and distribute a part of or the
+ * entire of our source code when you specify our copyright in your
+ * xdvik version.
+ *
+ * IANAL, but I think this is compatible with the X consortium
+ * license as specified in the other files.
+ */
+
+#ifndef PAGESEL_H_
+#define PAGESEL_H_
+
+#include "xdvi.h"
+
+extern void refresh_pagelist(int newsize, int newpage);
+extern void maybe_scroll_pagelist(int newpage, Boolean force_recenter);
+extern void create_pagelist(void);
+extern void list_toggle_current(int arg);
+extern void list_toggle_marks(int arg);
+
+# ifdef MOTIF
+extern Widget page_list;
+extern void toggle_pagelist(void);
+# else
+extern int xaw_get_pagelist_size(void);
+extern void xaw_create_pagelist_widgets(Dimension height, Dimension width, Position y, Widget parent);
+extern void handle_destroy_pagelist(Widget w, XtPointer client_data, XtPointer call_data);
+extern void handle_pagelist_resize(void);
+# endif
+
+/* pageinfo access methods */
+extern long pageinfo_get_offset(int page);
+extern int pageinfo_get_number(int page);
+extern int pageinfo_get_index_of_number(int number);
+
+extern unsigned int pageinfo_get_page_width(int page);
+extern unsigned int pageinfo_get_page_height(int page);
+extern unsigned int pageinfo_get_window_width(int page);
+extern unsigned int pageinfo_get_window_height(int page);
+
+extern void pageinfo_set_page_width(int page, unsigned int width);
+extern void pageinfo_set_page_height(int page, unsigned int height);
+extern void pageinfo_set_window_width(int page, unsigned int width);
+extern void pageinfo_set_window_height(int page, unsigned int height);
+
+extern void pageinfo_set_offset(int index, long offset);
+extern void pageinfo_set_number(int index, int number);
+
+extern void pageinfo_allocate(int total_pages);
+extern void pageinfo_deallocate(void);
+extern Boolean pageinfo_is_marked(int i);
+extern Boolean pageinfo_have_marked_pages(void);
+
+#endif /* PAGESEL_H_ */
diff --git a/Build/source/texk/xdvik/gui/print-dialog.c b/Build/source/texk/xdvik/gui/print-dialog.c
new file mode 100644
index 00000000000..c7187be6100
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-dialog.c
@@ -0,0 +1,2973 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ */
+
+/*
+ SU: Adapted from non-k xdvi's popups.c
+
+ This implements a print popup (and a `save to file' popup). My idea
+ was to use the same window layout framework for both tasks, since
+ there's a big overlap in the widgets needed. However after looking
+ at the mess I've created, I'm no longer convinced this was a good
+ idea. (I reckon it's slightly better than the code duplication when
+ doing it in separate files, but only *slightly* ...)
+
+ We need a more intelligent approach that bans this ugly kind of
+ `data proliferation' (those global arrays of widgets and helper
+ structures). Custom Widgets? Factory methods? Needs investigation.
+
+ Also, in the long run, I guess we want the `Save' window to be more
+ similar to the file browser (i.e. to contain a file browser e.g.
+ in the upper part); in that case, the code will be moved into another
+ module anyway.
+
+ Moreover, the GUI code should be completely separated from the backend
+ code.
+*/
+
+#include <string.h>
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "my-vsnprintf.h"
+#include <ctype.h>
+
+#include "print-dialog.h"
+#include "print-log.h"
+#include "print-internal.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "string-utils.h"
+#include "util.h"
+#include "x_util.h"
+#include "message-window.h"
+#include "pagesel.h"
+#include "my-snprintf.h"
+#include "sfSelFile.h"
+#include "dvisel.h" /* for select_marked_pages() */
+#include "xlwradio.h"
+#include "statusline.h"
+#include "search-dialog.h"
+#include "search-internal.h"
+#include "special.h"
+
+/* Xlib and Xutil are already included */
+
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#ifdef MOTIF
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/PanedW.h>
+# include <Xm/MessageB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#define XTranslations XmNtranslations
+#else /* MOTIF */
+# include <X11/Shell.h>
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+# include <X11/Xaw/SimpleMenu.h>
+# include <X11/Xaw/MenuButton.h>
+# include <X11/Xaw/Sme.h>
+# include <X11/Xaw/SmeBSB.h>
+#if 0
+#include "xaw_bitmaps.h"
+static Pixmap menu_double_arrow_bitmap;
+#endif
+#define XTranslations XtNtranslations
+#endif /* MOTIF */
+
+struct output_format_mapping {
+ const char *fmt_string;
+ outputFormatT fmt;
+ const char *extension;
+} output_format_mapping[] = {
+ { "Postscript", FMT_PS , ".ps" },
+ { "PDF", FMT_PS2PDF, ".pdf" },
+ { "DVI", FMT_DVI, ".dvi" },
+ { "Plain Text (ISO_8859-1)",FMT_ISO_8859_1, ".txt" },
+ { "Plain Text (UTF-8)", FMT_UTF8, ".txt" },
+ { NULL, FMT_NONE, NULL }
+};
+
+typedef enum printRadioT_ {
+ NO_PRINT_VAL = -1,
+ PRINT_TO_PRINTER = 1,
+ PRINT_TO_FILE,
+ SAVE_TO_FILE
+} printRadioT;
+
+
+typedef enum pageRadioT_ {
+ NO_PAGE_VAL = -1,
+ PRINT_ALL = 1,
+ PRINT_MARKED,
+ PRINT_RANGE,
+ SAVE_ALL,
+ SAVE_MARKED,
+ SAVE_RANGE
+} pageRadioT;
+
+static Boolean is_print_button(pageRadioT flag) {
+ return (flag <= PRINT_RANGE);
+}
+
+struct dialog_info {
+ char *printer_name;
+ char *file_name;
+ /* fully canonicalized filename, not visible in window, but used in error messages.
+ It is either NULL, or a malloc()ed buffer (which is free()d immediately before use). */
+ char *expanded_filename;
+ char *dvips_options;
+ char *from_page;
+ char *to_page;
+ printRadioT print_radio;
+ pageRadioT range_radio;
+ outputFormatT output_format;
+};
+
+/*
+ global widgets, and arrays of global widgets (mosly, one
+ for the printing and one for the saving dialog). Needs
+ cleanup!
+*/
+
+#define FORMAT_SEL_CNT 5
+
+/* top-level widgets: one for printing, one for saving to file */
+static Widget print_shell = NULL;
+static Widget save_shell = NULL;
+
+/* global structures for saving print info between invocations */
+static struct dialog_info save_pr_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NO_PRINT_VAL, NO_PAGE_VAL, FMT_NONE
+};
+static struct dialog_info save_save_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NO_PRINT_VAL, NO_PAGE_VAL, FMT_NONE
+};
+
+/*
+ these contain the currently selected values, or defaults;
+ used in communication between callbacks
+*/
+static struct dialog_info curr_pr_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, PRINT_TO_PRINTER, PRINT_ALL, FMT_NONE
+};
+static struct dialog_info curr_save_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, SAVE_TO_FILE, SAVE_ALL, FMT_NONE
+};
+
+static void print_precheck1(XtPointer info);
+static void print_precheck2(XtPointer info);
+
+/* access methods ... */
+const char *
+get_printer_options(void)
+{
+ return save_pr_info.printer_name;
+}
+
+char *
+get_dvips_options(printOrSaveActionT act)
+{
+ if (act == FILE_PRINT)
+ return save_pr_info.dvips_options;
+ else
+ return save_save_info.dvips_options;
+}
+
+#ifdef MOTIF
+static Widget from_label[FILE_ALL] = { None, None };
+static Widget format_selection_option;
+XmString format_selection_texts[FORMAT_SEL_CNT];
+
+#else /* MOTIF */
+
+static Widget format_selection_label;
+static Widget format_selection_button;
+#if 0
+static Widget format_selection_b1;
+#endif
+static Widget format_selection_popup;
+static Widget format_selection_menu[FORMAT_SEL_CNT];
+
+static void xaw_print_save_act_go(Widget, XEvent *, String *, Cardinal *);
+
+#endif /* MOTIF */
+
+static void print_cancel(Widget, XEvent *, String *, Cardinal *);
+static void save_cancel(Widget, XEvent *, String *, Cardinal *);
+
+static Widget to_printer_radio;
+static Widget to_file_radio_or_label[FILE_ALL] = { None, None };
+static Widget to_label[FILE_ALL] = { None, None };
+static Widget of_label[FILE_ALL] = { None, None };
+static Widget range_all_radio[FILE_ALL] = { None, None };
+static Widget range_marked_radio[FILE_ALL] = { None, None };
+static Widget range_from_to_radio[FILE_ALL] = { None, None };
+static Widget cancel_button[FILE_ALL] = { None, None };
+static Widget ok_button[FILE_ALL] = { None, None };
+static Widget print_to_printer_text;
+static Widget print_to_file_text[FILE_ALL] = { None, None };
+static Widget print_to_file_button[FILE_ALL] = { None, None };
+static Widget dvips_options_text[FILE_ALL] = { None, None };
+static Widget page_from_text[FILE_ALL] = { None, None };
+static Widget page_to_text[FILE_ALL] = { None, None };
+
+static int print_is_active = False; /* False if window is unmanaged or not created yet, True if managed */
+static int save_is_active = False; /* False if window is unmanaged or not created yet, True if managed */
+
+
+static XtActionsRec print_actions[] = {
+#ifndef MOTIF
+ {"saveInternal", xaw_print_save_act_go },
+ {"printInternal", xaw_print_save_act_go},
+#endif
+ {"WM_print_cancel", print_cancel },
+ {"WM_save_cancel", save_cancel },
+};
+
+/*
+ ============================================================
+ generic utility functions
+ ============================================================
+*/
+
+/*
+ Return the printer name, eventually followed by `-P$PRINTER',
+ since the `-o' option of dvips doesn't evaluate the environment
+ variable.
+*/
+static char *
+get_printer_name(void)
+{
+ char *printcmd, *printer;
+
+ if (resource.dvips_printer_str != NULL && strlen(resource.dvips_printer_str) > 0) {
+ return xstrdup(resource.dvips_printer_str);
+ }
+ printcmd = xstrdup("lpr");
+ printer = getenv("PRINTER");
+ if (printer != NULL) {
+ printcmd = xstrcat(printcmd, " -P");
+ printcmd = xstrcat(printcmd, printer);
+ }
+ return printcmd;
+}
+
+/* return basename of `old_name' with `old_ext' replaced by `new_ext', in fresh memory */
+static char *
+get_new_file_name(const char *old_name, const char *old_ext, const char *new_ext)
+{
+ /* old_name contains the normalized DVI file name, with path and extension */
+ char *basename, *new_name;
+ size_t len;
+
+ basename = strrchr(old_name, DIR_SEPARATOR);
+
+ if (basename != NULL) {
+ basename++;
+ new_name = xmalloc(strlen(basename) + strlen(new_ext) + 1);
+ new_name = strcpy(new_name, basename);
+ }
+ else {
+ new_name = xmalloc(strlen(old_name) + strlen(new_ext) + 1);
+ new_name = strcpy(new_name, old_name);
+ }
+
+ len = strlen(new_name);
+ strcpy(new_name + len - strlen(old_ext), new_ext);
+ return new_name;
+}
+
+/*
+ * Translate `non-standard' paper sizes for xdvi into options suitable
+ * for dvips. We don't do this always, since it would override the papersize
+ * specials inserted by e.g.
+ * \usepackage[dvips]{geometry}
+ * which is the preferred way to specify the papersize. If the papersize
+ * has been explicitly set by such a special, this function returns NULL.
+ * Else it returns the value of the `paper' resource, without the trailing
+ * `r', and sets the `landscape' argument to True if a trailing `r' was
+ * present.
+ *
+ * Note that we don't check/warn about whether the current paper
+ * resource is valid for dvips; dvips will ignore invalid paper sizes.
+ */
+static char *
+get_dvips_papersize(Boolean *landscape)
+{
+ char *papersize;
+ if (have_papersize_special())
+ return NULL;
+
+ papersize = xstrdup(resource.paper);
+ *landscape = False;
+ if (papersize[strlen(papersize) - 1] == 'r') { /* landscape size */
+ papersize[strlen(papersize) - 1] = '\0';
+ *landscape = True;
+ }
+ TRACE_GUI((stderr, "Using dvips arguments: `%s', %s", papersize, *landscape ? "landscape" : "portrait"));
+ return papersize;
+}
+
+static void
+set_outfile_name(struct dialog_info *info, struct dialog_info *save_info, printOrSaveActionT act)
+{
+ free(info->file_name);
+ if (act == FILE_PRINT) {
+ info->file_name = get_new_file_name(globals.dvi_name, ".dvi", ".ps");
+ }
+ else { /* saving to file */
+ if (save_info->range_radio == SAVE_ALL) {
+ info->file_name = get_new_file_name(globals.dvi_name, ".dvi",
+ output_format_mapping[resource.default_saving_format].extension);
+ }
+ else {
+ char *tmp = xstrdup("_pp");
+ tmp = xstrcat(tmp, output_format_mapping[resource.default_saving_format].extension);
+
+ info->file_name = get_new_file_name(globals.dvi_name, ".dvi", tmp);
+ free(tmp);
+ }
+ }
+}
+
+/* get initial values for dialog texts */
+static void
+get_initial_dialog_values(struct dialog_info *info, printOrSaveActionT act)
+{
+ if (act == FILE_PRINT && info->printer_name == NULL)
+ info->printer_name = get_printer_name();
+
+ if (info->dvips_options == NULL) {
+ info->dvips_options = xstrdup("");
+
+ /* add -t option if not already present */
+ if (resource.dvips_options_str != NULL
+ && strstr(resource.dvips_options_str, "-t ") == NULL) {
+ Boolean dvips_landscape = False;
+ char *dvips_paper_size = get_dvips_papersize(&dvips_landscape);
+ if (dvips_paper_size != NULL) {
+ info->dvips_options = xstrdup("-t ");
+ info->dvips_options = xstrcat(info->dvips_options, dvips_paper_size);
+ free(dvips_paper_size);
+ if (dvips_landscape) {
+ info->dvips_options = xstrcat(info->dvips_options, " -t landscape");
+ }
+ }
+ }
+
+ if (resource.dvips_options_str != NULL) {
+ if (strlen(info->dvips_options) > 0)
+ info->dvips_options = xstrcat(info->dvips_options, " ");
+ info->dvips_options = xstrcat(info->dvips_options, resource.dvips_options_str);
+ }
+ }
+
+ if (info->from_page == NULL) {
+ info->from_page = xmalloc(LENGTH_OF_INT + 1);
+ sprintf(info->from_page, "%d", current_page + globals.pageno_correct);
+ }
+
+ if (info->to_page == NULL) {
+ info->to_page = xmalloc(LENGTH_OF_INT + 1);
+ sprintf(info->to_page, "%d", current_page + globals.pageno_correct);
+ }
+}
+
+
+#if MOTIF
+static void
+set_sensitivity(int i)
+{
+ Boolean sensitivity;
+
+/* if (i == curr_pr_info.print_radio) /\* if no change *\/ */
+/* return; */
+
+ curr_pr_info.print_radio = i;
+
+ sensitivity = (i == PRINT_TO_PRINTER);
+ XtSetSensitive(print_to_printer_text, sensitivity);
+
+/* sensitivity ^= (True ^ False); */
+ XtSetSensitive(print_to_file_text[FILE_PRINT], !sensitivity);
+ XtSetSensitive(print_to_file_button[FILE_PRINT], !sensitivity);
+}
+#endif /* MOTIF */
+
+static void
+update_dvips_options_sensitivity(int idx, Widget top)
+{
+ Widget dvips_label;
+
+#if MOTIF
+ Widget dvips_options;
+
+ if (get_widget_by_name(&dvips_label, top, "dvips_options_name", True) &&
+ get_widget_by_name(&dvips_options, top, "dvips_options_text", True)) {
+ if (output_format_mapping[idx].fmt == FMT_PS ||
+ output_format_mapping[idx].fmt == FMT_PS2PDF) {
+ XtSetSensitive(dvips_label, True);
+ XtSetSensitive(dvips_options, True);
+ }
+ else {
+ XtSetSensitive(dvips_label, False);
+ XtSetSensitive(dvips_options, False);
+ }
+ }
+#else
+ if (get_widget_by_name(&dvips_label, top, "dvips_options_name", True)) {
+ XtSetSensitive(XtParent(dvips_label),
+ output_format_mapping[idx].fmt == FMT_PS ||
+ output_format_mapping[idx].fmt == FMT_PS2PDF);
+ }
+#endif
+}
+
+/* callbacks */
+
+static void
+select_format_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget file_text, top;
+
+ char *filename;
+ int i;
+#ifdef MOTIF
+ Widget f1, f2;
+ char *ptr;
+
+ i = (int)client_data;
+ UNUSED(call_data);
+ f1 = XtParent(w);
+ ASSERT(f1 != 0, "Parent of widget musn't be NULL!\n");
+ f2 = XtParent(f1);
+ ASSERT(f2 != 0, "Parent of f1 musn't be NULL!\n");
+ top = XtParent(f2);
+ ASSERT(top != 0, "Parent of f2 musn't be NULL!\n");
+
+ if ((file_text = XtNameToWidget(top, "*file_text")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"file_text\" widget!"));
+ return;
+ }
+ XtVaGetValues(file_text, XmNvalue, &filename, NULL);
+ if ((ptr = strrchr(filename, '.')) != NULL) {
+ char buf[1024];
+ replace_extension(filename, output_format_mapping[i].extension, buf, sizeof buf);
+ XtVaSetValues(file_text, XmNvalue, buf, NULL);
+ }
+#else /* MOTIF */
+
+ Widget popup, button;
+ char *ptr1, *ptr2;
+ char buf[1024];
+
+ UNUSED(call_data);
+ popup = XtParent(w);
+ ASSERT(popup != 0, "Parent of menu musn't be NULL!\n");
+ button = XtParent(popup);
+ ASSERT(button != 0, "Parent of popup musn't be NULL!\n");
+
+ top = (Widget)client_data;
+
+ if ((file_text = XtNameToWidget(top, "*file_text")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"file_text\" widget!"));
+ return;
+ }
+
+ XtVaGetValues(file_text, XtNstring, &filename, NULL);
+/* fprintf(stderr, "file text: |%s|\n", filename); */
+
+ /* swap title strings */
+ XtVaGetValues(button, XtNlabel, &ptr1, NULL);
+ XtVaGetValues(w, XtNlabel, &ptr2, NULL);
+ strncpy(buf, ptr1, sizeof buf);
+
+ for (i = 0; output_format_mapping[i].fmt_string != NULL; i++) {
+ if (strcmp(ptr2, output_format_mapping[i].fmt_string) == 0) {
+ char buf2[1024];
+ replace_extension(filename, output_format_mapping[i].extension, buf2, sizeof buf2);
+ XtVaSetValues(file_text, XtNstring, buf2, NULL);
+
+ break;
+ }
+ }
+ if (output_format_mapping[i].fmt_string == NULL) {
+ popup_message(get_matching_parent(w, globals.widgets.top_level, "print_popup", "save_popup", NULL),
+ MSG_WARN,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "Unrecognized string in format selector: |%s|", ptr2);
+ }
+ XtVaSetValues(button, XtNlabel, ptr2, NULL);
+ XtVaSetValues(w, XtNlabel, buf, NULL);
+
+#endif /* MOTIF */
+
+ save_save_info.output_format = curr_save_info.output_format = output_format_mapping[i].fmt;
+
+ update_dvips_options_sensitivity(i, save_shell);
+
+ resource.default_saving_format = save_save_info.output_format;
+ set_outfile_name(&save_save_info, &curr_save_info, FILE_SAVE);
+}
+
+static void
+cb_print_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "client_data in cb_print_cancel musn't be NULL!");
+ if (info->message_popup != 0) {
+ kill_message_window(info->message_popup);
+ }
+ XtPopdown(print_shell);
+ print_is_active = False;
+}
+
+static void
+cb_save_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "client_data in cb_save_cancel musn't be NULL!");
+ if (info->message_popup != 0) {
+ kill_message_window(info->message_popup);
+ }
+ XtPopdown(save_shell);
+ save_is_active = False;
+}
+
+static void
+cb_print_or_save(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ UNUSED(w);
+ UNUSED(call_data);
+
+ print_precheck1((XtPointer)info);
+}
+
+/* access from outside the module */
+void
+cancel_saving(struct save_or_print_info *info)
+{
+ cb_save_cancel(NULL, info, NULL);
+}
+
+
+static void
+print_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct save_or_print_info *info = NULL;
+ void *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in print_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in print_cancel mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ info = (struct save_or_print_info *)ptr;
+
+ cb_print_cancel(NULL, info, NULL);
+}
+
+static void
+save_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct save_or_print_info *info = NULL;
+ void *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in save_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in save_cancel mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ info = (struct save_or_print_info *)ptr;
+
+ cb_save_cancel(NULL, info, NULL);
+}
+
+#ifndef MOTIF
+
+/*
+ enable the `print to' button if user presses key or mouse button
+ inside that input field
+*/
+static void
+xaw_print_handle_key(Widget widget, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+ char *number;
+ int i;
+
+ number = (char *)closure;
+ i = atoi(number);
+ ASSERT(i == 2 || i == 3, "Button index should be 2 or 3");
+ UNUSED(widget);
+ UNUSED(ev);
+ UNUSED(cont);
+
+ if (i == 2) {
+ XawToggleSetCurrent(to_printer_radio, (XtPointer)PRINT_TO_PRINTER);
+ }
+ else {
+ ASSERT(to_file_radio_or_label[FILE_PRINT] != NULL, "");
+ XawToggleSetCurrent(to_file_radio_or_label[FILE_PRINT], (XtPointer)PRINT_TO_FILE);
+ }
+}
+
+/*
+ enable the `print range' button if user presses key or mouse button
+ inside that input field
+*/
+static void
+xaw_range_handle_key(Widget widget, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+ printOrSaveActionT act = (printOrSaveActionT)closure;
+ UNUSED(widget);
+ UNUSED(ev);
+ UNUSED(cont);
+
+ if (act == FILE_PRINT && curr_pr_info.range_radio != PRINT_RANGE) {
+ ASSERT(range_all_radio[act] != NULL, "button should have been initialized");
+ XawToggleSetCurrent(range_all_radio[act], (XtPointer)PRINT_RANGE);
+ }
+ else if (act == FILE_SAVE && curr_save_info.range_radio != SAVE_RANGE) {
+ ASSERT(range_all_radio[act] != NULL, "button should have been initialized");
+ XawToggleSetCurrent(range_all_radio[act], (XtPointer)SAVE_RANGE);
+ }
+}
+
+
+static void
+xaw_print_save_act_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct save_or_print_info *info = NULL;
+ void *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in search_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in search_cancel mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ info = (struct save_or_print_info *)ptr;
+
+ print_precheck1((XtPointer)info);
+}
+
+#if 0
+static void
+xaw_popup_menu_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Position x, y;
+ Dimension h;
+ int pos_x, pos_y;
+ Window dummy;
+
+ Widget popup = (Widget)client_data;
+ fprintf(stderr, "popup: %p\n", popup);
+ XtVaGetValues(w, XtNx, &x, XtNy, &y, XtNheight, &h, NULL);
+ fprintf(stderr, "x: %d, y: %d, h: %d\n", x, y, h);
+ XTranslateCoordinates(DISP, XtWindow(w), RootWindowOfScreen(SCRN),
+ x, y, &pos_x, &pos_y, &dummy);
+ XtRealizeWidget(popup);
+ /* WRONG - would need to use x position of its left widget ... */
+ XtVaSetValues(popup, XtNx, pos_x, XtNy, pos_y + h + 1, NULL);
+ XtPopup(popup, XtGrabNone);
+}
+#endif /* 0 */
+
+#endif /* not MOTIF */
+
+static void
+cb_print_vs_file(Widget w, XtPointer client_data, XtPointer call_data)
+{
+#ifdef MOTIF
+ Boolean to_printer = False, to_file = False;
+ if (((XmToggleButtonCallbackStruct *)call_data)->set) {
+ if (w == to_printer_radio)
+ to_printer = True;
+ else
+ to_file = True;
+
+ }
+ else {
+ if (w == to_printer_radio)
+ to_file = True;
+ else
+ to_printer = True;
+ }
+
+ XmToggleButtonGadgetSetState(to_file_radio_or_label[FILE_PRINT], to_file, False);
+ XmToggleButtonGadgetSetState(to_printer_radio, to_printer, False);
+
+ set_sensitivity((int)client_data);
+ XmProcessTraversal(curr_pr_info.print_radio == PRINT_TO_PRINTER
+ ? print_to_printer_text
+ : print_to_file_text[FILE_PRINT],
+ XmTRAVERSE_CURRENT);
+#else /* MOTIF */
+ int i = (int) XawToggleGetCurrent(to_printer_radio);
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ /*
+ NOTE: Unlike non-k xdvi, we don't use set_sensitivity for the
+ Xaw version, since the text inside the textfield cannot be made
+ insensitive, so it won't be obvious to users why they cannot
+ change the text. Also, the page range isn't set insensitive
+ either.
+ */
+ if (i != 0)
+ curr_pr_info.print_radio = i;
+#endif /* MOTIF */
+
+}
+
+
+
+static void
+cb_range(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ pageRadioT flag = (pageRadioT)client_data;
+ printOrSaveActionT act;
+
+#ifdef MOTIF
+
+ Boolean sensitivity;
+ UNUSED(call_data);
+ ASSERT(flag != PRINT_MARKED || flag != SAVE_MARKED || pageinfo_have_marked_pages(),
+ "PRINT_MARKED or SAVE_MARKED shouldn't be togglable if there are no marked pages!");
+
+ if (is_print_button(flag)) {
+ curr_pr_info.range_radio = (int)client_data;
+ sensitivity = (curr_pr_info.range_radio == PRINT_RANGE);
+ act = FILE_PRINT;
+ }
+ else {
+ curr_save_info.range_radio = (int)client_data;
+ sensitivity = (curr_save_info.range_radio == SAVE_RANGE);
+ act = FILE_SAVE;
+ }
+
+ /* switch off other radio buttons, switch on current one */
+ XmToggleButtonGadgetSetState(range_all_radio[act], False, False);
+ XmToggleButtonGadgetSetState(range_marked_radio[act], False, False);
+ XmToggleButtonGadgetSetState(range_from_to_radio[act], False, False);
+ XmToggleButtonGadgetSetState(w, True, False);
+
+ /* set from-to range to sensitive if appropriate */
+ XtSetSensitive(from_label[act], sensitivity);
+ XtSetSensitive(page_from_text[act], sensitivity);
+ XtSetSensitive(to_label[act], sensitivity);
+ XtSetSensitive(page_to_text[act], sensitivity);
+ XtSetSensitive(of_label[act], sensitivity);
+
+#else /* MOTIF */
+
+ int i;
+ UNUSED(call_data);
+ if (is_print_button(flag)) {
+ act = FILE_PRINT;
+ }
+ else {
+ act = FILE_SAVE;
+ }
+
+ UNUSED(w);
+
+ i = (int) XawToggleGetCurrent(range_all_radio[act]);
+
+ if (i != 0) {
+ ASSERT(i != PRINT_MARKED || i != SAVE_MARKED || pageinfo_have_marked_pages(),
+ "PRINT_MARKED or SAVE_MARKED shouldn't be togglable if there are no marked pages!");
+
+ if (act == FILE_PRINT)
+ curr_pr_info.range_radio = i;
+ else
+ curr_save_info.range_radio = i;
+ }
+
+#endif /* MOTIF */
+}
+
+static void
+set_filename_callback(const char *fname, void *data)
+{
+ if (fname != NULL) {
+ Widget w = (Widget)data;
+ XtVaSetValues(w,
+#ifdef MOTIF
+ XmNvalue, fname,
+ XmNcursorPosition, strlen(fname),
+#else
+ XtNstring, fname,
+#endif
+ NULL);
+ }
+}
+
+
+static void
+cb_browse(Widget w, XtPointer client_data, XtPointer call_data)
+{
+/* char *fname; */
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ printOrSaveActionT act = info->act;
+/* Widget ret_widget; */
+ Widget parent;
+
+ UNUSED(call_data);
+#ifdef MOTIF
+ UNUSED(w);
+#else
+ if (act == FILE_PRINT)
+ xaw_print_handle_key(w, (XtPointer)"3", NULL, NULL);
+#endif
+
+ if (act == FILE_SAVE) {
+ static struct filesel_callback cb; /* static so that we can pass its address */
+ cb.title = "Xdvi: Save to file";
+ cb.prompt = "Save to file:";
+ cb.ok = "OK";
+ cb.cancel = "Cancel";
+ cb.init_path = NULL;
+ cb.filemask = "*.dvi";
+ cb.must_exist = False;
+ cb.exit_on_cancel = False;
+ cb.func_ptr = set_filename_callback;
+ cb.data = print_to_file_text[act];
+
+ if (!get_widget_by_name(&parent, globals.widgets.top_level, Xdvi_SAVE_SHELL_NAME, True))
+ parent = globals.widgets.top_level;
+ XsraSelFile(parent, &cb);
+/* fprintf(stderr, "done saving: return widget = %p\n", ret_widget); */
+ }
+ else {
+ static struct filesel_callback cb; /* static so that we can pass its address */
+ cb.title = "Xdvi: Print to file";
+ cb.prompt = "Print to file:";
+ cb.ok = "OK";
+ cb.cancel = "Cancel";
+ cb.init_path = NULL;
+ cb.filemask = "*.ps";
+ cb.must_exist = False;
+ cb.exit_on_cancel = False;
+ cb.func_ptr = set_filename_callback;
+ cb.data = print_to_file_text[act];
+
+ if (!get_widget_by_name(&parent, globals.widgets.top_level, Xdvi_PRINT_SHELL_NAME, True))
+ parent = globals.widgets.top_level;
+ XsraSelFile(parent, &cb);
+/* fname = XsraSelFile(parent, "Xdvi: Print to file", "Print to file:", */
+/* "OK", "Cancel", */
+/* NULL, */
+/* "*.ps", False, &ret_widget); */
+/* fprintf(stderr, "done printing: return widget = %p\n", ret_widget); */
+ }
+
+/* if (fname != NULL) { */
+/* XtVaSetValues(print_to_file_text[act], */
+/* #ifdef MOTIF */
+/* XmNvalue, fname, XmNcursorPosition, strlen(fname), */
+/* #else */
+/* XtNstring, fname, */
+/* #endif */
+/* NULL); */
+/* } */
+/* free(fname); */
+}
+
+/* create a popup dialog for printing a DVI file OR saving pages from a DVI file */
+static Widget
+create_print_or_save_window(struct save_or_print_info *info, char *ofstring)
+{
+ printOrSaveActionT act = info->act;
+ Widget top_level_shell;
+ Atom WM_DELETE_WINDOW;
+#ifndef MOTIF
+ Widget form, paned, box;
+ Widget f01form, f02form; /* dummy forms to get indentation consistent */
+ Widget r1form;
+ Widget r1label;
+ Widget r2form, r3form, r4form = 0;
+ Widget r4label;
+ Widget r5label;
+ Widget r6form;
+ Widget r61form;
+ Widget r7form;
+ char *str;
+
+ XtTranslations xlats, xlats2, wm_translations;
+ XtAccelerators accels2;
+ int ddist;
+
+ static Dimension w_avg = 220;
+ Dimension w_curr;
+
+ /* handy abbrevs */
+#define HORIZONTAL_RESIZING_NO XtNleft, XtChainLeft, XtNright, XtChainLeft
+#define HORIZONTAL_RESIZING_YES XtNleft, XtChainLeft, XtNright, XtChainRight
+#define VERTICAL_RESIZING_NO XtNtop, XtChainTop, XtNbottom, XtChainTop
+
+ XtAddActions(print_actions, XtNumber(print_actions));
+
+ if (act == FILE_SAVE) {
+ str = get_string_va("<Message>WM_PROTOCOLS: WM_save_cancel(%p)\n"
+ "<Key>Escape:WM_save_cancel(%p)\n"
+ "<Key>q:WM_save_cancel(%p)",
+ info, info, info);
+ wm_translations = XtParseTranslationTable(str);
+ free(str);
+ }
+ else {
+ str = get_string_va("<Message>WM_PROTOCOLS: WM_print_cancel(%p)\n"
+ "<Key>Escape:WM_print_cancel(%p)\n"
+ "<Key>q:WM_print_cancel(%p)",
+ info, info, info);
+ wm_translations = XtParseTranslationTable(str);
+ free(str);
+ }
+
+ top_level_shell = XtVaCreatePopupShell(act == FILE_SAVE ? Xdvi_SAVE_SHELL_NAME : Xdvi_PRINT_SHELL_NAME,
+ transientShellWidgetClass,
+ globals.widgets.top_level,
+ XtNtitle, act == FILE_SAVE ? "xdvik: Save file" : "xdvik: Print DVI file",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, globals.widgets.top_level,
+ XtNallowShellResize, True,
+ XtNtranslations, wm_translations,
+ NULL);
+
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
+
+ paned = XtVaCreateManagedWidget(act == FILE_SAVE ? "save_paned" : "print_paned",
+ panedWidgetClass, top_level_shell, NULL);
+
+ form = XtVaCreateManagedWidget("form", formWidgetClass,
+ paned,
+ XtNallowResize, True,
+ NULL);
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+/* fprintf(stderr, "form1: %ld\n", (long)form); */
+
+ xlats = XtParseTranslationTable("<EnterWindow>:highlight(Always)\n"
+ "<LeaveWindow>:unhighlight()\n"
+ "<Btn1Down>,<Btn1Up>:set()notify()");
+
+ if (act == FILE_PRINT) {
+ str = get_string_va("<Key>Return:printInternal(%p)", info);
+ xlats2 = XtParseTranslationTable(str);
+ }
+ else {
+ str = get_string_va("<Key>Return:saveInternal(%p)", info);
+ xlats2 = XtParseTranslationTable(str);
+ }
+ free(str);
+
+ if (act == FILE_PRINT) { /* selection `to printer/to file' */
+ /* FIXME: set real sizes here */
+/* Dimension w_curr; */
+ f01form = XtVaCreateManagedWidget("dummy_print_to_label_form", formWidgetClass,
+ form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ /* XtNvertDistance, 10, */
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+ r1label = XtVaCreateManagedWidget("print_to", labelWidgetClass,
+ f01form,
+ XtNlabel, "Print to: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ r2form = XtVaCreateManagedWidget("print_to_printer_form", formWidgetClass,
+ form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ XtNvertDistance, 0,
+ XtNfromVert, f01form,
+ HORIZONTAL_RESIZING_YES,
+ XtNallowResize, True,
+ NULL);
+
+ accels2 = XtParseAcceleratorTable("<Btn1Down>,<Btn1Up>:set()notify()");
+
+ to_printer_radio = XtVaCreateManagedWidget("to_printer",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r2form,
+ XtNlabel, "Printer: ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioData, PRINT_TO_PRINTER,
+ XtNstate, resource.default_printing_target == PRINT_TO_PRINTER,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ XtAddCallback(to_printer_radio, XtNcallback, cb_print_vs_file, NULL);
+ XtInstallAccelerators(r2form, to_printer_radio);
+
+ print_to_printer_text = XtVaCreateManagedWidget("printer_text", asciiTextWidgetClass,
+ r2form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ /* XtNresize, XawtextResizeWidth, */
+ XtNfromHoriz, to_printer_radio,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ /* XtNscrollHorizontal, XawtextScrollAlways, */
+ NULL);
+ XtOverrideTranslations(print_to_printer_text, xlats2);
+ XtAddEventHandler(print_to_printer_text, KeyPressMask | ButtonPressMask, False,
+ xaw_print_handle_key, (XtPointer)"2");
+
+ adjust_vertically(to_printer_radio, print_to_printer_text, ddist);
+
+ r3form = XtVaCreateManagedWidget("print_to_file_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNvertDistance, 0,
+ XtNfromVert, r2form,
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r3form,
+ XtNhighlightThickness, 1,
+ XtNborderWidth, 0,
+ XtNlabel, "File: ",
+ XtNstate, resource.default_printing_target == PRINT_TO_FILE,
+ XtNradioGroup, to_printer_radio,
+ XtNradioData, PRINT_TO_FILE,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtAddCallback(to_file_radio_or_label[act], XtNcallback, cb_print_vs_file, NULL);
+ XtInstallAccelerators(r3form, to_file_radio_or_label[act]);
+
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", asciiTextWidgetClass,
+ r3form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, to_file_radio_or_label[act],
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(print_to_file_text[act], xlats2);
+ XtAddEventHandler(print_to_file_text[act], KeyPressMask | ButtonPressMask, False,
+ xaw_print_handle_key, (XtPointer)"3");
+ }
+ else { /* not printing, but saving */
+ int i;
+ Dimension max_entry_width = 0;
+ f01form = XtVaCreateManagedWidget("dummy_save_as_form", formWidgetClass,
+ form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ /* XtNvertDistance, 10, */
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+ r1label = XtVaCreateManagedWidget("save_as", labelWidgetClass,
+ f01form,
+ XtNlabel, "Save as: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+ r1form = XtVaCreateManagedWidget("save_to_file_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, f01form,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+/* fprintf(stderr, "formr1: %ld\n", (long)r1form); */
+#if 0
+ menu_double_arrow_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_double_arrow_bits, MENU_DOUBLE_ARROW_W, MENU_DOUBLE_ARROW_H);
+#endif
+ format_selection_label = XtVaCreateManagedWidget("format_selection_label", labelWidgetClass,
+ r1form,
+ XtNlabel, "Format: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ format_selection_button = XtVaCreateManagedWidget("format_selection_button", menuButtonWidgetClass,
+ r1form,
+ XtNmenuName, "format_selection_popup",
+ XtNlabel, output_format_mapping[resource.default_saving_format].fmt_string,
+ XtNjustify, XtJustifyLeft,
+ XtNborderWidth, resource.btn_border_width,
+ XtNfromHoriz, format_selection_label,
+#if 0
+ XtNhighlightThickness, 0,
+#endif
+ NULL);
+#if 0 /* Hack for arrow - menuButtonWidget cannot have a XtNrightBitmap!!! */
+ format_selection_b1 = XtVaCreateManagedWidget("format_selection_b1", commandWidgetClass,
+ r1form,
+ XtNborderWidth, resource.btn_border_width,
+ XtNfromHoriz, format_selection_button,
+ XtNhorizDistance, -1,
+ XtNhighlightThickness, 0,
+ XtNbitmap, menu_double_arrow_bitmap,
+ NULL);
+ adjust_heights(format_selection_button, format_selection_b1, NULL);
+#endif
+ format_selection_popup = XtCreatePopupShell("format_selection_popup", simpleMenuWidgetClass,
+ format_selection_button,
+/* globals.widgets.top_level, */
+ NULL, 0);
+#if 0
+ XtAddCallback(format_selection_b1, XtNcallback, xaw_popup_menu_cb, format_selection_popup);
+#endif
+ for (i = 1; i < FORMAT_SEL_CNT; i++) {
+ char name[1024];
+ Dimension curr_entry_width;
+ SNPRINTF(name, sizeof name, "format_selection_pulldown_%d", i);
+ format_selection_menu[i] = XtVaCreateManagedWidget(name, smeBSBObjectClass,
+ format_selection_popup,
+ XtNjustify, XtJustifyLeft,
+ XtNlabel,
+ i == resource.default_saving_format
+ ? output_format_mapping[0].fmt_string
+ : output_format_mapping[i].fmt_string,
+ NULL);
+ XtVaGetValues(format_selection_menu[i], XtNwidth, &curr_entry_width, NULL);
+ if (curr_entry_width > max_entry_width)
+ max_entry_width = curr_entry_width;
+ XtAddCallback(format_selection_menu[i], XtNcallback, select_format_cb, form);
+ }
+ XtVaSetValues(format_selection_button, XtNwidth, max_entry_width, NULL);
+
+ r3form = XtVaCreateManagedWidget("to_file_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r1form,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file", labelWidgetClass,
+ r3form,
+ XtNlabel, "File name: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", asciiTextWidgetClass,
+ r3form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ /* XtNvertDistance, ddist + 5, */
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, to_file_radio_or_label[act],
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(print_to_file_text[act], xlats2);
+
+
+ { /* align left edges of format selection pulldown and filename field */
+ Dimension w1, w2, w_max;
+ XtVaGetValues(format_selection_label, XtNwidth, &w1, NULL);
+ XtVaGetValues(to_file_radio_or_label[act], XtNwidth, &w2, NULL);
+ w_max = MAX(w1, w2);
+ XtVaSetValues(format_selection_button, XtNhorizDistance, ddist + (w_max - w1), NULL);
+ XtVaSetValues(print_to_file_text[act], XtNhorizDistance, ddist + (w_max - w2), NULL);
+ }
+ }
+
+#define DIST_1 8 /* FIXME */
+ print_to_file_button[act] = XtVaCreateManagedWidget("file_button", commandWidgetClass,
+ r3form,
+ XtNlabel, "Browse ...",
+ XtNfromHoriz, print_to_file_text[act],
+ XtNhorizDistance, DIST_1,
+ /* attach to right of form, no resizing: */
+ XtNleft, XtChainRight, XtNright, XtChainRight,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ XtVaGetValues(print_to_file_button[act], XtNwidth, &w_curr, NULL);
+ XtVaSetValues(print_to_file_text[act], XtNwidth, w_avg - w_curr - DIST_1 - 2, NULL);
+#undef DIST_1
+
+ adjust_vertically(to_file_radio_or_label[act], print_to_file_text[act], ddist + 5);
+ adjust_vertically(print_to_file_text[act], to_file_radio_or_label[act], ddist + 5);
+ adjust_vertically(print_to_file_button[act], to_file_radio_or_label[act], ddist + 5);
+
+ XtAddCallback(print_to_file_button[act], XtNcallback, cb_browse, (XtPointer)info);
+
+ /* other dvips options */
+ r4form = XtVaCreateManagedWidget("dvips_options_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r3form,
+ XtNvertDistance, 0,
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+
+ r4label = XtVaCreateManagedWidget("dvips_options_name", labelWidgetClass,
+ r4form,
+ XtNlabel, "Dvips Options:",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ dvips_options_text[act] = XtVaCreateManagedWidget("dvips_options_text", asciiTextWidgetClass,
+ r4form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, r4label,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(dvips_options_text[act], xlats2);
+
+ { /* align left edges of input fields */
+ Dimension w1, w2, w3, w_max;
+
+ if (act == FILE_PRINT)
+ XtVaGetValues(to_printer_radio, XtNwidth, &w1, NULL);
+ else
+ XtVaGetValues(format_selection_label, XtNwidth, &w1, NULL);
+
+ XtVaGetValues(to_file_radio_or_label[act], XtNwidth, &w2, NULL);
+ XtVaGetValues(r4label, XtNwidth, &w3, NULL);
+
+ w_max = MAX(MAX(w1, w2), w3);
+
+ if (act == FILE_PRINT)
+ XtVaSetValues(print_to_printer_text, XtNhorizDistance, ddist + (w_max - w1), NULL);
+ else
+ XtVaSetValues(format_selection_button, XtNhorizDistance, ddist + (w_max - w1), NULL);
+
+ XtVaSetValues(print_to_file_text[act], XtNhorizDistance, ddist + (w_max - w2), NULL);
+ XtVaSetValues(dvips_options_text[act], XtNhorizDistance, ddist + (w_max - w3), NULL);
+ }
+
+ /* page selection */
+
+ f02form = XtVaCreateManagedWidget("dummy_pages_form", formWidgetClass,
+ form,
+ XtNfromVert, r4form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ /* XtNvertDistance, 10, */
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ r5label = XtVaCreateManagedWidget("range_lab", labelWidgetClass,
+ f02form,
+ XtNlabel, "Pages:",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ r6form = XtVaCreateManagedWidget("page_range_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, f02form,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ accels2 = XtParseAcceleratorTable("<Btn1Down>,<Btn1Up>:set()notify()");
+ range_all_radio[act] = XtVaCreateManagedWidget("range_all",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r6form,
+ XtNlabel, "All ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioData, act == FILE_PRINT ? PRINT_ALL : SAVE_ALL,
+ XtNstate, True, /* enable this button by default */
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(range_all_radio[act], XtNcallback, cb_range, (XtPointer)PRINT_ALL);
+ else
+ XtAddCallback(range_all_radio[act], XtNcallback, cb_range, (XtPointer)SAVE_ALL);
+ XtInstallAccelerators(r6form, range_all_radio[act]);
+
+ r61form = XtVaCreateManagedWidget("range_marked_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r6form,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ range_marked_radio[act] = XtVaCreateManagedWidget("range_marked",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+
+ r61form,
+ XtNlabel, "Marked ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioGroup, range_all_radio[act],
+ XtNradioData, act == FILE_PRINT ? PRINT_MARKED : SAVE_MARKED,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(range_marked_radio[act], XtNcallback, cb_range, (XtPointer)PRINT_RANGE);
+ else
+ XtAddCallback(range_marked_radio[act], XtNcallback, cb_range, (XtPointer)SAVE_RANGE);
+ XtInstallAccelerators(r61form, range_marked_radio[act]);
+
+ r7form = XtVaCreateManagedWidget("range_from_to_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r61form,
+ /* XtNvertDistance, 0, */
+ XtNresizable, True,
+ /* HORIZONTAL_RESIZING_NO, */
+ NULL);
+
+ range_from_to_radio[act] = XtVaCreateManagedWidget("range_from_to",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r7form,
+ XtNlabel, "From: ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioGroup, range_all_radio[act],
+ XtNradioData, act == FILE_PRINT ? PRINT_RANGE : SAVE_RANGE,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(range_from_to_radio[act], XtNcallback, cb_range, (XtPointer)PRINT_RANGE);
+ else
+ XtAddCallback(range_from_to_radio[act], XtNcallback, cb_range, (XtPointer)SAVE_RANGE);
+ XtInstallAccelerators(r7form, range_from_to_radio[act]);
+
+ page_from_text[act] = XtVaCreateManagedWidget("range_from", asciiTextWidgetClass,
+ r7form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, range_from_to_radio[act],
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(page_from_text[act], xlats2);
+ XtAddEventHandler(page_from_text[act], KeyPressMask | ButtonPressMask, False,
+ xaw_range_handle_key, (XtPointer)act);
+
+ to_label[act] = XtVaCreateManagedWidget("range_to_lab", labelWidgetClass,
+ r7form,
+ XtNlabel, "to: ",
+ XtNborderWidth, 0,
+ XtNfromHoriz, page_from_text[act],
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ page_to_text[act] = XtVaCreateManagedWidget("range_to", asciiTextWidgetClass,
+ r7form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, to_label[act],
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(page_to_text[act], xlats2);
+ XtAddEventHandler(page_to_text[act], KeyPressMask | ButtonPressMask, False,
+ xaw_range_handle_key, (XtPointer)act);
+
+ of_label[act] = XtVaCreateManagedWidget("range_of", labelWidgetClass,
+ r7form,
+ XtNlabel, ofstring,
+ XtNborderWidth, 0,
+ XtNresizable, True,
+ XtNfromHoriz, page_to_text[act],
+ /* HORIZONTAL_RESIZING_NO, */
+ XtNleft, XtChainLeft,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ adjust_vertically(range_from_to_radio[act], page_from_text[act], ddist);
+ adjust_vertically(to_label[act], page_from_text[act], ddist);
+ adjust_vertically(of_label[act], page_from_text[act], ddist);
+
+ /* box for the OK/Cancel button */
+ box = XtVaCreateManagedWidget("box", formWidgetClass,
+ paned,
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the pane widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ ok_button[act] = XtVaCreateManagedWidget(act == FILE_PRINT ? "print_button" : "save_button",
+ commandWidgetClass, box,
+ XtNlabel, act == FILE_PRINT ? "Print" : "Save",
+ XtNaccelerators, G_accels_cr,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(ok_button[act], XtNcallback, cb_print_or_save, (XtPointer)info);
+ else
+ XtAddCallback(ok_button[act], XtNcallback, cb_print_or_save, (XtPointer)info);
+
+ XtInstallAccelerators(form, ok_button[act]);
+ if (act == FILE_PRINT)
+ XtInstallAccelerators(print_to_printer_text, ok_button[act]);
+ XtInstallAccelerators(print_to_file_text[act], ok_button[act]);
+
+ cancel_button[act] = XtVaCreateManagedWidget("cancel", commandWidgetClass,
+ box,
+ XtNlabel, "Cancel",
+ XtNfromHoriz, ok_button[act],
+ XtNbottom, XtChainBottom,
+ XtNjustify, XtJustifyRight,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(cancel_button[act], XtNcallback, cb_print_cancel, (XtPointer)info);
+ else
+ XtAddCallback(cancel_button[act], XtNcallback, cb_save_cancel, (XtPointer)info);
+
+ XtManageChild(top_level_shell);
+ center_window(top_level_shell, globals.widgets.top_level);
+ XtMapWidget(top_level_shell);
+ XSetWMProtocols(XtDisplay(top_level_shell), XtWindow(top_level_shell), &WM_DELETE_WINDOW, 1);
+
+ if (pageinfo_have_marked_pages()) {
+ XawToggleSetCurrent(range_all_radio[act],
+ act == FILE_PRINT ? (XtPointer)PRINT_MARKED : (XtPointer)SAVE_MARKED);
+ }
+ else if ((act == FILE_PRINT && save_pr_info.range_radio == PRINT_MARKED)
+ || (act == FILE_SAVE && save_save_info.range_radio == SAVE_MARKED)) {
+ XawToggleSetCurrent(range_all_radio[act],
+ act == FILE_PRINT ? (XtPointer)PRINT_ALL : (XtPointer)SAVE_ALL);
+ }
+
+#else /* not MOTIF */
+ Widget form, pane, box;
+ Widget frame1, f1label, f1child;
+ Widget r4label;
+ Widget frame2, f2label, f2child;
+ XmString str;
+ XtTranslations xlats;
+
+ XtAddActions(print_actions, XtNumber(print_actions));
+
+ if (act == FILE_SAVE) {
+ char *ptr = get_string_va("#override \n<Key>osfCancel:WM_save_cancel(%p)", info);
+ xlats = XtParseTranslationTable(ptr);
+ free(ptr);
+ }
+ else {
+ char *ptr = get_string_va("#override \n<Key>osfCancel:WM_print_cancel(%p)", info);
+ xlats = XtParseTranslationTable(ptr);
+ free(ptr);
+ }
+
+ top_level_shell = XtVaCreatePopupShell(act == FILE_SAVE ? "save_popup" : "print_popup",
+ xmDialogShellWidgetClass, globals.widgets.top_level,
+ XmNtitle, act == FILE_SAVE ? "Save file" : "Print DVI file",
+ XmNallowShellResize, True,
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+ XmNmappedWhenManaged, False, /* so that we can center it first */
+ NULL);
+
+ /* make the window manager destroy action just pop down the dialog */
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
+ if (act == FILE_SAVE)
+ XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_save_cancel, (XtPointer)info);
+ else
+ XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_print_cancel, (XtPointer)info);
+
+
+ pane = XtVaCreateWidget(act == FILE_SAVE ? "save_paned" : "print_paned",
+ xmPanedWindowWidgetClass, top_level_shell,
+ /* make sashes invisible */
+ XmNsashWidth, 1,
+ XmNsashHeight, 1,
+ /* turn separator off, since it gives visual noise with the frames */
+ XmNseparatorOn, False,
+ NULL);
+
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ pane,
+ XmNhorizontalSpacing, DDIST_MAJOR,
+ XmNverticalSpacing, DDIST_MAJOR,
+ XmNautoUnmanage, False,
+ XTranslations, xlats,
+ NULL);
+
+ if (act == FILE_PRINT) {
+ /* First frame: print to printer or file */
+
+ frame1 = XtVaCreateWidget("print_to_frame", xmFrameWidgetClass, form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("Print to:");
+ f1label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame1,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f1child = XtVaCreateWidget("form", xmFormWidgetClass, frame1,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("Printer:");
+ to_printer_radio = XtVaCreateManagedWidget("to_printer",
+ xmToggleButtonGadgetClass, f1child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNset, resource.default_printing_target == PRINT_TO_PRINTER,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(to_printer_radio, XmNvalueChangedCallback, cb_print_vs_file, (XtPointer)1);
+
+ XtOverrideTranslations(to_printer_radio, xlats);
+
+ print_to_printer_text = XtVaCreateManagedWidget("print_text", xmTextFieldWidgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftWidget, to_printer_radio,
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(print_to_printer_text, XmNactivateCallback, cb_print_or_save, info);
+
+ adjust_heights(to_printer_radio, print_to_printer_text, NULL);
+
+ str = XmStringCreateLocalized("File:");
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file", xmToggleButtonGadgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, print_to_printer_text,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNset, resource.default_printing_target == PRINT_TO_FILE,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(to_file_radio_or_label[act], XmNvalueChangedCallback, cb_print_vs_file, (XtPointer)2);
+
+ str = XmStringCreateLocalized("Browse ...");
+ print_to_file_button[act] = XtVaCreateManagedWidget("file_button", xmPushButtonWidgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNsensitive, resource.default_printing_target == PRINT_TO_FILE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, print_to_printer_text,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ XtOverrideTranslations(to_file_radio_or_label[act], xlats);
+ XtOverrideTranslations(print_to_file_button[act], xlats);
+
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", xmTextFieldWidgetClass,
+ f1child,
+ XmNsensitive, resource.default_printing_target == PRINT_TO_FILE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, print_to_printer_text,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, print_to_file_button[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, to_file_radio_or_label[act],
+ XTranslations, xlats,
+ NULL);
+
+ adjust_heights(to_file_radio_or_label[act], print_to_file_button[act], print_to_file_text[act], NULL);
+
+ XtAddCallback(print_to_file_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+ XtAddCallback(print_to_file_button[act], XmNactivateCallback, cb_browse, (XtPointer)info);
+
+ XtManageChild(f1child);
+ XtManageChild(frame1);
+
+ } /* saving, not printing */
+ else {
+ frame1 = XtVaCreateWidget("save_as_frame", xmFrameWidgetClass,
+ form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ str = XmStringCreateLocalized("Save as:");
+ f1label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame1,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f1child = XtVaCreateWidget("form", xmFormWidgetClass, frame1,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+/* fprintf(stderr, "CHILD: 0x%x\n", (long)f1child); */
+ str = XmStringCreateLocalized("Format:");
+ format_selection_texts[0] = XmStringCreateLocalized((char *)output_format_mapping[0].fmt_string);
+ format_selection_texts[1] = XmStringCreateLocalized((char *)output_format_mapping[1].fmt_string);
+ format_selection_texts[2] = XmStringCreateLocalized((char *)output_format_mapping[2].fmt_string);
+ format_selection_texts[3] = XmStringCreateLocalized((char *)output_format_mapping[3].fmt_string);
+ format_selection_texts[4] = XmStringCreateLocalized((char *)output_format_mapping[4].fmt_string);
+ format_selection_option
+ = XmVaCreateSimpleOptionMenu(f1child, "format_selection_option",
+ str, 'F',
+ resource.default_saving_format, /*initial menu selection*/
+ select_format_cb, /* callback */
+ XmVaPUSHBUTTON, format_selection_texts[0], 'P', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[1], 'F', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[2], 'D', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[3], 'T', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[4], 'U', NULL, NULL,
+ NULL);
+
+ XmStringFree(str);
+ XmStringFree(format_selection_texts[0]);
+ XmStringFree(format_selection_texts[1]);
+ XmStringFree(format_selection_texts[2]);
+ XmStringFree(format_selection_texts[3]);
+ XmStringFree(format_selection_texts[4]);
+
+ str = XmStringCreateLocalized("File name:");
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file", xmLabelGadgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, format_selection_option,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* XmNchildType, XmFRAME_TITLE_CHILD, */
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Browse ...");
+ print_to_file_button[act] = XtVaCreateManagedWidget("file_button", xmPushButtonWidgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, format_selection_option,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", xmTextFieldWidgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, format_selection_option,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, to_file_radio_or_label[act],
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, print_to_file_button[act],
+ XTranslations, xlats,
+ NULL);
+
+ adjust_heights(to_file_radio_or_label[act], print_to_file_button[act], print_to_file_text[act], NULL);
+ XtAddCallback(print_to_file_button[act], XmNactivateCallback, cb_browse, (XtPointer)info);
+ }
+
+#if 1
+ { /* align left edges of widgets */
+ Dimension w1, w2;
+
+ XtVaGetValues(to_file_radio_or_label[act], XmNwidth, &w2, NULL);
+ if (act == FILE_PRINT)
+ XtVaGetValues(to_printer_radio, XmNwidth, &w1, NULL);
+ else {
+ Widget w;
+ if (get_widget_by_name(&w, format_selection_option, "OptionLabel", True)) {
+ XtVaGetValues(w, XmNwidth, &w1, NULL);
+ }
+ else {
+ w1 = w2;
+ }
+ }
+
+ if (w1 > w2) {
+ Dimension offset = DDIST;
+ offset += w1 - w2;
+ XtVaSetValues(print_to_file_text[act], XmNleftOffset, offset, NULL);
+ }
+ else if (w2 > w1) {
+ Dimension offset = DDIST;
+ offset += w2 - w1;
+ if (act == FILE_PRINT)
+ XtVaSetValues(print_to_printer_text, XmNleftOffset, offset, NULL);
+ else {
+ Widget w;
+ if (get_widget_by_name(&w, format_selection_option, "OptionLabel", True)) {
+ /* FIXME: Setting width would be cleaner, but it doesn't work ...?
+ Dimension curr_w;
+ XtVaGetValues(w, XmNwidth, &curr_w, NULL);
+ XtVaSetValues(w, XmNwidth, curr_w + offset, NULL);
+ */
+ /* fprintf(stderr, "Setting width from %d to: %d\n", curr_w, curr_w + offset); */
+ XtVaSetValues(w,
+ XmNmarginRight, offset,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ }
+
+ }
+ }
+ }
+#endif /* 0 */
+
+ if (act == FILE_SAVE) {
+ XtManageChild(format_selection_option);
+ XtManageChild(f1child);
+ XtManageChild(frame1);
+ }
+
+ /* additional dvips options */
+ str = XmStringCreateLocalized("Dvips Options:");
+ r4label = XtVaCreateManagedWidget("dvips_options_name", xmLabelGadgetClass,
+ form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame1,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ dvips_options_text[act] = XtVaCreateManagedWidget("dvips_options_text", xmTextFieldWidgetClass,
+ form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame1,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftWidget, r4label,
+ XmNcolumns, 20,
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(dvips_options_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+ adjust_heights(r4label, dvips_options_text[act], NULL);
+
+ /* page selection */
+ frame2 = XtVaCreateWidget(act == FILE_PRINT ? "print_page_frame" : "save_page_frame", xmFrameWidgetClass,
+ form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, dvips_options_text[act],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("Pages:");
+ f2label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame2,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f2child = XtVaCreateWidget("form", xmFormWidgetClass, frame2,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ XTranslations, xlats,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("All");
+ range_all_radio[act] = XtVaCreateManagedWidget("all",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNset, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ XTranslations, xlats,
+ NULL);
+ XmStringFree(str);
+ if (act == FILE_PRINT) {
+ XtAddCallback(range_all_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)PRINT_ALL);
+ }
+ else {
+ XtAddCallback(range_all_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)SAVE_ALL);
+ }
+
+ str = XmStringCreateLocalized("Marked");
+ range_marked_radio[act] = XtVaCreateManagedWidget("marked",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_all_radio[act],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ XTranslations, xlats,
+ NULL);
+ XmStringFree(str);
+ if (act == FILE_PRINT) {
+ XtAddCallback(range_marked_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)PRINT_MARKED);
+ }
+ else {
+ XtAddCallback(range_marked_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)SAVE_MARKED);
+ }
+
+ str = XmStringCreateLocalized("Range:");
+ range_from_to_radio[act] = XtVaCreateManagedWidget("range",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ XTranslations, xlats,
+ NULL);
+ XmStringFree(str);
+
+ if (act == FILE_PRINT) {
+ XtAddCallback(range_from_to_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)PRINT_RANGE);
+ }
+ else {
+ XtAddCallback(range_from_to_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)SAVE_RANGE);
+ }
+ str = XmStringCreateLocalized("From");
+ from_label[act] = XtVaCreateManagedWidget("from", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, range_from_to_radio[act],
+ NULL);
+ XmStringFree(str);
+
+ page_from_text[act] = XtVaCreateManagedWidget("from_page",
+ xmTextFieldWidgetClass, f2child,
+ XmNcolumns, 5,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, from_label[act],
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(page_from_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+
+ str = XmStringCreateLocalized("to");
+ to_label[act] = XtVaCreateManagedWidget("to", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, page_from_text[act],
+ NULL);
+ XmStringFree(str);
+
+ page_to_text[act] = XtVaCreateManagedWidget("to_page", xmTextFieldWidgetClass,
+ f2child,
+ XmNcolumns, 5,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, to_label[act],
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(page_to_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+
+ str = XmStringCreateLocalized(ofstring);
+ of_label[act] = XtVaCreateManagedWidget("of", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, page_to_text[act],
+ NULL);
+ XmStringFree(str);
+
+ adjust_heights(range_from_to_radio[act],
+ from_label[act], page_from_text[act],
+ to_label[act], page_to_text[act],
+ of_label[act],
+ NULL);
+
+ XtManageChild(f2child);
+ XtManageChild(frame2);
+
+ /* box for the OK/Cancel button */
+ box = XtVaCreateManagedWidget("box", xmFormWidgetClass,
+ pane,
+ XmNskipAdjust, True, /* don't resize this area */
+ XTranslations, xlats,
+ NULL);
+
+ if (act == FILE_PRINT)
+ str = XmStringCreateLocalized("Print");
+ else
+ str = XmStringCreateLocalized("Save");
+ ok_button[act] = XtVaCreateManagedWidget(act == FILE_PRINT ? "print_button" : "save_button",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNleftOffset, 10,
+ NULL);
+ XmStringFree(str);
+ if (act == FILE_PRINT)
+ XtAddCallback(ok_button[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+ else
+ XtAddCallback(ok_button[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+
+ XtOverrideTranslations(ok_button[act], XtParseTranslationTable("<Key>Return:ArmAndActivate()"));
+
+ str = XmStringCreateLocalized("Cancel");
+ cancel_button[act] = XtVaCreateManagedWidget("cancel",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNrightOffset, 10,
+ NULL);
+ XmStringFree(str);
+
+ XtOverrideTranslations(range_all_radio[act], xlats);
+ XtOverrideTranslations(range_marked_radio[act], xlats);
+ XtOverrideTranslations(range_from_to_radio[act], xlats);
+ XtOverrideTranslations(ok_button[act], xlats);
+ XtOverrideTranslations(cancel_button[act], xlats);
+
+ if (act == FILE_PRINT)
+ XtAddCallback(cancel_button[act], XmNactivateCallback, cb_print_cancel, (XtPointer)info);
+ else
+ XtAddCallback(cancel_button[act], XmNactivateCallback, cb_save_cancel, (XtPointer)info);
+
+ { /* make the buttons the same size: */
+ Dimension w1, w2;
+ XtVaGetValues(ok_button[act], XtNwidth, &w1, NULL);
+ XtVaGetValues(cancel_button[act], XtNwidth, &w2, NULL);
+ if (w1 < w2)
+ XtVaSetValues(ok_button[act], XtNwidth, w2, NULL);
+ else if (w2 > w1)
+ XtVaSetValues(cancel_button[act], XtNwidth, w1, NULL);
+ }
+
+ if (pageinfo_have_marked_pages()) {
+ XmToggleButtonGadgetSetState(range_marked_radio[act], True, True);
+ }
+ else if (save_pr_info.range_radio == PRINT_MARKED) {
+ XmToggleButtonGadgetSetState(range_all_radio[act], True, True);
+ }
+
+ XtManageChild(form);
+ XtManageChild(pane);
+ center_window(top_level_shell, globals.widgets.top_level);
+ XtMapWidget(top_level_shell);
+ XmProcessTraversal(ok_button[act], XmTRAVERSE_CURRENT);
+#endif /* not MOTIF */
+
+ /* set default output format */
+ save_save_info.output_format = curr_save_info.output_format =
+ output_format_mapping[resource.default_saving_format].fmt;
+
+ if (act == FILE_SAVE)
+ update_dvips_options_sensitivity(resource.default_saving_format, top_level_shell);
+
+ return top_level_shell;
+}
+#undef HORIZONTAL_RESIZING_NO
+#undef HORIZONTAL_RESIZING_YES
+#undef VERTICAL_RESIZING_NO
+
+
+static void
+set_target_radio(struct dialog_info *save_info, struct dialog_info *curr_info, printOrSaveActionT act)
+{
+#ifdef MOTIF
+ if (save_info->print_radio > 0 && save_info->print_radio != curr_info->print_radio) {
+ XmToggleButtonGadgetSetState(save_info->print_radio == PRINT_TO_PRINTER
+ ? to_printer_radio
+ : to_file_radio_or_label[act], True, True);
+ }
+#else /* MOTIF */
+ UNUSED(act);
+ UNUSED(curr_info);
+ XawToggleSetCurrent(to_printer_radio, (XtPointer)save_info->print_radio);
+#endif /* MOTIF */
+}
+
+static void
+set_range_radio(struct dialog_info *save_info, struct dialog_info *curr_info, printOrSaveActionT act)
+{
+#ifdef MOTIF
+ if (save_info->range_radio > 0 && save_info->range_radio != curr_info->range_radio) {
+ Widget selected = 0;
+ switch (save_info->range_radio) {
+ case PRINT_ALL:
+ case SAVE_ALL:
+ selected = range_all_radio[act];
+ break;
+ case PRINT_MARKED:
+ case SAVE_MARKED:
+ selected = range_marked_radio[act];
+ break;
+ case PRINT_RANGE:
+ case SAVE_RANGE:
+ selected = range_from_to_radio[act];
+ break;
+ default:
+ ASSERT(0, "wrong button type in set_range_radio()");
+ }
+ XmToggleButtonGadgetSetState(selected, True, True);
+ }
+#else /* MOTIF */
+ UNUSED(curr_info);
+ XawToggleSetCurrent(range_all_radio[act], (XtPointer)save_info->range_radio);
+#endif /* MOTIF */
+}
+
+void
+save_or_print_callback(struct save_or_print_info *info)
+{
+ printOrSaveActionT act = info->act;
+ static char ofstring[1024]; /* should be ample */
+ struct dialog_info *save_info = NULL, *curr_info = NULL;
+
+ if (act == FILE_PRINT) {
+ save_info = &save_pr_info;
+ curr_info = &curr_pr_info;
+ if (print_is_active) {
+ XBell(DISP, 0);
+ XRaiseWindow(DISP, XtWindow(print_shell));
+ return;
+ }
+
+ if (printlog_raise_active()) {
+ XBell(DISP, 0);
+ return;
+ }
+ }
+ else if (act == FILE_SAVE) {
+ save_info = &save_save_info;
+ curr_info = &curr_save_info;
+ if (save_is_active) {
+ XBell(DISP, 0);
+ XRaiseWindow(DISP, XtWindow(save_shell));
+ return;
+ }
+ }
+ else {
+ ASSERT(0, "wrong action type in save_or_print_callback()");
+ }
+
+ if (globals.dvi_file.bak_fp == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Empty or incomplete DVI file. "
+ "Please select a new DVI file via File -> Open.");
+ return;
+ }
+
+ if (globals.pageno_correct == 1)
+ sprintf(ofstring, "of %d physical pages", total_pages);
+ else
+ sprintf(ofstring, "of %d to %d pages", globals.pageno_correct, total_pages + globals.pageno_correct - 1);
+
+ if (act == FILE_PRINT && print_shell == NULL) {
+ curr_info->print_radio = resource.default_printing_target;
+ print_shell = create_print_or_save_window(info, ofstring);
+#ifdef MOTIF
+ set_sensitivity(resource.default_printing_target);
+#endif
+ }
+ else if (act == FILE_SAVE && save_shell == NULL)
+ save_shell = create_print_or_save_window(info, ofstring);
+ else { /* if the window was already created */
+#ifdef MOTIF
+ XmString str;
+#endif
+ /* XXX: is this actually needed??? */
+ /* XXX: To test, remove the following */
+ if (!pageinfo_have_marked_pages()) {
+ if (act == FILE_PRINT && save_pr_info.range_radio == PRINT_MARKED) {
+ save_pr_info.range_radio = PRINT_ALL;
+ }
+ else if (act == FILE_SAVE && save_save_info.range_radio == SAVE_MARKED) {
+ save_save_info.range_radio = SAVE_ALL;
+ }
+ }
+
+ if (act == FILE_PRINT)
+ set_target_radio(save_info, curr_info, act);
+ set_range_radio(save_info, curr_info, act);
+#ifdef MOTIF
+ str = XmStringCreateLocalized(ofstring);
+ XtVaSetValues(of_label[act], XmNlabelString, str, NULL);
+ XmStringFree(str);
+
+ /* FIXME: this seems neccessary, otherwise labels are misaligned
+ again if window is closed and opened a second time? */
+ adjust_heights(range_from_to_radio[act],
+ from_label[act], page_from_text[act],
+ to_label[act], page_to_text[act],
+ of_label[act],
+ NULL);
+
+ if (save_info->dvips_options != NULL) {
+ XtVaSetValues(dvips_options_text[act], XmNvalue, save_info->dvips_options,
+ XmNcursorPosition, strlen(save_info->dvips_options), NULL);
+ }
+ else {
+ XtVaSetValues(dvips_options_text[act], XmNvalue, "", NULL);
+ }
+#else /* MOTIF */
+ XtVaSetValues(of_label[act], XtNlabel, ofstring, NULL);
+
+ if (save_info->dvips_options != NULL) {
+ XtVaSetValues(dvips_options_text[act], XtNstring, save_info->dvips_options, NULL);
+ XawTextSetInsertionPoint(dvips_options_text[act], strlen(save_info->dvips_options));
+ }
+ else {
+ XtVaSetValues(dvips_options_text[act], XtNstring, "", NULL);
+ }
+#endif /* MOTIF */
+ }
+
+ get_initial_dialog_values(save_info, act);
+
+#ifdef MOTIF
+ if (act == FILE_PRINT)
+ XtVaSetValues(print_to_printer_text, XmNvalue, save_info->printer_name,
+ XmNcursorPosition, strlen(save_info->printer_name), NULL);
+
+ XtVaSetValues(dvips_options_text[act], XmNvalue, save_info->dvips_options,
+ XmNcursorPosition, strlen(save_info->dvips_options), NULL);
+
+ XtVaSetValues(page_from_text[act], XmNvalue, save_info->from_page,
+ XmNcursorPosition, strlen(save_info->from_page), NULL);
+
+ XtVaSetValues(page_to_text[act], XmNvalue, save_info->to_page,
+ XmNcursorPosition, strlen(save_info->to_page), NULL);
+#else /* MOTIF */
+ if (act == FILE_PRINT) {
+ XtVaSetValues(print_to_printer_text, XtNstring, save_info->printer_name, NULL);
+ XawTextSetInsertionPoint(print_to_printer_text, strlen(save_info->printer_name));
+ }
+
+ XtVaSetValues(dvips_options_text[act], XtNstring, save_info->dvips_options, NULL);
+ XawTextSetInsertionPoint(dvips_options_text[act], strlen(save_info->dvips_options));
+
+ XtVaSetValues(page_from_text[act], XtNstring, save_info->from_page, NULL);
+ XawTextSetInsertionPoint(page_from_text[act], strlen(save_info->from_page));
+
+ XtVaSetValues(page_to_text[act], XtNstring, save_info->to_page, NULL);
+ XawTextSetInsertionPoint(page_to_text[act], strlen(save_info->to_page));
+#endif /* MOTIF */
+
+ if (act == FILE_PRINT) {
+ if (pageinfo_have_marked_pages()) {
+ XtSetSensitive(range_marked_radio[FILE_PRINT], True);
+ }
+ else {
+ XtSetSensitive(range_marked_radio[FILE_PRINT], False);
+ }
+ ASSERT(save_pr_info.range_radio != PRINT_MARKED || pageinfo_have_marked_pages(),
+ "PRINT_MARKED shouldn't be togglable if there are no marked pages!");
+ }
+ else if (act == FILE_SAVE) {
+ if (pageinfo_have_marked_pages()) {
+ XtSetSensitive(range_marked_radio[FILE_SAVE], True);
+ }
+ else {
+ XtSetSensitive(range_marked_radio[FILE_SAVE], False);
+ }
+ ASSERT(save_save_info.range_radio != SAVE_MARKED || pageinfo_have_marked_pages(),
+ "SAVE_MARKED shouldn't be togglable if there are no marked pages!");
+ }
+
+ set_outfile_name(save_info, &curr_save_info, act);
+
+#ifdef MOTIF
+ XtVaSetValues(print_to_file_text[act], XmNvalue, save_info->file_name,
+ XmNcursorPosition, strlen(save_info->file_name), NULL);
+#else /* MOTIF */
+ XtVaSetValues(print_to_file_text[act], XtNstring, save_info->file_name, NULL);
+ XawTextSetInsertionPoint(print_to_file_text[act], strlen(save_info->file_name));
+#endif /* MOTIF */
+
+ if (act == FILE_PRINT) {
+ XtPopup(print_shell, XtGrabNone);
+ print_is_active = True;
+ }
+ else {
+ XtPopup(save_shell, XtGrabNone);
+ save_is_active = True;
+ }
+}
+
+static int
+getpageno(Widget w)
+{
+ char *s, *p;
+ int pageno;
+#ifndef MOTIF
+ XtVaGetValues(w, XtNstring, &s, NULL);
+#else /* MOTIF */
+ s = XmTextFieldGetString(w);
+#endif
+ p = s;
+ if (*p == '-')
+ ++p;
+ if (!isdigit((int)*p)) {
+ return 0;
+ }
+ do {
+ ++p;
+ } while (isdigit((int)*p));
+ if (*p != '\0')
+ return 0;
+
+ pageno = atoi(s) - globals.pageno_correct;
+#ifdef MOTIF
+ XtFree(s);
+#endif
+ return pageno;
+}
+
+
+/*
+ return text value of Widget w in newly allocated memory,
+ free()ing old_val as appropriate. Returns NULL if
+ text value starts with '\0'.
+*/
+static char *
+get_saved_command(char **old_val, Widget w)
+{
+ char *val = NULL;
+
+ if (*old_val != NULL) {
+#if MOTIF
+ XtFree((char *)*old_val);
+#else
+ free((char*)*old_val);
+#endif
+ *old_val = NULL;
+ }
+#if MOTIF
+ val = XmTextFieldGetString(w);
+ if (*val == '\0') {
+ XtFree((char *)val);
+ val = NULL;
+ }
+#else
+ XtVaGetValues(w, XtNstring, &val, NULL);
+ if (*val == '\0') {
+ val = NULL;
+ }
+ else {
+ val = xstrdup(val);
+ }
+#endif
+ return val;
+}
+
+/* fill curr_print_info and save_print_info with current values */
+static void
+get_save_window_state(struct dialog_info *save_info, struct dialog_info *curr_info, printOrSaveActionT act)
+{
+ save_info->print_radio = curr_info->print_radio;
+ save_info->range_radio = curr_info->range_radio;
+
+ if (act == FILE_PRINT) {
+ save_info->printer_name = get_saved_command(&(save_info->printer_name), print_to_printer_text);
+ curr_info->printer_name = get_saved_command(&(curr_info->printer_name), print_to_printer_text);
+ }
+ save_info->file_name = get_saved_command(&(save_info->file_name), print_to_file_text[act]);
+ curr_info->file_name = get_saved_command(&(curr_info->file_name), print_to_file_text[act]);
+
+ save_info->dvips_options = get_saved_command(&(save_info->dvips_options), dvips_options_text[act]);
+ curr_info->dvips_options = get_saved_command(&(curr_info->dvips_options), dvips_options_text[act]);
+
+ save_info->from_page = get_saved_command(&(save_info->from_page), page_from_text[act]);
+ save_info->to_page = get_saved_command(&(save_info->to_page), page_to_text[act]);
+
+ TRACE_GUI((stderr, "saved options:\nprinter: |%s|, file: |%s|, dvips: |%s|, from: |%s|, to: |%s|\n",
+ save_info->printer_name ? save_info->printer_name : "<NULL>",
+ save_info->file_name ? save_info->file_name : "<NULL>",
+ save_info->dvips_options ? save_info->dvips_options : "<NULL>",
+ save_info->from_page ? save_info->from_page : "<NULL>",
+ save_info->to_page ? save_info->to_page : "<NULL>"));
+}
+
+static void
+popdown_dialog_and_print_or_save(XtPointer myinfo)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)myinfo;
+ struct select_pages_info *pinfo = (struct select_pages_info *)info->pinfo;
+ struct dialog_info *curr_info = NULL;
+
+ /* pop down the dialog */
+ if (pinfo->act == FILE_PRINT) {
+ curr_info = &save_pr_info;
+ cb_print_cancel(NULL, info, NULL);
+ /* when printing to file, set ps_out.fname to non-NULL; this will
+ notify called routines that printing should go to the file */
+ if (curr_info->print_radio == PRINT_TO_FILE) {
+ pinfo->finfo->ps_out.fname = xstrdup(curr_info->expanded_filename);
+ }
+ }
+ else {
+ curr_info = &save_save_info;
+ cb_save_cancel(NULL, info, NULL);
+ }
+
+ if (globals.dvi_file.bak_fp == NULL) { /* shouldn't happen */
+ info->message_popup = popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL,
+ "No active DVI file");
+ return;
+ }
+
+ ASSERT(pinfo->finfo->dvi_in.fp != NULL, "DVI input FILE * must have been set!");
+
+ /* when saving, set the final file names */
+ if (curr_info->range_radio == SAVE_RANGE
+ || curr_info->range_radio == SAVE_MARKED
+ || curr_info->range_radio == SAVE_ALL) {
+ switch (curr_info->output_format) {
+ case FMT_DVI:
+ pinfo->finfo->dvi_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "DVI out_name: |%s|", pinfo->finfo->dvi_out.fname));
+ break;
+ case FMT_PS:
+ pinfo->finfo->ps_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "PS out_name: |%s|", pinfo->finfo->ps_out.fname));
+ break;
+ case FMT_PS2PDF:
+ pinfo->finfo->pdf_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "PDF out_name: |%s|", pinfo->finfo->pdf_out.fname));
+ break;
+ case FMT_ISO_8859_1:
+ case FMT_UTF8:
+ pinfo->finfo->txt_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "TXT out_name: |%s|", pinfo->finfo->txt_out.fname));
+ break;
+ case FMT_NONE:
+ break;
+ }
+ }
+
+ /* add info about page ranges */
+ switch (curr_info->range_radio) {
+ case SAVE_RANGE:
+ case PRINT_RANGE:
+ /* convert from 1-based to 0-based */
+ pinfo->from = strtoul(curr_info->from_page, (char **)NULL, 10) - 1;
+ pinfo->to = strtoul(curr_info->to_page, (char **)NULL, 10) - 1;
+ pinfo->callback = check_pagerange;
+ break;
+ case SAVE_MARKED:
+ case PRINT_MARKED:
+ pinfo->callback = check_marked;
+ break;
+ case SAVE_ALL:
+ case PRINT_ALL:
+ pinfo->callback = NULL;
+ break;
+ case NO_PAGE_VAL:
+ ASSERT(0, "Shouldn't happen: NO_PAGE_VAL passed to popdown_dialog_and_print_or_save()");
+ break;
+ }
+
+ store_preference(NULL, "dvipsOptionsString", "%s", save_pr_info.dvips_options ? save_pr_info.dvips_options : "");
+ if (pinfo->act == FILE_PRINT) {
+ store_preference(NULL, "defaultPrintingTarget", "%d", save_pr_info.print_radio);
+ store_preference(NULL, "dvipsPrinterString", "%s", save_pr_info.printer_name ? save_pr_info.printer_name : "");
+ internal_print(pinfo);
+ }
+ else {
+ store_preference(NULL, "defaultSavingFormat", "%d", save_save_info.output_format);
+ internal_save(pinfo, curr_info->output_format);
+ }
+}
+
+/* Clean up after user has aborted printing/saving */
+static void
+do_cleanup(XtPointer arg)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)arg;
+ struct select_pages_info *pinfo = (struct select_pages_info *)info->pinfo;
+ struct file_info *finfo = pinfo->finfo;
+
+ cancel_saving(info);
+ unlink(finfo->dvi_tmp.fname);
+}
+
+/* XXX: is the save_* stuff actually *needed*??? */
+static Boolean
+validate_and_save_values(struct save_or_print_info *info)
+{
+ int page_range_begin, page_range_end;
+ printOrSaveActionT act = info->act;
+
+ if ((act == FILE_PRINT && curr_pr_info.range_radio == PRINT_RANGE)
+ || (act == FILE_SAVE && curr_save_info.range_radio == SAVE_RANGE)) {
+ page_range_begin = getpageno(page_from_text[act]);
+ page_range_end = getpageno(page_to_text[act]);
+ if (page_range_begin + 1 < 1) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Please specify a valid page range.",
+ "Invalid page range: start (%d) < 1.",
+ page_range_begin + 1);
+ return False;
+ }
+ else if (page_range_begin > page_range_end) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Please specify a valid page range.",
+ "Invalid page range: start (%d) > end (%d).",
+ page_range_begin + 1, page_range_end + 1);
+ return False;
+ }
+ else if (page_range_end + 1 > total_pages) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Please specify a valid page range.",
+ "Invalid page range: end (%d) > total_pages (%d).",
+ page_range_end + 1, total_pages);
+ return False;
+ }
+
+ if (act == FILE_PRINT) {
+ curr_pr_info.from_page = xrealloc(curr_pr_info.from_page, LENGTH_OF_INT + 1);
+ curr_pr_info.to_page = xrealloc(curr_pr_info.to_page, LENGTH_OF_INT + 1);
+ sprintf(curr_pr_info.from_page, "%d", page_range_begin);
+ sprintf(curr_pr_info.to_page, "%d", page_range_end);
+ }
+ else {
+ curr_save_info.from_page = xrealloc(curr_save_info.from_page, LENGTH_OF_INT + 1);
+ curr_save_info.to_page = xrealloc(curr_save_info.to_page, LENGTH_OF_INT + 1);
+ sprintf(curr_save_info.from_page, "%d", page_range_begin);
+ sprintf(curr_save_info.to_page, "%d", page_range_end);
+ }
+ }
+
+ if (act == FILE_PRINT)
+ get_save_window_state(&save_pr_info, &curr_pr_info, act);
+ else
+ get_save_window_state(&save_save_info, &curr_save_info, act);
+
+ return True;
+}
+
+/*
+ * Routines for freeing allocated resources in file_info:
+ * close file pointers, and free file name memory.
+ */
+static void
+free_file_info(struct file_IO *info)
+{
+ if (info->fp != NULL) {
+ fclose(info->fp);
+ info->fp = NULL;
+ }
+ free(info->fname);
+ info->fname = NULL;
+}
+
+static void
+reset_file_info(struct file_info *finfo)
+{
+ free_file_info(&(finfo->dvi_in));
+ free_file_info(&(finfo->dvi_tmp));
+ free_file_info(&(finfo->dvi_out));
+ free_file_info(&(finfo->ps_out));
+ free_file_info(&(finfo->pdf_out));
+ free_file_info(&(finfo->txt_out));
+}
+
+/*
+ First round of sanity checks. Note the use of curr_pr_info here;
+ this is before the values are saved to save_pr_info.
+*/
+static void
+print_precheck1(XtPointer myinfo)
+{
+ /* Initialize structures with defaults. Note: structures are
+ static, so that they survive between calls, and to make memory
+ management with callbacks (and all the stuff in print-internal.c)
+ easier.
+ */
+ struct save_or_print_info *info = (struct save_or_print_info *)myinfo;
+ printOrSaveActionT act = info->act;
+ static struct select_pages_info pinfo = {
+ FILE_ALL, 0, 0, NULL, check_marked, { 0, NULL }, NO_ERROR
+ };
+ static struct file_info finfo = {
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL }
+ };
+ char *ok_button_str = NULL;
+ FILE *fin = NULL;
+
+ /* Return if there are active popups; otherwise, the print process
+ may get messed up */
+ if (raise_message_windows()) {
+ XBell(DISP, 0);
+/* popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell, */
+/* MSG_WARN, NULL, */
+/* "Please close other open message windows first!"); */
+ return;
+ }
+
+ /* free all pointers in case we've been called again */
+ reset_file_info(&finfo);
+
+ pinfo.finfo= &finfo; /* pass finfo in data field of pinfo to callbacks etc. */
+ pinfo.act = act;
+ info->pinfo = &pinfo;
+
+ /* Validate page ranges, and if they are correct, save them to the
+ * appropriate save_save_info/save_print_info structure.
+ * NOTE: From here on, always use the save_* variants to retrieve values!
+ */
+ if (!validate_and_save_values(info))
+ return;
+
+ /* We need to create a temporary DVI file containing the selected or all pages
+ if we want to do one of the following:
+ - print the marked pages
+ - save to a DVI file
+ - print only the marked pages to a PS or a PDF file.
+ */
+ if ((pinfo.act == FILE_PRINT && curr_pr_info.range_radio == PRINT_MARKED)
+ || (pinfo.act == FILE_SAVE
+ && (save_save_info.output_format == FMT_DVI
+ || ((save_save_info.output_format == FMT_PS || save_save_info.output_format == FMT_PS2PDF)
+ && save_save_info.range_radio == SAVE_MARKED)))) {
+ /* need to create a temporary DVI file containing the selected pages */
+ int tmp_fd = xdvi_temp_fd(&(finfo.dvi_tmp.fname)); /* this allocates finfo.dvi_tmp.fname */
+
+ if (tmp_fd == -1) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Couldn't create temporary DVI file for printing: %s", strerror(errno));
+ return;
+ }
+ /* don't use XFOPEN here, since we don't want to treat an error in opening the file as fatal. */
+ /* `b' in mode won't hurt ... */
+ if ((finfo.dvi_tmp.fp = try_fdopen(tmp_fd, "wb+")) == NULL) { /* failure */
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Xdvi needs to create a temporary file containing the "
+ "currently marked pages, but creating that file failed. "
+ "Try to fix the cause of the problem, or choose "
+ "\"Print selected pages\" as a workaround.",
+ "Could not open temp file for writing: %s.\n",
+ strerror(errno));
+ return;
+ }
+ }
+ /* We try to use the original DVI file unless it's corrupted, in which case
+ we ask the user if they want to save the cached copy instead */
+ if ((fin = fopen(globals.dvi_name, "rb")) == NULL
+ || !find_postamble(fin, &(pinfo.errflag))) {
+ Boolean could_not_open = False;
+ if (fin == NULL)
+ could_not_open = True;
+ if (fin)
+ fclose(fin);
+
+ /* if we can't use the temporary file as source for our copy, this is a fatal error */
+ if (!resource.use_temp_fp) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Could not copy DVI file %s: The file %s",
+ globals.dvi_name, could_not_open ? "doesn't exist any more" : "seems to be corrupted");
+ return;
+ }
+
+ /* else, we'll try to use the cached copy of the DVI file */
+ if ((fin = fopen(get_tmp_dvi_name(), "rb")) == NULL) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Something's very wrong here - opening of both the "
+ "original DVI file and the cached copy failed!");
+ return;
+ }
+
+ if (!find_postamble(fin, &(pinfo.errflag))) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Shouldn't happen: Cached copy of the DVI file seems corrupted!");
+ return;
+ }
+ finfo.dvi_in.fp = fin;
+
+ /* tell user about it */
+ if (pinfo.act == FILE_PRINT)
+ ok_button_str = "Print Copy";
+ else
+ ok_button_str = "Save Copy";
+
+ info->message_popup =
+ choice_dialog(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_QUESTION, NULL,
+#ifndef MOTIF
+ NULL, /* TODO: binding for RET? */
+#endif /* MOTIF */
+ NULL, NULL, /* no pre_callbacks */
+ ok_button_str, print_precheck2, (XtPointer)info,
+ "Cancel", do_cleanup, (XtPointer)info,
+ "The DVI file %s %s. Do you want to %s a cached copy of the file?",
+ globals.dvi_name,
+ could_not_open ? "doesn't exist any more" : "seems to be corrupted",
+ pinfo.act == FILE_PRINT ? "print" : "save");
+ }
+ else { /* original DVI file is OK, copy it */
+ finfo.dvi_in.fp = fin;
+ print_precheck2((XtPointer)info);
+ }
+}
+
+static void
+print_precheck2(XtPointer myinfo)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)myinfo;
+ char *expanded_filename = NULL;
+ struct select_pages_info *pinfo = (struct select_pages_info *)info->pinfo;
+ printOrSaveActionT act = pinfo->act;
+ const char *fname;
+
+ /* Return if there are active popups; otherwise, the print process
+ will be messed up. */
+ if (raise_message_windows()) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ /* expand and canonicalize path name */
+ if (act == FILE_PRINT)
+ fname = save_pr_info.file_name;
+ else
+ fname = save_save_info.file_name;
+
+ if (fname == NULL) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_WARN,
+ NULL,
+ "No filename specified!");
+ return;
+ }
+ expanded_filename = expand_homedir(fname); /* this allocates expanded_filename */
+ if (expanded_filename == NULL) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_WARN,
+ "Please specify either a filename or a full path, without using \"~\" or \"~user\".",
+ "Couldn't expand filename \"%s\" to a full path.",
+ fname);
+ return;
+ }
+
+ if (act == FILE_PRINT) {
+ free(save_pr_info.expanded_filename);
+ save_pr_info.expanded_filename = expanded_filename;
+ }
+ else {
+ free(save_save_info.expanded_filename);
+ save_save_info.expanded_filename = expanded_filename;
+ }
+
+
+ if (act == FILE_SAVE && save_save_info.output_format == FMT_DVI) { /* canonicalize filename */
+ char *tmp = expand_filename_append_dvi(save_save_info.expanded_filename, USE_CWD_PATH, False);
+ if (strcmp(tmp, globals.dvi_name) == 0) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ NULL,
+ "Cannot overwrite the current DVI file (%s). "
+ "Please select a different file name.",
+ save_save_info.expanded_filename);
+ free(tmp);
+ return;
+ }
+ free(save_save_info.expanded_filename);
+ save_save_info.expanded_filename = tmp;
+ }
+ if (act == FILE_SAVE || (act == FILE_PRINT && curr_pr_info.print_radio == PRINT_TO_FILE)) {
+ /* check whether to clobber existing file */
+ struct stat statbuf;
+
+ if ((act == FILE_SAVE
+ && stat(save_save_info.expanded_filename, &statbuf) == 0
+ && S_ISREG(statbuf.st_mode))
+ || (act == FILE_PRINT
+ && stat(save_pr_info.expanded_filename, &statbuf) == 0
+ && S_ISREG(statbuf.st_mode))) {
+
+ info->message_popup =
+ choice_dialog(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_QUESTION, NULL,
+#ifndef MOTIF
+ NULL, /* TODO: binding for RET */
+#endif
+ NULL, NULL, /* no pre_callbacks */
+ "Replace", popdown_dialog_and_print_or_save, (XtPointer)info,
+ /*
+ do nothing if user selects `cancel'; this will return to the
+ printing dialog, since user hasn't changed their mind about
+ printing, but would probably just like to choose another filename
+ */
+ "Cancel", NULL, (XtPointer)NULL,
+ "%s already exists.\nDo you want to replace it?",
+ act == FILE_SAVE
+ ? save_save_info.expanded_filename
+ : save_pr_info.expanded_filename);
+ return;
+ }
+ else {
+ popdown_dialog_and_print_or_save(info);
+ }
+ }
+ else {
+ popdown_dialog_and_print_or_save(info);
+ }
+}
+
+/* called from pagesel.c if user marks or unmarks a page in the page list */
+void
+notify_print_dialog_have_marked(Boolean flag)
+{
+ /* Note: check for *both* windows, save and print: */
+
+ static pageRadioT old_value = NO_PAGE_VAL;
+
+ if (save_is_active) {
+ if (!flag && curr_save_info.range_radio == SAVE_MARKED) {
+ /* switch button from `marked' to its previous value */
+ switch (old_value) {
+ case SAVE_ALL:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_all_radio[FILE_SAVE], True, True);
+#else
+ XawToggleSetCurrent(range_all_radio[FILE_SAVE], (XtPointer)old_value);
+#endif
+ break;
+ case SAVE_RANGE:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_from_to_radio[FILE_SAVE], True, True);
+#else
+ XawToggleSetCurrent(range_from_to_radio[FILE_SAVE], (XtPointer)old_value);
+#endif
+ break;
+ default: break;
+ }
+ }
+ else if (flag) {
+ /* switch button to `marked', saving the current value */
+ if (curr_save_info.range_radio != SAVE_MARKED) /* guard for second invocation on mouse release */
+ old_value = curr_save_info.range_radio;
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_marked_radio[FILE_SAVE], True, True);
+#else
+ XawToggleSetCurrent(range_marked_radio[FILE_SAVE], (XtPointer)SAVE_MARKED);
+#endif /* MOTIF */
+ }
+ XtSetSensitive(range_marked_radio[FILE_SAVE], flag);
+ }
+
+ if (print_is_active) {
+ if (!flag && curr_pr_info.range_radio == PRINT_MARKED) {
+ /* switch button from `marked' to its previous value */
+ switch (old_value) {
+ case PRINT_ALL:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_all_radio[FILE_PRINT], True, True);
+#else
+ XawToggleSetCurrent(range_all_radio[FILE_PRINT], (XtPointer)old_value);
+#endif
+ break;
+ case PRINT_RANGE:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_from_to_radio[FILE_PRINT], True, True);
+#else
+ XawToggleSetCurrent(range_from_to_radio[FILE_PRINT], (XtPointer)old_value);
+#endif
+ break;
+ default: break;
+ }
+ }
+ else if (flag) {
+ /* switch button to `marked', saving the current value */
+ if (curr_pr_info.range_radio != PRINT_MARKED) /* guard for second invocation on mouse release */
+ old_value = curr_pr_info.range_radio;
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_marked_radio[FILE_PRINT], True, True);
+#else
+ XawToggleSetCurrent(range_marked_radio[FILE_PRINT], (XtPointer)PRINT_MARKED);
+#endif /* MOTIF */
+ }
+ XtSetSensitive(range_marked_radio[FILE_PRINT], flag);
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/print-dialog.h b/Build/source/texk/xdvik/gui/print-dialog.h
new file mode 100644
index 00000000000..95f73de3e18
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-dialog.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef PRINT_DIALOG_H_
+#define PRINT_DIALOG_H_
+
+#define Xdvi_SAVE_SHELL_NAME "save_popup"
+#define Xdvi_PRINT_SHELL_NAME "print_popup"
+
+typedef enum { FILE_PRINT = 0, FILE_SAVE = 1, FILE_ALL = 2 } printOrSaveActionT;
+
+struct save_or_print_info {
+ printOrSaveActionT act;
+ Widget message_popup;
+ struct select_pages_info *pinfo;
+};
+
+extern void save_or_print_callback(struct save_or_print_info *info);
+extern void cancel_saving(struct save_or_print_info *info);
+extern const char *get_printer_options(void);
+extern char *get_dvips_options(printOrSaveActionT act);
+
+extern void notify_print_dialog_have_marked(Boolean flag);
+
+#endif /* PRINT_DIALOG_H_ */
diff --git a/Build/source/texk/xdvik/gui/print-log.c b/Build/source/texk/xdvik/gui/print-log.c
new file mode 100644
index 00000000000..dd1c26bc008
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-log.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ */
+
+#include <string.h>
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "xdvi-debug.h"
+#include "print-dialog.h"
+#include "print-log.h" /* for adjust_vertically() */
+#include "util.h"
+#include "x_util.h"
+#include "xlwradio.h"
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+/* FIXME: change #if XAW to #if !defined(MOTIF) to make it consistent with other files */
+
+#ifdef MOTIF
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/MessageB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/PanedW.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#else
+# include <X11/Shell.h>
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+
+/* XawFmt8Bit is only available starting with X11R6: */
+# if XtSpecificationRelease < 6
+# define XawFmt8Bit FMT8BIT
+# endif
+
+#endif /* MOTIF */
+
+static Boolean printlog_active = False; /* if the print log is active */
+static Widget printlog_shell = NULL;
+
+/* global callbacks - FIXME: avoid this, by passing the callback as argument to the action? */
+static void (*g_close_callback)(Widget w, XtPointer client_data, XtPointer call_data);
+static void (*g_cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data);
+static void (*g_destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data);
+
+static void printlog_act_close(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_keep(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_unkeep(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_cancel(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_destroy(Widget, XEvent *, String *, Cardinal *);
+
+#ifdef MOTIF
+static void xm_printlog_act_destroy(Widget w, XtPointer a, XtPointer b)
+{
+ UNUSED(w);
+ UNUSED(a);
+ UNUSED(b);
+ ASSERT(g_destroy_callback != NULL, "Callback not initialized");
+ (g_destroy_callback)(NULL, NULL, NULL);
+}
+#endif
+
+static Atom WM_DELETE_WINDOW;
+
+static XtActionsRec printlog_actions[] = {
+ {"printlogIntClose", printlog_act_close},
+ {"printlogIntKeep", printlog_act_keep},
+ {"printlogIntUnkeep", printlog_act_unkeep},
+ {"printlogIntCancel", printlog_act_cancel},
+ {"WM_destroy", printlog_act_destroy },
+};
+
+static char *text_translations = \
+ "<Key>Return:printlogIntClose()\n"
+ "^<Key>c:printlogIntCancel()\n"
+ "^<Key>s:printlogIntKeep()\n"
+ "^<Key>q:printlogIntUnkeep()";
+
+static Widget printlog_text;
+static Widget printlog_close;
+static Widget printlog_unkeep;
+static Widget printlog_cancel;
+
+
+#ifdef MOTIF
+static XmTextPosition printlog_length;
+#else
+static XawTextPosition printlog_length;
+#endif
+
+Boolean
+printlog_raise_active(void)
+{
+ if (printlog_active) {
+ XRaiseWindow(DISP, XtWindow(printlog_shell));
+ return True;
+ }
+ return False;
+}
+
+void
+printlog_popup(void)
+{
+ printlog_length = 0;
+ center_window(printlog_shell, globals.widgets.top_level);
+ XtMapWidget(printlog_shell);
+/* XtPopup(printlog_shell, XtGrabNone); */
+ printlog_active = True;
+#ifndef MOTIF
+ XSetWMProtocols(XtDisplay(printlog_shell), XtWindow(printlog_shell), &WM_DELETE_WINDOW, 1);
+#else
+ XmProcessTraversal(printlog_cancel, XmTRAVERSE_CURRENT);
+ XtOverrideTranslations(printlog_text, XtParseTranslationTable(text_translations));
+#endif
+}
+
+void
+printlog_reset(void)
+{
+ printlog_length = 0;
+}
+
+
+
+void
+printlog_create(const char *title,
+ const char *close_label,
+ void (*close_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ void (*cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ void (*destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ void (*unkeep_callback)(Widget w, XtPointer client_data, XtPointer call_data))
+{
+ /*
+ FIXME BETA: The printlog presents too much detail and is confusing for users.
+ Re-implement it using an `printing page n of m' message,
+ i.e. according to the spec on:
+ http://xdvi.sourceforge.net/gui.html#file-print
+ Possible save the detailed log to a different window that can be viewed
+ via `File -> logs', as described on:
+ http://xdvi.sourceforge.net/gui.html#file-logs
+ */
+ XtAddActions(printlog_actions, XtNumber(printlog_actions));
+ g_destroy_callback = destroy_callback;
+
+#ifndef MOTIF
+ /* Create popup window */
+ if (printlog_shell == NULL) {
+ Widget form, box, paned;
+/* int ddist; */
+/* Dimension w0, w1, w2, w3, b; */
+
+ XtTranslations wm_translations = XtParseTranslationTable("<Message>WM_PROTOCOLS: WM_destroy()");
+ printlog_shell = XtVaCreatePopupShell("printlog",
+ transientShellWidgetClass, globals.widgets.top_level,
+ XtNtitle, title,
+ XtNtransientFor, globals.widgets.top_level,
+ XtNmappedWhenManaged, False,
+ XtNtranslations, wm_translations,
+ XtNtransientFor, globals.widgets.top_level,
+ NULL);
+
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(printlog_shell), "WM_DELETE_WINDOW", False);
+
+ paned = XtVaCreateManagedWidget("paned", panedWidgetClass, printlog_shell, NULL);
+
+ form = XtVaCreateManagedWidget("form", formWidgetClass,
+ paned,
+ XtNdefaultDistance, 6,
+ NULL);
+ printlog_text = XtVaCreateManagedWidget("text",
+ asciiTextWidgetClass, form,
+ XtNstring, "",
+ XtNdataCompression, False,
+ XtNeditType, XawtextAppend,
+ XtNscrollHorizontal, XawtextScrollAlways,
+ XtNscrollVertical, XawtextScrollAlways,
+ XtNwidth, 600,
+ XtNheight, 400,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtOverrideTranslations(printlog_text, XtParseTranslationTable(text_translations));
+
+ printlog_unkeep = XtVaCreateManagedWidget("keep",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ form,
+ XtNlabel, close_label,
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ XtNfromVert, printlog_text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtVaSetValues(printlog_unkeep,
+ XtNstate, resource.dvips_hang > 0 && resource.dvips_fail_hang > 0,
+ NULL);
+ XtAddCallback(printlog_unkeep, XtNcallback, unkeep_callback, NULL);
+
+ /* box for the Close/Cancel button */
+ box = XtVaCreateManagedWidget("box", formWidgetClass,
+ paned,
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the pane widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ printlog_close = XtVaCreateManagedWidget("close",
+ commandWidgetClass, box,
+ XtNlabel, "Close",
+ XtNsensitive, False,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_close, XtNcallback, close_callback, NULL);
+ g_close_callback = close_callback;
+
+ printlog_cancel = XtVaCreateManagedWidget("cancel",
+ commandWidgetClass, box,
+ XtNlabel, "Cancel",
+ XtNfromHoriz, printlog_unkeep,
+ XtNleft, XawChainRight,
+ XtNright, XawChainRight,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_cancel, XtNcallback, cancel_callback, NULL);
+ g_cancel_callback = cancel_callback;
+ XtManageChild(printlog_shell);
+ }
+ else {
+ XtSetSensitive(printlog_close, False);
+ XtSetSensitive(printlog_cancel, True);
+ }
+
+#else /* MOTIF */
+
+ /* Create popup window */
+ if (printlog_shell == NULL) {
+ Widget form, pane, box;
+ XmString str;
+ Arg args[10];
+ int n;
+
+ printlog_shell = XtVaCreatePopupShell("printlog",
+ xmDialogShellWidgetClass, globals.widgets.top_level,
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+ XmNtitle, title,
+ XtNmappedWhenManaged, False,
+ NULL);
+
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(printlog_shell), "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(printlog_shell, WM_DELETE_WINDOW, xm_printlog_act_destroy, NULL);
+
+ pane = XtVaCreateWidget("printlog_pane", xmPanedWindowWidgetClass, printlog_shell,
+ /* make sashes invisible */
+ XmNsashWidth, 1,
+ XmNsashHeight, 1,
+ NULL);
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass, pane,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNautoUnmanage, False,
+ NULL);
+ /* force vertical scrollbars. Under Motif 2.x (2.1.0 and 2.2.2 at least),
+ XmNeditMode must be set early in order to have an effect. */
+ n = 0;
+ XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
+ XtSetArg(args[n], XmNeditable, False); n++;
+ XtSetArg(args[n], XmNrows, 24); n++;
+ XtSetArg(args[n], XmNcolumns, 80); n++;
+
+ printlog_text = XmCreateScrolledText(form, "text", args, n);
+
+ XtVaSetValues(XtParent(printlog_text),
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtManageChild(printlog_text);
+
+ str = XmStringCreateLocalized((char *)close_label);
+ printlog_unkeep = XtVaCreateManagedWidget("keep",
+ xmToggleButtonGadgetClass, form,
+ XmNlabelString, str,
+ XmNnavigationType, XmTAB_GROUP,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(printlog_text),
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_unkeep, XmNvalueChangedCallback, unkeep_callback, NULL);
+ XmToggleButtonGadgetSetState(printlog_unkeep, resource.dvips_hang > 0 && resource.dvips_fail_hang > 0, False);
+
+ /* box for Close/Cancel button */
+ box = XtVaCreateManagedWidget("box", xmFormWidgetClass,
+ pane,
+ NULL);
+
+ str = XmStringCreateLocalized("Close");
+ printlog_close = XtVaCreateManagedWidget("close",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNsensitive, False,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNleftOffset, 10,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_close, XmNactivateCallback, close_callback, NULL);
+ g_close_callback = close_callback;
+
+ str = XmStringCreateLocalized("Cancel");
+ printlog_cancel = XtVaCreateManagedWidget("cancel",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNrightOffset, 10,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_cancel, XmNactivateCallback, cancel_callback, NULL);
+ g_cancel_callback = cancel_callback;
+
+ XtManageChild(box);
+ XtManageChild(form);
+ XtManageChild(pane);
+/* center_window(printlog_shell, globals.widgets.top_level); */
+/* XtMapWidget(printlog_shell); */
+ /* this doesn't help */
+ /* XtOverrideTranslations(form, XtParseTranslationTable(text_translations)); */
+ /* XtOverrideTranslations(pane, XtParseTranslationTable(text_translations)); */
+ }
+ else {
+ XtSetSensitive(printlog_close, False);
+ XtSetSensitive(printlog_cancel, True);
+ }
+#endif
+ adjust_width(printlog_close, printlog_cancel);
+}
+
+void
+printlog_append(const char *str, size_t len)
+{
+#ifndef MOTIF
+
+ static XawTextBlock block = {0, 0, NULL, 0};
+
+ block.ptr = (char *) str;
+ block.length = len;
+ block.format = XawFmt8Bit;
+ while (XawTextReplace(printlog_text, printlog_length, printlog_length, &block)
+ != XawEditDone) {
+ int length;
+
+ XtVaGetValues(printlog_text, XtNlength, &length, NULL);
+ printlog_length = length;
+ }
+ printlog_length += len;
+ XawTextSetInsertionPoint(printlog_text, printlog_length);
+
+#else /* MOTIF */
+
+ XmTextInsert(printlog_text, printlog_length, (char *) str);
+ printlog_length += len;
+ XtVaSetValues(printlog_text, XmNcursorPosition, printlog_length, NULL);
+ XmTextShowPosition(printlog_text, printlog_length);
+
+#endif /* MOTIF */
+}
+
+void
+printlog_append_str(const char *str)
+{
+ printlog_append(str, strlen(str));
+}
+
+/* disable cancel button, enable close button */
+void
+printlog_enable_closebutton(void)
+{
+ XtSetSensitive(printlog_close, True);
+ XtSetSensitive(printlog_cancel, False);
+#if MOTIF
+ XmProcessTraversal(printlog_close, XmTRAVERSE_CURRENT);
+#endif
+}
+
+static void
+printlog_internal_close(void)
+{
+ XtUnmapWidget(printlog_shell);
+ printlog_active = False;
+#ifndef MOTIF
+ XtVaSetValues(printlog_text, XtNstring, "", NULL);
+#else
+ XmTextSetString(printlog_text, "");
+#endif
+}
+
+void
+printlog_popdown(Boolean force)
+{
+ if (force) { /* user clicked on `Close' */
+ printlog_internal_close();
+ }
+ else { /* timer elapsed */
+#ifndef MOTIF
+ Boolean state;
+ XtVaGetValues(printlog_unkeep, XtNstate, &state, NULL);
+ if (state) {
+ printlog_internal_close();
+ }
+#else
+ if (XmToggleButtonGadgetGetState(printlog_unkeep)) {
+ printlog_internal_close();
+ }
+#endif
+ }
+}
+
+
+static void
+printlog_act_close(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(g_close_callback != NULL, "Callback not initialized");
+ (g_close_callback)(NULL, NULL, NULL);
+}
+
+static void
+printlog_act_keep(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(printlog_unkeep, False, False);
+#else
+ XtVaSetValues(printlog_unkeep, XtNstate, False, NULL);
+#endif
+}
+
+
+
+static void
+printlog_act_unkeep(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(printlog_unkeep, True, False);
+#else
+ XtVaSetValues(printlog_unkeep, XtNstate, True, NULL);
+#endif
+}
+
+static void
+printlog_act_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(g_cancel_callback != NULL, "Callback not initialized");
+ (g_cancel_callback)(NULL, NULL, NULL);
+}
+
+static void
+printlog_act_destroy(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT((g_destroy_callback) != NULL, "Callback not initialized");
+ (g_destroy_callback)(NULL, NULL, NULL);
+}
diff --git a/Build/source/texk/xdvik/gui/print-log.h b/Build/source/texk/xdvik/gui/print-log.h
new file mode 100644
index 00000000000..90e69be8343
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-log.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef PRINT_LOG_H_
+#define PRINT_LOG_H_
+
+/* printlog access functions */
+
+extern void printlog_create(const char *title,
+ const char *close_label,
+ /* callback for `close' button */
+ void (*close_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ /* callback for `cancel' button */
+ void (*cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ /* callback for destroying window via window manager */
+ void (*destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ /* callback for `close automatically' checkbox */
+ void (*unkeep_callback)(Widget w, XtPointer client_data, XtPointer call_data));
+extern Boolean printlog_raise_active(void);
+extern void printlog_popup(void);
+extern void printlog_reset(void);
+extern void printlog_append(const char *str, size_t len);
+extern void printlog_append_str(const char *str);
+extern void printlog_enable_closebutton(void);
+extern void printlog_popdown(Boolean override_timer);
+
+#endif /* PRINT_LOG_H_ */
diff --git a/Build/source/texk/xdvik/gui/search-dialog.c b/Build/source/texk/xdvik/gui/search-dialog.c
new file mode 100644
index 00000000000..c77fa9d219e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/search-dialog.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (c) 2003-2004 Stefan Ulrich
+ *
+ * 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.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "events.h"
+#include "dvi-init.h"
+#include "search-dialog.h"
+#include "search-internal.h"
+#include "xlwradio.h"
+#include "statusline.h"
+#include "string-utils.h"
+#include "util.h"
+#include "message-window.h"
+#include "x_util.h"
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#ifdef MOTIF
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/PanedW.h>
+# include <Xm/MessageB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#else /* MOTIF */
+# include <X11/Shell.h>
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+#endif /* MOTIF */
+
+/* #defines for widgets that are used in common code */
+#ifdef MOTIF
+# define SHELL_WIDGET xmDialogShellWidgetClass
+# define PANED_WIDGET xmPanedWindowWidgetClass
+# define FORM_WIDGET xmFormWidgetClass
+# define LABEL_WIDGET xmLabelGadgetClass
+# define TEXT_WIDGET xmTextFieldWidgetClass
+# define CHECKBOX_WIDGET xmToggleButtonGadgetClass
+# define CHECKBUTTON_IS_SET XmNset
+# define PUSHBUTTON_WIDGET xmPushButtonWidgetClass
+# define VALUE_CALLBACK_NAME XmNvalueChangedCallback
+# define ACTIVATE_CALLBACK_NAME XmNactivateCallback
+#else /* MOTIF */
+# define SHELL_WIDGET transientShellWidgetClass
+# define PANED_WIDGET panedWidgetClass
+# define FORM_WIDGET formWidgetClass
+# define LABEL_WIDGET labelWidgetClass
+# define TEXT_WIDGET asciiTextWidgetClass
+# ifdef XAW
+# define CHECKBOX_WIDGET radioWidgetClass
+# else /* XAW */
+# define CHECKBOX_WIDGET toggleWidgetClass
+# endif /* XAW */
+# define CHECKBUTTON_IS_SET XtNstate
+# define PUSHBUTTON_WIDGET commandWidgetClass
+# define VALUE_CALLBACK_NAME XtNcallback
+# define ACTIVATE_CALLBACK_NAME XtNcallback
+#endif /* MOTIF */
+
+static Boolean m_find_popup_active = False;
+
+/* flags for setting single bits in resource.search_window_defaults */
+static const int SETTINGS_USE_REGEXP_FLAG = 1;
+static const int SETTINGS_CASE_SENSITIVE_FLAG = 2;
+static const int SETTINGS_BACKWARDS_FLAG = 4;
+static const int SETTINGS_IGNORE_LINEBREAKS_FLAG = 8;
+
+
+static void
+cb_search_go(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ Widget find_popup;
+ Position x = 0, y = 0;
+
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(call_data);
+
+ TRACE_FIND((stderr, "cb_search_go: settings: searchterm=|%s|, down = %d, re = %d, case = %d",
+ settings->term, settings->direction, settings->use_regexp, settings->case_sensitive));
+
+ /* retrieve the find popup window */
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
+ x = y = 0;
+ }
+ else {
+ XtVaGetValues(find_popup, XtNx, &x, XtNy, &y, NULL);
+ /* add some offsets */
+ settings->x_pos = x + 10;
+ settings->y_pos = y + 10;
+ TRACE_GUI((stderr, "SHELL: %ld; x: %d, y: %d", (unsigned long)w, x, y));
+ }
+
+ settings->from_page = current_page;
+ settings->message_window = 0;
+ TRACE_FIND((stderr, "starting search from page: %d", settings->from_page));
+ search_dvi((XtPointer)settings);
+}
+
+static void
+show_settings(const char *func_name, struct search_settings *settings)
+{
+ TRACE_FIND((stderr, "%s: settings: str=|%s|, down = %d, re = %d, "
+ "case = %d, ignore_hyphens = %d, ignore_linebreaks = %d\n",
+ func_name,
+ settings->term,
+ settings->direction,
+ settings->use_regexp,
+ settings->case_sensitive,
+ settings->ignore_hyphens,
+ settings->ignore_linebreaks));
+
+}
+
+
+static void
+cb_regexp_search(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ /* Hack: Since XawToggleUnsetCurrent() will invoke this callback again,
+ return every second time to avoid multiple popups. This is done by
+ setting the flag `do_return'.
+ */
+#if !HAVE_REGEX_H
+ static Boolean do_return = False;
+#endif
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(call_data);
+
+#if !HAVE_REGEX_H
+ if (do_return) {
+ do_return = False;
+ return;
+ }
+
+ XBell(DISP, 0);
+ popup_message(get_matching_parent(w, globals.widgets.top_level, "find_popup", NULL),
+ MSG_ERR,
+ NULL,
+ "Sorry, regular expression support (regex.h) is not available on this platform.");
+ do_return = True;
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(w, True, False);
+#else
+ XawToggleUnsetCurrent(w);
+#endif
+
+#else
+ UNUSED(w);
+ settings->use_regexp = !(settings->use_regexp);
+
+ /* force re-initialization of search term by resetting utf8_term: */
+ free(settings->utf8_term);
+ settings->utf8_term = NULL;
+
+ show_settings("cb_regexp_search", settings);
+#endif
+
+ if (settings->use_regexp)
+ resource.search_window_defaults |= SETTINGS_USE_REGEXP_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_USE_REGEXP_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_backwards_search(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(w);
+ UNUSED(call_data);
+
+ switch (settings->direction) {
+ case SEARCH_UP: settings->direction = SEARCH_DOWN; break;
+ case SEARCH_DOWN: settings->direction = SEARCH_UP; break;
+ default: ASSERT(0, "shouldn't happen: settings->direction is neither SEARCH_UP nor SEARCH_DOWN!"); break;
+ }
+
+ show_settings("cb_backwards_search", settings);
+
+ if (settings->direction == SEARCH_UP)
+ resource.search_window_defaults |= SETTINGS_BACKWARDS_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_BACKWARDS_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_match_case(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(w);
+ UNUSED(call_data);
+
+ settings->case_sensitive = !(settings->case_sensitive);
+
+ show_settings("cb_match_case", settings);
+
+ if (settings->case_sensitive)
+ resource.search_window_defaults |= SETTINGS_CASE_SENSITIVE_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_CASE_SENSITIVE_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_linebreaks(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(w);
+ UNUSED(call_data);
+
+ settings->ignore_linebreaks = !(settings->ignore_linebreaks);
+ settings->ignore_hyphens = !(settings->ignore_hyphens);
+
+ show_settings("cb_linebreaks", settings);
+
+ if (settings->ignore_linebreaks)
+ resource.search_window_defaults |= SETTINGS_IGNORE_LINEBREAKS_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_IGNORE_LINEBREAKS_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_search_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget find_popup;
+ struct search_settings *settings = (struct search_settings *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ /* retrieve the find popup window */
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
+ return;
+ }
+
+ /* This flag is checked in the scanning routines, and
+ will be eventually reset by do_pages() in events.c.
+ (The scanning routines musn't reset it, since they
+ might not be called again after this point!) */
+ globals.ev.flags |= EV_FIND_CANCEL;
+
+ search_signal_page_changed(); /* Hack to make search restart anew */
+ search_erase_highlighting(True);
+ if (settings->message_window != 0) {
+ TRACE_GUI((stderr, "kill_message_window: %p\n", (void *)settings->message_window));
+ kill_message_window(settings->message_window);
+ }
+ XtPopdown(find_popup);
+ m_find_popup_active = False;
+}
+
+static void
+cb_search_get_term_button(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ char *searchterm = NULL;
+
+ Widget searchbox_input, paned, box;
+ UNUSED(call_data);
+
+ box = XtParent(w);
+ ASSERT(box != 0, "Parent of button widget mustn't be NULL!");
+ paned = XtParent(box);
+ ASSERT(paned != 0, "Parent of box widget mustn't be NULL!");
+
+ if ((searchbox_input = XtNameToWidget(paned, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+
+#ifdef MOTIF
+ XtVaGetValues(searchbox_input, XmNvalue, &searchterm, NULL);
+#else
+ XtVaGetValues(searchbox_input, XtNstring, &searchterm, NULL);
+#endif
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Searchterm in cb_search_get_term callback shouldn't be NULL!"));
+ return;
+ }
+ TRACE_FIND((stderr, "searchterm1: |%s|", searchterm));
+ settings->term = searchterm;
+
+ cb_search_go(w, settings, NULL);
+}
+
+static void
+search_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct search_settings *settings = NULL;
+ void *ptr;
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in search_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in search_cancel mustn't be NULL!");
+
+ /*
+ * the *params char pointer contains the pointer value (address) of `settings';
+ * convert it back to a pointer:
+ */
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+ TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
+ ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
+
+ cb_search_cancel(w, settings, NULL);
+}
+
+#ifdef MOTIF
+
+static void
+cb_search_get_term(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ char *searchterm = NULL;
+ Widget form, paned, searchbox_form;
+ Widget button;
+ XEvent ev;
+ UNUSED(call_data);
+
+ /* retrieve the `Find' button widget */
+ searchbox_form = XtParent(w);
+ ASSERT(searchbox_form != 0, "Parent of button widget mustn't be NULL!");
+ form = XtParent(searchbox_form);
+ ASSERT(form != 0, "Parent of searchbox_form widget mustn't be NULL!");
+ paned = XtParent(form);
+ ASSERT(paned != 0, "Parent of form widget mustn't be NULL!");
+ if ((button = XtNameToWidget(paned, "*find_button")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_button\" widget!"));
+ return;
+ }
+
+ if (settings != NULL) {
+ /* retrieve search term from text input field */
+ XtVaGetValues(w, XmNvalue, &searchterm, NULL);
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Searchterm in cb_search_get_term callback shouldn't be NULL!"));
+ return;
+ }
+
+ TRACE_FIND((stderr, "searchterm2: |%s|", searchterm));
+ settings->term = (const char *)searchterm;
+ }
+
+ /* make the `Find' button think it got pushed.
+ Also synthetisize an event, just to be sure ... */
+ synthetisize_event(&ev, button);
+
+ XtCallActionProc(button, "ArmAndActivate", &ev, NULL, 0);
+ /* the following don't make the button appear visually pressed: */
+ /* XtCallCallbacks(button, XmNarmCallback, NULL); */
+ /* XtCallCallbacks(button, XmNactivateCallback, NULL); */
+}
+
+static void
+xm_search_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct search_settings *settings = NULL;
+ void *ptr;
+ Widget input;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (params != NULL) { /* re-initialize search term */
+ ASSERT(*num_params == 1, "num_params in xm_search_go should be 1 if *params != NULL");
+ /*
+ * the *params char pointer contains the pointer value (address) of `settings';
+ * convert it back to a pointer:
+ */
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+ TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
+ ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
+ }
+
+ if ((input = XtNameToWidget(globals.widgets.top_level, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+ cb_search_get_term(input, settings, NULL);
+}
+
+#else /* MOTIF */
+
+static void
+xaw_unset_button(XtPointer client_data, XtIntervalId *id)
+{
+ XEvent ev;
+ Widget button = (Widget)client_data;
+
+ UNUSED(id);
+
+ synthetisize_event(&ev, button);
+ XtCallActionProc(button, "unset", &ev, NULL, 0);
+}
+
+static void
+xaw_search_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct search_settings *settings = NULL;
+ void *ptr;
+ char *searchterm = NULL;
+ Widget button, input;
+ XtIntervalId timeout;
+
+ UNUSED(w);
+
+ /* retrieve the `Find' button widget */
+ if ((button = XtNameToWidget(globals.widgets.top_level, "*find_button")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_button\" widget!"));
+ return;
+ }
+ if ((input = XtNameToWidget(globals.widgets.top_level, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+
+ XtVaGetValues(input, XtNstring, &searchterm, NULL);
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Searchterm in xaw_search_go callback shouldn't be NULL!"));
+ return;
+ }
+
+ if (params != NULL) { /* re-initialize search term */
+ ASSERT(*num_params == 1, "num_params in xaw_search_go should be 1 if *params != NULL");
+ /*
+ * the *params char pointer contains the pointer value (address) of `settings';
+ * convert it back to a pointer:
+ */
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+ TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
+ ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
+
+ settings->term = (const char *)searchterm;
+ }
+
+ /*
+ * Again, we want the button to appear activated when <RETURN> is pressed.
+ * For this, we explicitly invoke set()notify(), and unset() after a timeout
+ * of 150 milliseconds, which seems to correspond to the Motif default.
+ */
+ XtCallActionProc(button, "set", event, NULL, 0);
+ XtCallActionProc(button, "notify", event, NULL, 0);
+ XSync(DISP, False);
+ timeout = XtAppAddTimeOut(app, 150, xaw_unset_button, (XtPointer)button);
+}
+
+
+/*
+ * Restart search from within another popup (confirmation) window.
+ */
+static void
+xaw_search_restart(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ void *ptr;
+ struct search_settings *settings;
+
+ UNUSED(event);
+ UNUSED(w);
+
+ ASSERT(*num_params > 0, "params in xaw_search_restart must be > 0!");
+ ASSERT(*params != NULL, "params in xaw_search_restart mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+
+ search_restart((XtPointer)settings);
+}
+
+static XtActionsRec xaw_search_actions[] = {
+ { "do-search-restart", xaw_search_restart },
+ { "do-search", xaw_search_go },
+};
+#endif /* MOTIF */
+
+static XtActionsRec search_actions[] = {
+ { "do-search",
+#ifdef MOTIF
+ xm_search_go
+#else
+ xaw_search_go
+#endif
+ },
+ { "cancel-search", search_cancel },
+};
+
+static Widget
+create_search_window(struct search_settings *settings)
+{
+ Widget top_level_shell;
+ Atom WM_DELETE_WINDOW;
+ Widget form, find_paned, box;
+ unsigned char curr_state;
+
+ Widget searchbox_form, searchbox_label, searchbox_input;
+ /* left and right column */
+ Widget options_left_form, options_right_form;
+ /* checkboxes in left column */
+ Widget regexp_checkbox, matchcase_checkbox, backwards_checkbox;
+ /* checkboxes in right column */
+ Widget linebreaks_checkbox;
+ Widget find_button, cancel_button;
+
+ XtTranslations xlats;
+ char *translation_str = NULL;
+#ifdef MOTIF
+ XmString str;
+#else /* MOTIF */
+ XtTranslations wm_translations;
+ int ddist;
+#endif
+
+ XtAddActions(search_actions, XtNumber(search_actions));
+
+#ifndef MOTIF
+
+ XtAddActions(xaw_search_actions, XtNumber(xaw_search_actions));
+#define HORIZONTAL_RESIZING_NO XtNleft, XtChainLeft, XtNright, XtChainLeft
+#define HORIZONTAL_RESIZING_YES XtNleft, XtChainLeft, XtNright, XtChainRight
+#define VERTICAL_RESIZING_NO XtNtop, XtChainTop, XtNbottom, XtChainTop
+
+ /*
+ * hacky: Since translations can only contain strings, pass
+ * the pointer address as string in the callback. But the only
+ * portability problem should be the size of the pointer
+ * representation, and we deal with that by using VSNPRINTF().
+ */
+ translation_str = get_string_va("<Message>WM_PROTOCOLS: cancel-search(%p)\nCtrl<Key>g:find-next()",
+ (void *)settings);
+ wm_translations = XtParseTranslationTable(translation_str);
+ free(translation_str);
+ translation_str = NULL;
+#endif /* not MOTIF */
+
+ top_level_shell = XtVaCreatePopupShell("find_popup",
+ SHELL_WIDGET,
+ globals.widgets.top_level,
+ XtNtitle, "xdvik: Find in DVI file",
+ XtNmappedWhenManaged, False, /* so that we can center it first */
+ XtNtransientFor, globals.widgets.top_level,
+ XtNallowShellResize, True,
+#ifdef MOTIF
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+#else
+ XtNtranslations, wm_translations,
+#endif
+ NULL);
+
+ TRACE_GUI((stderr, "toplevel: %ld", (unsigned long)top_level_shell));
+
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
+#ifdef MOTIF
+ XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_search_cancel, settings);
+#endif
+
+ find_paned = XtVaCreateWidget("find_paned",
+ PANED_WIDGET,
+ top_level_shell,
+#ifdef MOTIF
+ /* make sashes invisible */
+ XmNsashWidth, 1,
+ XmNsashHeight, 1,
+#endif
+ NULL);
+
+ form = XtVaCreateWidget("form",
+ FORM_WIDGET,
+ find_paned,
+#ifdef MOTIF
+ XmNhorizontalSpacing, DDIST_MAJOR,
+ XmNverticalSpacing, DDIST_MAJOR,
+ XmNautoUnmanage, False,
+#else
+ XtNallowResize, True,
+#endif
+ NULL);
+
+#ifdef MOTIF
+ str = XmStringCreateLocalized("Find:");
+#else
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+#endif
+
+ /* search term input field */
+ searchbox_form = XtVaCreateWidget("searchbox_form",
+ FORM_WIDGET,
+ form,
+#ifdef MOTIF
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+#else
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_YES,
+#endif
+ NULL);
+ searchbox_label = XtVaCreateManagedWidget("searchbox_label",
+ LABEL_WIDGET,
+ searchbox_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+#else
+ XtNlabel, "Find:",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ searchbox_input = XtVaCreateManagedWidget("searchbox_input",
+ TEXT_WIDGET,
+ searchbox_form,
+#ifdef MOTIF
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, searchbox_label,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ XtNwidth, 260,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, searchbox_label,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+
+ if (settings->term != NULL) {
+ XtVaSetValues(searchbox_input,
+#ifdef MOTIF
+ XmNvalue,
+#else
+ XtNstring,
+#endif
+ settings->term, NULL);
+ }
+
+ XtManageChild(searchbox_form);
+
+#ifdef MOTIF
+ XtAddCallback(searchbox_input, XmNactivateCallback, cb_search_get_term, settings);
+#endif
+
+ /*
+ * form for left row of options checkbuttons
+ */
+ options_left_form = XtVaCreateManagedWidget("options_left_form",
+ FORM_WIDGET,
+ form,
+#ifdef MOTIF
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, searchbox_form,
+ XmNleftAttachment, XmATTACH_FORM,
+/* XmNrightAttachment, XmATTACH_FORM, */
+/* XmNbottomAttachment, XmATTACH_FORM, */
+#else
+ XtNborderWidth, 0,
+ XtNfromVert, searchbox_form,
+ HORIZONTAL_RESIZING_NO,
+#endif
+ NULL);
+ /*
+ * form for right row of options checkbuttons
+ */
+ options_right_form = XtVaCreateManagedWidget("options_right_form",
+ FORM_WIDGET,
+ form,
+#ifdef MOTIF
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, searchbox_form,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, options_left_form,
+ XmNrightAttachment, XmATTACH_FORM,
+/* XmNbottomAttachment, XmATTACH_FORM, */
+#else
+ XtNborderWidth, 0,
+ XtNfromVert, searchbox_form,
+ XtNfromHoriz, options_left_form,
+ HORIZONTAL_RESIZING_NO,
+#endif
+ NULL);
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Regular expression");
+#endif
+
+ regexp_checkbox = XtVaCreateManagedWidget("regexp_checkbox",
+ CHECKBOX_WIDGET,
+ options_left_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Regular expression",
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(regexp_checkbox, VALUE_CALLBACK_NAME, cb_regexp_search, settings);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Find backwards");
+#endif
+
+ backwards_checkbox = XtVaCreateManagedWidget("backwards_checkbox",
+ CHECKBOX_WIDGET,
+ options_left_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, regexp_checkbox,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Find backwards",
+ XtNfromVert, regexp_checkbox,
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(backwards_checkbox, VALUE_CALLBACK_NAME, cb_backwards_search, settings);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Case sensitive");
+#endif
+
+ matchcase_checkbox = XtVaCreateManagedWidget("matchcase_checkbox",
+ CHECKBOX_WIDGET,
+ options_right_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Case sensitive",
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(matchcase_checkbox, VALUE_CALLBACK_NAME, cb_match_case, settings);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Ignore newlines/hyphens");
+#endif
+
+ linebreaks_checkbox = XtVaCreateManagedWidget("linebreaks_checkbox",
+ CHECKBOX_WIDGET,
+ options_right_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, matchcase_checkbox,
+ XmNleftAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Ignore newlines/hyphens",
+ XtNfromVert, matchcase_checkbox,
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(linebreaks_checkbox, VALUE_CALLBACK_NAME, cb_linebreaks, settings);
+
+ /*
+ * box for Find/Cancel buttons
+ */
+ box = XtVaCreateManagedWidget("box",
+ FORM_WIDGET,
+ find_paned,
+#ifdef MOTIF
+ XmNskipAdjust, True, /* don't resize this area */
+#else
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the pane widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+#endif
+ NULL);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Find");
+#endif
+
+ find_button = XtVaCreateManagedWidget("find_button",
+ PUSHBUTTON_WIDGET,
+ box,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNleftOffset, 10,
+#else
+ XtNlabel, "Find",
+ XtNaccelerators, G_accels_cr,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ HORIZONTAL_RESIZING_NO,
+#endif
+ NULL);
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Cancel");
+#endif
+
+ cancel_button = XtVaCreateManagedWidget("cancel_button",
+ PUSHBUTTON_WIDGET,
+ box,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNrightOffset, 10,
+#else
+ XtNlabel, "Cancel",
+ XtNfromHoriz, find_button,
+ XtNbottom, XtChainBottom,
+ XtNjustify, XtJustifyRight,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+#endif
+ NULL);
+
+#ifdef MOTIF
+ XmStringFree(str);
+#endif
+
+ XtAddCallback(cancel_button, ACTIVATE_CALLBACK_NAME, cb_search_cancel, settings);
+ XtAddCallback(find_button, ACTIVATE_CALLBACK_NAME, cb_search_get_term_button, settings);
+
+ translation_str = get_string_va(
+#ifdef MOTIF
+ "<Key>osfCancel:cancel-search(%p)\n"
+#else
+ "<Key>Escape:cancel-search(%p)\n"
+#endif
+ "<Key>Return:do-search(%p)\n"
+ "Ctrl<Key>g:find-next()",
+ (void *)settings, (void *)settings);
+
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+
+ XtOverrideTranslations(searchbox_form, xlats);
+ XtOverrideTranslations(options_left_form, xlats);
+ XtOverrideTranslations(options_right_form, xlats);
+ XtOverrideTranslations(regexp_checkbox, xlats);
+ XtOverrideTranslations(matchcase_checkbox, xlats);
+ XtOverrideTranslations(backwards_checkbox, xlats);
+ XtOverrideTranslations(box, xlats);
+ XtOverrideTranslations(find_button, xlats);
+ XtOverrideTranslations(cancel_button, xlats);
+ XtOverrideTranslations(searchbox_input, xlats);
+
+ /* following doesn't help to force input to textbox in xaw: */
+ /* XtInstallAllAccelerators(find_paned, find_paned); */
+ /* XtInstallAllAccelerators(searchbox_input, find_paned); */
+
+ XtManageChild(form);
+ XtManageChild(find_paned);
+
+ { /* set all buttons to same size */
+ Dimension w1, w2, max;
+ XtVaGetValues(find_button, XtNwidth, &w1, NULL);
+ XtVaGetValues(cancel_button, XtNwidth, &w2, NULL);
+ max = MAX(w1, w2);
+ XtVaSetValues(find_button, XtNwidth, max, NULL);
+ XtVaSetValues(cancel_button, XtNwidth, max, NULL);
+ }
+
+ XtManageChild(top_level_shell);
+ /* don't center this one - would just get in the way in this case. */
+ /* center_window(top_level_shell, globals.widgets.top_level); */
+ XtPopup(top_level_shell, XtGrabNone);
+ m_find_popup_active = True;
+
+#ifdef MOTIF
+ XmProcessTraversal(searchbox_input, XmTRAVERSE_CURRENT);
+/* XmProcessTraversal(find_button, XmTRAVERSE_CURRENT); */
+#endif
+ XSetWMProtocols(XtDisplay(top_level_shell), XtWindow(top_level_shell), &WM_DELETE_WINDOW, 1);
+
+ /* check if we have default values from resource.search_window_defaults */
+ if (resource.search_window_defaults & SETTINGS_USE_REGEXP_FLAG)
+ XtVaSetValues(regexp_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+ if (resource.search_window_defaults & SETTINGS_CASE_SENSITIVE_FLAG)
+ XtVaSetValues(matchcase_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+ if (resource.search_window_defaults & SETTINGS_BACKWARDS_FLAG)
+ XtVaSetValues(backwards_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+ if (resource.search_window_defaults & SETTINGS_IGNORE_LINEBREAKS_FLAG)
+ XtVaSetValues(linebreaks_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+
+ /* initialize `settings' values according to the checkbox states
+ (in case user has assigned values via X defaults): */
+ XtVaGetValues(regexp_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->use_regexp = curr_state;
+ XtVaGetValues(matchcase_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->case_sensitive = curr_state;
+ XtVaGetValues(backwards_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->direction = curr_state ? SEARCH_UP : SEARCH_DOWN;
+ XtVaGetValues(linebreaks_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->ignore_hyphens = settings->ignore_linebreaks = curr_state;
+
+#ifndef MOTIF
+
+#undef HORIZONTAL_RESIZING_NO
+#undef HORIZONTAL_RESIZING_YES
+#undef VERTICAL_RESIZING_NO
+
+#endif /* MOTIF */
+ return top_level_shell;
+}
+
+void
+dvi_find_string(const char *str, Boolean find_next)
+{
+ /* Synthesize a RET keystroke for the find dialog.
+ * Also pops up the find dialog, to make it easier for user to
+ * edit options, change direction etc. */
+ Widget find_popup;
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ static struct search_settings settings;
+ static struct search_info searchinfo = { False, False, False, 0, 0, 0, 0 };
+ settings.term = str;
+ settings.use_regexp = False;
+ settings.case_sensitive = False;
+ settings.direction = SEARCH_DOWN;
+ settings.ignore_hyphens = False;
+ settings.ignore_linebreaks = False;
+ settings.x_pos = -1;
+ settings.y_pos = -1;
+ settings.searchinfo = &searchinfo;
+ settings.hyphen_delta = 0;
+
+ find_popup = create_search_window(&settings);
+
+ if (find_next)
+ return;
+ }
+ else if (str != NULL) { /* change the search term */
+ Widget searchbox_input;
+ if ((searchbox_input = XtNameToWidget(find_popup, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+ XtVaSetValues(searchbox_input,
+#ifdef MOTIF
+ XmNvalue,
+#else
+ XtNstring,
+#endif
+ str, NULL);
+ }
+ if (m_find_popup_active) {
+ XRaiseWindow(DISP, XtWindow(find_popup));
+ }
+ else {
+ XtPopup(find_popup, XtGrabNone);
+ m_find_popup_active = True;
+ }
+
+ if (str != NULL || find_next) {
+#ifdef MOTIF
+ xm_search_go(NULL, NULL, NULL, NULL);
+#else
+ xaw_search_go(NULL, NULL, NULL, NULL);
+#endif
+ }
+}
+
diff --git a/Build/source/texk/xdvik/gui/search-dialog.h b/Build/source/texk/xdvik/gui/search-dialog.h
new file mode 100644
index 00000000000..c272658d021
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/search-dialog.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2004 Stefan Ulrich
+ *
+ * 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.
+ */
+
+#ifndef SEARCH_DIALOG_H_
+#define SEARCH_DIALOG_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+typedef enum { SEARCH_UP = 0, SEARCH_DOWN, SEARCH_UNINITIALIZED } searchDirectionT;
+
+/* bounding box info for words. */
+struct bbox {
+ int ulx, uly, lrx, lry;
+};
+
+struct search_info {
+ Boolean have_match;
+ Boolean locked; /* to block multiple searches */
+ Boolean search_wrapped; /* if restarting from start (or end) */
+ int from_pos;
+ int to_pos;
+ int scan_page;
+ int page_offset; /* start of current scan */
+};
+
+
+struct search_settings {
+ const char *term; /* original search term */
+ char *utf8_term; /* term in UTF-8 encoding */
+ char *posix_term; /* utf8_term with Perl abbreviations mapped to POSIX */
+ Boolean use_regexp;
+ Boolean case_sensitive;
+ Boolean ignore_hyphens;
+ Boolean ignore_linebreaks;
+ searchDirectionT direction;
+ struct search_info *searchinfo;
+ /* internal state management */
+ int x_pos, y_pos; /* position of the search popup window */
+ int from_page; /* page to start search from */
+ int curr_page; /* current page of search search from */
+ int to_page; /* highest page already scanned */
+ int hyphen_delta; /* difference in offsets when hyphenation is removed */
+ Widget message_window; /* warning popup, or NULL if it doesn't exist */
+};
+
+extern void dvi_find_string(const char *str, Boolean find_next);
+
+#endif /* SEARCH_DIALOG_H_ */
diff --git a/Build/source/texk/xdvik/gui/selection.c b/Build/source/texk/xdvik/gui/selection.c
new file mode 100644
index 00000000000..e0bef1e5f1e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/selection.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <string.h>
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#if HAVE_X11_XMU_XMU_H
+#include <X11/Xmu/Atoms.h>
+#include <X11/Xmu/Xmu.h>
+#endif
+
+#include "events.h"
+#include "util.h"
+#include "encodings.h"
+#include "message-window.h"
+#include "selection.h"
+#include "statusline.h"
+
+/*
+ * Set the current X selection (i.e. the primary selection AKA XA_PRIMARY).
+ * Most of this is copied from Asente/Converse/Swick: X Window System Toolkit Manual
+ */
+
+/* This is file scope since deliver_selection_cb() needs access to it.
+ * I guess we could also store it in an Atom, but why bother ...
+ */
+static char *m_selection_text = NULL;
+static char *m_cvt_selection_text = NULL;
+static size_t m_selection_size = 0;
+
+/* helper routine */
+static Atom
+fetch_atom(Widget w, const char *name)
+{
+ Atom a;
+ XrmValue source, dest;
+
+ source.size = strlen(name) + 1;
+ source.addr = (char *)name;
+ dest.size = sizeof a;
+ dest.addr = (caddr_t)&a;
+
+ (void)XtConvertAndStore(w, XtRString, &source, XtRAtom, &dest);
+ return a;
+}
+
+/* Lose the selection */
+static void
+lose_selection_cb(Widget w, Atom *selection)
+{
+ UNUSED(w);
+ UNUSED(selection);
+
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+}
+
+static char *
+utf8_to_native_encoding(const char *utf8)
+{
+ static const char *text_encoding = NULL;
+
+ /* convert to user encoding, similar to search-internal.c */
+ if (text_encoding == NULL) {
+ text_encoding = get_text_encoding();
+ }
+
+ if (memicmp(text_encoding, "iso-8859-1", strlen("iso-8859-1")) == 0
+ || memicmp(text_encoding, "iso8859-1", strlen("iso8859-1")) == 0) {
+ return str_utf8_to_iso_8859_1(utf8);
+ }
+ else if (memicmp(text_encoding, "utf-8", strlen("utf-8")) != 0
+ && memicmp(text_encoding, "utf8", strlen("utf8")) != 0) {
+ /* some other encoding */
+ return iconv_convert_string("utf-8", text_encoding, utf8);
+ }
+ /* fallback */
+ return xstrdup(utf8);
+}
+
+/* Deliver the selection. Only supports XA_STRING. */
+static Boolean
+deliver_selection_cb(Widget w,
+ Atom *selection,
+ Atom *target,
+ Atom *type,
+ XtPointer *value,
+ unsigned long *length,
+ int *format)
+{
+ Atom targets = fetch_atom(w, "TARGETS");
+ Atom utf8_string = fetch_atom(w, "UTF8_STRING");
+
+ TRACE_GUI((stderr, "selection target = %lu (%s)",
+ *target, XGetAtomName(DISP, *target)));
+
+ if (m_selection_text == NULL) /* paranoia */
+ return False;
+
+#if HAVE_X11_XMU_XMU_H
+ if (*target == targets) {
+ /* TARGETS handling copied from xclipboard.c */
+ Atom* targetP;
+ Atom* std_targets;
+ unsigned long std_length;
+ XSelectionRequestEvent* req = XtGetSelectionRequest(w, *selection, (XtRequestId)NULL);
+
+ TRACE_GUI((stderr, "Selection type: targets"));
+ XmuConvertStandardSelection(w, req->time, selection,
+ target, type, (XPointer*)&std_targets, &std_length, format);
+ *value = XtMalloc(sizeof(Atom)*(std_length + 2));
+ targetP = *(Atom**)value;
+ *length = std_length + 2;
+ *targetP++ = XA_COMPOUND_TEXT(DISP);
+ *targetP++ = XA_STRING;
+ memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
+ XtFree((char*)std_targets);
+ *type = XA_ATOM;
+ *format = sizeof(Atom) * 8;
+ return True;
+ }
+ else
+#endif
+ if (*target == utf8_string) {
+ TRACE_GUI((stderr, "Selection type: UTF8_STRING"));
+ *type = *target;
+ *value = (XtPointer)XtNewString(m_selection_text);
+ /* *value = (XtPointer)m_selection_text; */
+ *length = strlen(m_selection_text);
+ *format = 8;
+ return True;
+ }
+ else if (*target == XA_STRING) {
+ char *ptr = utf8_to_native_encoding(m_selection_text);
+ TRACE_GUI((stderr, "Selection type: XA_STRING"));
+ strncpy(m_cvt_selection_text, ptr, m_selection_size);
+ m_cvt_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
+ free(ptr);
+ *type = *target;
+ *value = (XtPointer)XtNewString(m_cvt_selection_text);
+ /* *value = (XtPointer)m_selection_text; */
+ *length = strlen(m_cvt_selection_text);
+ *format = 8;
+ return True;
+ }
+#if HAVE_X11_XMU_XMU_H
+ else if (*target == XA_COMPOUND_TEXT(DISP) || *target == XA_TEXT(DISP)) {
+ const char *cl[1];
+ char *ptr;
+ int retval;
+
+ XTextProperty ct;
+ XICCEncodingStyle style = XStdICCTextStyle;
+
+ TRACE_GUI((stderr, "Selection type: XA_COMPOUND_TEXT"));
+ ptr = utf8_to_native_encoding(m_selection_text);
+ strncpy(m_cvt_selection_text, ptr, m_selection_size);
+ m_cvt_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
+ cl[0] = m_cvt_selection_text;
+
+ *type = *target;
+ retval = XmbTextListToTextProperty(DISP, (char **)cl, 1, style, &ct);
+
+ if (retval == XNoMemory || retval == XLocaleNotSupported || retval == XConverterNotFound) {
+ statusline_print(STATUS_MEDIUM, "XmbTextListToTextProperty failed: %d", retval);
+ return False;
+ }
+
+ *value = ct.value;
+ *length = ct.nitems;
+ *format = 8;
+ return True;
+ }
+#endif
+ else {
+#if HAVE_X11_XMU_XMU_H
+ TRACE_GUI((stderr, "Selection type: standard selection"));
+ if (XmuConvertStandardSelection(w, CurrentTime, selection,
+ target, type, (XPointer *)value, length, format))
+ return True;
+ else {
+#endif
+ TRACE_GUI((stderr, "Selection type unsupported: %lu (%s)",
+ (unsigned long)*target, XGetAtomName(DISP, *target)));
+ statusline_print(STATUS_MEDIUM,
+ "X client asked for an unsupported selection target type: %lu (%s)",
+ (unsigned long)*target, XGetAtomName(DISP, *target));
+ return False ;
+#if HAVE_X11_XMU_XMU_H
+ }
+#endif
+ }
+}
+
+/* do it */
+Boolean
+set_selection(const char *text, Widget w)
+{
+ /* caller should make sure that text is never longer than 4 * XMaxRequestSize(DISP) - 32 */
+ if (m_selection_text == NULL) {
+ m_selection_size = 4 * XMaxRequestSize(DISP);
+ m_selection_text = xmalloc(m_selection_size);
+ m_cvt_selection_text = xmalloc(m_selection_size);
+ }
+ strncpy(m_selection_text, text, m_selection_size);
+ m_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
+
+ return XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)),
+ deliver_selection_cb,
+ lose_selection_cb,
+ (XtSelectionDoneProc)NULL);
+}
+
+void
+unset_selection(Widget w)
+{
+ XtDisownSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)));
+}
+
diff --git a/Build/source/texk/xdvik/gui/selection.h b/Build/source/texk/xdvik/gui/selection.h
new file mode 100644
index 00000000000..1dcb8416cbb
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/selection.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ */
+
+#ifndef SELECTION_H_
+#define SELECTION_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+Boolean set_selection(const char *text, Widget w);
+void unset_selection(Widget w);
+
+#endif /* SELECTION_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfDir.c b/Build/source/texk/xdvik/gui/sfDir.c
new file mode 100644
index 00000000000..de39ccf3678
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDir.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+#include "sfDir.h"
+
+#if !defined(MOTIF) /* entire file */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#undef wchar_t
+
+#include <stdio.h>
+
+#ifdef SEL_FILE_IGNORE_CASE
+#include <ctype.h>
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+
+#ifdef SEL_FILE_IGNORE_CASE
+int
+SFcompareEntries(const void *vp, const void *vq)
+{
+ SFEntry *p = vp;
+ SFEntry *q = vq;
+ char *r, *s;
+ char c1, c2;
+
+ r = p->real;
+ s = q->real;
+
+ c1 = *r++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *s++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+
+ while (c1 == c2) {
+ if (!c1) {
+ return strcmp(p->real, q->real);
+ }
+ c1 = *r++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *s++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+ }
+
+ return c1 - c2;
+}
+#else /* def SEL_FILE_IGNORE_CASE */
+int
+SFcompareEntries(const void *vp, const void *vq)
+{
+ const SFEntry *p = vp;
+ const SFEntry *q = vq;
+ return strcmp(p->real, q->real);
+}
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+int
+SFgetDir(SFDir *dir)
+{
+ SFEntry *result = NULL;
+ int alloc = 0;
+ int i;
+ DIR *dirp;
+ struct dirent *dp;
+ char *str;
+ int len;
+ int maxChars;
+ struct stat statBuf;
+
+ maxChars = strlen(dir->dir) - 1;
+
+ dir->entries = NULL;
+ dir->nEntries = 0;
+ dir->nChars = 0;
+
+ result = NULL;
+ i = 0;
+
+ dirp = opendir(".");
+ if (!dirp) {
+ return 1;
+ }
+
+ (void)stat(".", &statBuf);
+ dir->mtime = statBuf.st_mtime;
+
+ (void)readdir(dirp); /* throw away "." */
+
+#ifndef S_IFLNK
+ (void)readdir(dirp); /* throw away ".." */
+#endif /* ndef S_IFLNK */
+
+ while ((dp = readdir(dirp))) {
+ if (i >= alloc) {
+ alloc = 2 * (alloc + 1);
+ result = (SFEntry *) XtRealloc((char *)result,
+ (unsigned)(alloc * sizeof(SFEntry)));
+ }
+ result[i].statDone = 0;
+ str = dp->d_name;
+ len = strlen(str);
+ result[i].real = XtMalloc((unsigned)(len + 2));
+ (void)strcat(strcpy(result[i].real, str), " ");
+ if (len > maxChars) {
+ maxChars = len;
+ }
+ result[i].shown = result[i].real;
+ i++;
+ }
+
+#if defined(SVR4) || defined(SYSV) || defined(USG)
+ qsort((char *)result, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
+#else /* defined(SVR4) || defined(SYSV) || defined(USG) */
+ qsort((char *)result, i, sizeof(SFEntry), SFcompareEntries);
+#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
+
+ dir->entries = result;
+ dir->nEntries = i;
+ dir->nChars = maxChars + 1;
+
+ closedir(dirp);
+
+ return 0;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfDir.h b/Build/source/texk/xdvik/gui/sfDir.h
new file mode 100644
index 00000000000..0207ec4f1a0
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDir.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef SFDIR_H_
+#define SFDIR_H_
+
+#include "xdvi-config.h"
+
+#include "kpathsea/c-auto.h"
+#include "kpathsea/config.h"
+#include "kpathsea/c-dir.h"
+#include "kpathsea/c-stat.h"
+
+#ifndef MOTIF
+
+typedef struct {
+ int statDone;
+ char *real;
+ char *shown;
+} SFEntry;
+
+typedef struct {
+ char *dir;
+ char *path;
+ SFEntry *entries;
+ int nEntries;
+ int vOrigin;
+ int nChars;
+ int hOrigin;
+ int changed;
+ int beginSelection;
+ int endSelection;
+ time_t mtime;
+} SFDir;
+
+extern int SFcompareEntries(const void *vp, const void *vq);
+extern int SFgetDir(SFDir *dir);
+
+extern SFDir *SFdirs;
+
+#endif /* MOTIF */
+
+#endif /* SFDIR_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfDraw.c b/Build/source/texk/xdvik/gui/sfDraw.c
new file mode 100644
index 00000000000..7a3ddd8cf06
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDraw.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+
+#include "kpathsea/c-auto.h"
+#include "kpathsea/config.h"
+#include "kpathsea/c-stat.h"
+#include "xdvi.h"
+
+#include "sfDraw.h"
+#include "sfDir.h"
+#include "sfPath.h"
+
+#if !defined(MOTIF) /* for xdvik */
+
+#define SF_DEFAULT_FONT "9x15"
+
+typedef struct {
+ char *font;
+} TextData, *textPtr;
+
+int SFcharWidth, SFcharAscent, SFcharHeight;
+
+int SFcurrentInvert[3] = { -1, -1, -1 };
+
+static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
+
+static XtResource textResources[] = {
+ {XtNfont, XtCFont, XtRString, sizeof(char *),
+ XtOffset(textPtr, font), XtRString, SF_DEFAULT_FONT},
+};
+
+static XFontStruct *SFfont;
+
+static int SFcurrentListY;
+
+static XtIntervalId SFscrollTimerId;
+
+void
+SFinitFont(void)
+{
+ TextData *data;
+
+ data = XtNew(TextData);
+
+ XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
+ XtNumber(textResources), (Arg *) NULL, ZERO);
+
+ SFfont = XLoadQueryFont(SFdisplay, data->font);
+ if (!SFfont) {
+ SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
+ if (!SFfont) {
+ char sbuf[256];
+
+ (void)sprintf(sbuf, "XsraSelFile: can't get font %s",
+ SF_DEFAULT_FONT);
+
+ XtAppError(SFapp, sbuf);
+ }
+ }
+
+ TRACE_GUI((stderr, "FONT: width %d, %d\n", SFfont->max_bounds.width, SFfont->min_bounds.width));
+ SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
+ SFcharAscent = SFfont->max_bounds.ascent;
+ SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
+ if (SFcharWidth == 0) {
+ /* if min_bounds.width = -max_bounds.width, we probably
+ have a scalable TT font; try to determine its actual
+ width by measuring the letter `x':
+ */
+ SFcharWidth = XTextWidth(SFfont, "x", 1);
+ }
+ if (SFcharWidth == 0) { /* last resort */
+ SFcharWidth = SFfont->max_bounds.width / 2;
+ }
+ TRACE_GUI((stderr,
+ "Using font measures: charwidth %d, ascent %d, height %d",
+ SFcharWidth, SFcharAscent, SFcharHeight));
+}
+
+void
+SFcreateGC(void)
+{
+ XGCValues gcValues;
+ XRectangle rectangles[1];
+
+/* XtVaGetValues(selFileLists[0], */
+/* XtNforeground, &(gcValues.foreground), */
+/* XtNbackground, &(gcValues.background), */
+/* NULL); */
+ gcValues.foreground = SFfore;
+
+ SFlineGC = XtGetGC(selFileLists[0], (XtGCMask)
+ GCForeground | 0, &gcValues);
+
+ SFscrollGC = XtGetGC(selFileLists[0], (XtGCMask)
+ 0, &gcValues);
+
+ gcValues.function = GXinvert;
+/* gcValues.plane_mask = (gcValues.foreground ^ gcValues.background); */
+ gcValues.plane_mask = (SFfore ^ SFback);
+
+ SFinvertGC = XtGetGC(selFileLists[0], (XtGCMask)
+ GCFunction | GCPlaneMask | 0, &gcValues);
+
+ gcValues.foreground = SFfore;
+ gcValues.background = SFback;
+ gcValues.font = SFfont->fid;
+
+ SFtextGC = XCreateGC(SFdisplay, XtWindow(selFileLists[0]), (unsigned long)
+ GCForeground | GCBackground | GCFont | 0, &gcValues);
+
+ rectangles[0].x = SFlineToTextH + SFbesideText;
+ rectangles[0].y = 0;
+ rectangles[0].width = SFcharsPerEntry * SFcharWidth;
+ rectangles[0].height = SFupperY + 1;
+
+ XSetClipRectangles(SFdisplay, SFtextGC, 0, 0, rectangles, 1, Unsorted);
+}
+
+void
+SFclearList(int n, int doScroll)
+{
+ SFDir *dir;
+
+ SFcurrentInvert[n] = -1;
+
+ XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
+
+ XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
+
+ if (doScroll) {
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) {
+ XawScrollbarSetThumb(selFileVScrolls[n],
+ (double)dir->vOrigin / dir->nEntries,
+ (double)(dir->nEntries < SFlistSize
+ ? dir->nEntries
+ : SFlistSize)
+ / dir->nEntries);
+
+ XawScrollbarSetThumb(selFileHScrolls[n],
+ (double)(dir->hOrigin) / dir->nChars,
+ (double)(dir->nChars < SFcharsPerEntry
+ ? dir-> nChars : SFcharsPerEntry)
+ / dir->nChars);
+ }
+ else {
+ XawScrollbarSetThumb(selFileVScrolls[n], 0.0, 1.0);
+ XawScrollbarSetThumb(selFileHScrolls[n], 0.0, 1.0);
+ }
+ }
+}
+
+static void
+SFdeleteEntry(SFDir *dir, SFEntry *entry)
+{
+ SFEntry *e;
+ SFEntry *end;
+ int n;
+ int idx;
+
+ idx = entry - dir->entries;
+
+ if (idx < dir->beginSelection) {
+ dir->beginSelection--;
+ }
+ if (idx <= dir->endSelection) {
+ dir->endSelection--;
+ }
+ if (dir->beginSelection > dir->endSelection) {
+ dir->beginSelection = dir->endSelection = -1;
+ }
+
+ if (idx < dir->vOrigin) {
+ dir->vOrigin--;
+ }
+
+ XtFree(entry->real);
+
+ end = &(dir->entries[dir->nEntries - 1]);
+
+ for (e = entry; e < end; e++) {
+ *e = *(e + 1);
+ }
+
+ if (!(--dir->nEntries)) {
+ return;
+ }
+
+ n = dir - &(SFdirs[SFdirPtr]);
+ if ((n < 0) || (n > 2)) {
+ return;
+ }
+
+ XawScrollbarSetThumb(selFileVScrolls[n],
+ (double)(dir->vOrigin) / dir->nEntries,
+ (double)(dir->nEntries < SFlistSize
+ ? dir->nEntries : SFlistSize)
+ / dir->nEntries);
+}
+
+static void
+SFwriteStatChar(char *name, int last, struct stat *statBuf)
+{
+ name[last] = SFstatChar(statBuf);
+}
+
+static int
+SFstatAndCheck(SFDir *dir, SFEntry *entry)
+{
+ struct stat statBuf;
+ char save;
+ int last;
+ extern int SFchdir();
+
+ /*
+ * must be restored before returning
+ */
+ save = *(dir->path);
+ *(dir->path) = 0;
+
+ if (!SFchdir(SFcurrentPath)) {
+ last = strlen(entry->real) - 1;
+ entry->real[last] = 0;
+ entry->statDone = 1;
+ if ((!stat(entry->real, &statBuf))
+#ifdef S_IFLNK
+ || (!lstat(entry->real, &statBuf))
+#endif /* ndef S_IFLNK */
+ ) {
+ if (SFfunc) {
+ char *shown;
+
+ shown = NULL;
+ if (SFfunc(entry->real, &shown, &statBuf)) {
+ if (shown) {
+ int len;
+
+ len = strlen(shown);
+ entry->shown = XtMalloc((unsigned)(len + 2)
+ );
+ (void)strcpy(entry->shown, shown);
+ SFwriteStatChar(entry->shown, len, &statBuf);
+ entry->shown[len + 1] = 0;
+ }
+ }
+ else {
+ SFdeleteEntry(dir, entry);
+
+ *(dir->path) = save;
+ return 1;
+ }
+ }
+ SFwriteStatChar(entry->real, last, &statBuf);
+ }
+ else {
+ entry->real[last] = ' ';
+ }
+ }
+
+ *(dir->path) = save;
+ return 0;
+}
+
+static void
+SFdrawStrings(Window w, SFDir *dir, int from, int to)
+{
+ int i;
+ SFEntry *entry;
+ int x;
+
+ x = SFtextX - dir->hOrigin * SFcharWidth;
+
+ if (dir->vOrigin + to >= dir->nEntries) {
+ to = dir->nEntries - dir->vOrigin - 1;
+ }
+ for (i = from; i <= to; i++) {
+ entry = &(dir->entries[dir->vOrigin + i]);
+ if (!(entry->statDone)) {
+ if (SFstatAndCheck(dir, entry)) {
+ if (dir->vOrigin + to >= dir->nEntries) {
+ to = dir->nEntries - dir->vOrigin - 1;
+ }
+ i--;
+ continue;
+ }
+ }
+ XDrawImageString(SFdisplay,
+ w,
+ SFtextGC,
+ x,
+ SFtextYoffset + i * SFentryHeight,
+ entry->shown, strlen(entry->shown));
+ if (dir->vOrigin + i == dir->beginSelection) {
+ XDrawLine(SFdisplay,
+ w,
+ SFlineGC,
+ SFlineToTextH + 1,
+ SFlowerY + i * SFentryHeight,
+ SFlineToTextH + SFentryWidth - 2,
+ SFlowerY + i * SFentryHeight);
+ }
+ if (
+ (dir->vOrigin + i >= dir->beginSelection) &&
+ (dir->vOrigin + i <= dir->endSelection)) {
+ SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
+ SFlowerY + i * SFentryHeight;
+ SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
+ SFlowerY + (i + 1) * SFentryHeight - 1;
+ XDrawSegments(SFdisplay, w, SFlineGC, SFcompletionSegs, 2);
+ }
+ if (dir->vOrigin + i == dir->endSelection) {
+ XDrawLine(SFdisplay,
+ w,
+ SFlineGC,
+ SFlineToTextH + 1,
+ SFlowerY + (i + 1) * SFentryHeight - 1,
+ SFlineToTextH + SFentryWidth - 2,
+ SFlowerY + (i + 1) * SFentryHeight - 1);
+ }
+ }
+}
+
+void
+SFdrawList(int n, int doScroll)
+{
+ SFDir *dir;
+ Window w;
+
+ SFclearList(n, doScroll);
+
+ if (SFdirPtr + n < SFdirEnd) {
+ dir = &(SFdirs[SFdirPtr + n]);
+ w = XtWindow(selFileLists[n]);
+ XDrawImageString(SFdisplay,
+ w,
+ SFtextGC,
+ SFtextX - dir->hOrigin * SFcharWidth,
+ SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
+ dir->dir, strlen(dir->dir)
+ );
+ SFdrawStrings(w, dir, 0, SFlistSize - 1);
+ }
+}
+
+void
+SFdrawLists(int doScroll)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ SFdrawList(i, doScroll);
+ }
+}
+
+static void
+SFinvertEntry(int n)
+{
+ XFillRectangle(SFdisplay,
+ XtWindow(selFileLists[n]),
+ SFinvertGC,
+ SFlineToTextH,
+ SFcurrentInvert[n] * SFentryHeight + SFlowerY,
+ SFentryWidth, SFentryHeight);
+}
+
+static unsigned long
+SFscrollTimerInterval(void)
+{
+ static int maxVal = 200;
+ static int varyDist = 50;
+ static int minDist = 50;
+ int t;
+ int dist;
+
+ if (SFcurrentListY < SFlowerY) {
+ dist = SFlowerY - SFcurrentListY;
+ }
+ else if (SFcurrentListY > SFupperY) {
+ dist = SFcurrentListY - SFupperY;
+ }
+ else {
+ return (unsigned long)1;
+ }
+
+ t = maxVal - ((maxVal / varyDist) * (dist - minDist));
+
+ if (t < 1) {
+ t = 1;
+ }
+
+ if (t > maxVal) {
+ t = maxVal;
+ }
+
+ return (unsigned long)t;
+}
+
+static void
+SFscrollTimer(XtPointer p, XtIntervalId *id)
+{
+ SFDir *dir;
+ int save;
+ int n;
+
+ UNUSED(id);
+
+ n = (int)p;
+
+ fprintf(stderr, "SFscrollTimer called!\n");
+
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = dir->vOrigin;
+
+ if (SFcurrentListY < SFlowerY) {
+ if (dir->vOrigin > 0) {
+ SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
+ }
+ }
+ else if (SFcurrentListY > SFupperY) {
+ if (dir->vOrigin < dir->nEntries - SFlistSize) {
+ SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
+ }
+ }
+
+ if (dir->vOrigin != save) {
+ if (dir->nEntries) {
+ XawScrollbarSetThumb(selFileVScrolls[n],
+ (double)(dir->vOrigin) / dir->nEntries,
+ (double)(dir->nEntries < SFlistSize
+ ? dir-> nEntries : SFlistSize)
+ / dir->nEntries);
+ }
+ }
+
+ if (SFbuttonPressed) {
+ SFscrollTimerId = XtAppAddTimeOut(SFapp,
+ SFscrollTimerInterval(),
+ SFscrollTimer, (XtPointer) n);
+ }
+}
+
+static int
+SFnewInvertEntry(int n, XMotionEvent *event)
+{
+ int x, y;
+ int new;
+ static int SFscrollTimerAdded = 0;
+
+ x = event->x;
+ y = event->y;
+
+ if (SFdirPtr + n >= SFdirEnd) {
+ return -1;
+ }
+ else if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY)
+ ) {
+ SFDir *dir = &(SFdirs[SFdirPtr + n]);
+
+ if (SFscrollTimerAdded) {
+ SFscrollTimerAdded = 0;
+ XtRemoveTimeOut(SFscrollTimerId);
+ }
+
+ new = (y - SFlowerY) / SFentryHeight;
+ if (dir->vOrigin + new >= dir->nEntries) {
+ return -1;
+ }
+ return new;
+ }
+ else {
+ if (SFbuttonPressed) {
+ SFcurrentListY = y;
+ if (!SFscrollTimerAdded) {
+ SFscrollTimerAdded = 1;
+ SFscrollTimerId = XtAppAddTimeOut(SFapp,
+ SFscrollTimerInterval(),
+ SFscrollTimer, (XtPointer) n);
+ }
+ }
+
+ return -1;
+ }
+}
+
+void
+SFenterList(Widget w, int n, XEnterWindowEvent *event)
+{
+ int new;
+
+ UNUSED(w);
+
+ /* sanity */
+ if (SFcurrentInvert[n] != -1) {
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = -1;
+ }
+
+ new = SFnewInvertEntry(n, (XMotionEvent *) event);
+ if (new != -1) {
+ SFcurrentInvert[n] = new;
+ SFinvertEntry(n);
+ }
+}
+
+void
+SFleaveList(Widget w, int n, XEvent *event)
+{
+ UNUSED(w);
+ UNUSED(event);
+
+ if (SFcurrentInvert[n] != -1) {
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = -1;
+ }
+}
+
+void
+SFmotionList(Widget w, int n, XMotionEvent *event)
+{
+ int new;
+
+ UNUSED(w);
+
+ new = SFnewInvertEntry(n, event);
+
+ if (new != SFcurrentInvert[n]) {
+ if (SFcurrentInvert[n] != -1) {
+ SFinvertEntry(n);
+ }
+ SFcurrentInvert[n] = new;
+ if (new != -1) {
+ SFinvertEntry(n);
+ }
+ }
+}
+
+void
+SFvFloatSliderMovedCallback(Widget w, int n, float *fnew)
+{
+ int new;
+
+ new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;
+
+ SFvSliderMovedCallback(w, n, new);
+}
+
+void
+SFvSliderMovedCallback(Widget w, int n, int new)
+{
+ int old;
+ Window win;
+ SFDir *dir;
+
+ UNUSED(w);
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ old = dir->vOrigin;
+ dir->vOrigin = new;
+
+ if (old == new) {
+ return;
+ }
+
+ win = XtWindow(selFileLists[n]);
+
+ if (ABS(new - old) < SFlistSize) {
+ if (new > old) {
+ XCopyArea(SFdisplay,
+ win,
+ win,
+ SFscrollGC,
+ SFlineToTextH,
+ SFlowerY + (new - old) * SFentryHeight,
+ SFentryWidth + SFlineToTextH,
+ (SFlistSize - (new - old)) * SFentryHeight,
+ SFlineToTextH, SFlowerY);
+ XClearArea(SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY + (SFlistSize - (new - old)) *
+ SFentryHeight,
+ SFentryWidth + SFlineToTextH,
+ (new - old) * SFentryHeight, False);
+ SFdrawStrings(win, dir, SFlistSize - (new - old), SFlistSize - 1);
+ }
+ else {
+ XCopyArea(SFdisplay,
+ win,
+ win,
+ SFscrollGC,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ (SFlistSize - (old - new)) * SFentryHeight,
+ SFlineToTextH, SFlowerY + (old - new) * SFentryHeight);
+ XClearArea(SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ (old - new) * SFentryHeight, False);
+ SFdrawStrings(win, dir, 0, old - new);
+ }
+ }
+ else {
+ XClearArea(SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ SFlistSize * SFentryHeight, False);
+ SFdrawStrings(win, dir, 0, SFlistSize - 1);
+ }
+}
+
+void
+SFvAreaSelectedCallback(Widget w, int n, int pnew)
+{
+ SFDir *dir;
+ int new;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ new = dir->vOrigin + ((double)pnew / SFvScrollHeight) * dir->nEntries;
+
+ if (new > dir->nEntries - SFlistSize) {
+ new = dir->nEntries - SFlistSize;
+ }
+
+ if (new < 0) {
+ new = 0;
+ }
+
+ if (dir->nEntries) {
+ float f;
+
+ f = ((double)new) / dir->nEntries;
+
+ XawScrollbarSetThumb(w, f,
+ (double)(dir->nEntries < SFlistSize
+ ? dir->nEntries
+ : SFlistSize)
+ / dir->nEntries);
+ }
+
+ SFvSliderMovedCallback(w, n, new);
+}
+
+void
+SFhSliderMovedCallback(Widget w, int n, float *new)
+{
+ SFDir *dir;
+ int save;
+
+ UNUSED(w);
+
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = dir->hOrigin;
+ dir->hOrigin = (*new) * dir->nChars;
+ if (dir->hOrigin == save) {
+ return;
+ }
+
+ SFdrawList(n, SF_DO_NOT_SCROLL);
+}
+
+void
+SFhAreaSelectedCallback(Widget w, int n, int pnew)
+{
+ SFDir *dir;
+ int new;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ new = dir->hOrigin + (((double)pnew) / SFhScrollWidth) * dir->nChars;
+
+ if (new > dir->nChars - SFcharsPerEntry) {
+ new = dir->nChars - SFcharsPerEntry;
+ }
+
+ if (new < 0) {
+ new = 0;
+ }
+
+ if (dir->nChars) {
+ float f;
+
+ f = (double)new / dir->nChars;
+
+ XawScrollbarSetThumb(w, f,
+ (double)(dir->nChars < SFcharsPerEntry
+ ? dir->nChars
+ : SFcharsPerEntry)
+ / dir->nChars);
+
+ SFhSliderMovedCallback(w, n, &f);
+ }
+}
+
+void
+SFpathSliderMovedCallback(Widget w, XtPointer client_data, float *new)
+{
+ SFDir *dir;
+ int n;
+ XawTextPosition pos;
+ int SFdirPtrSave;
+
+ UNUSED(w);
+ UNUSED(client_data);
+
+ SFdirPtrSave = SFdirPtr;
+ SFdirPtr = (*new) * SFdirEnd;
+ if (SFdirPtr == SFdirPtrSave) {
+ return;
+ }
+
+ SFdrawLists(SF_DO_SCROLL);
+
+ n = 2;
+ while (SFdirPtr + n >= SFdirEnd) {
+ n--;
+ }
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ pos = dir->path - SFcurrentPath;
+
+ if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
+ pos -= strlen(SFstartDir);
+ if (pos < 0) {
+ pos = 0;
+ }
+ }
+
+ XawTextSetInsertionPoint(selFileField, pos);
+}
+
+void
+SFpathAreaSelectedCallback(Widget w, XtPointer client_data, int pnew)
+{
+ int new;
+ float f;
+
+ UNUSED(client_data);
+
+ new = SFdirPtr + (((double)pnew) / SFpathScrollWidth) * SFdirEnd;
+
+ if (new > SFdirEnd - 3) {
+ new = SFdirEnd - 3;
+ }
+
+ if (new < 0) {
+ new = 0;
+ }
+
+ f = ((double)new) / SFdirEnd;
+
+ XawScrollbarSetThumb(w, f,
+ (double)(SFdirEnd < 3 ? SFdirEnd : 3) / SFdirEnd);
+
+ SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);
+}
+
+Boolean
+SFworkProc(void)
+{
+ SFDir *dir;
+ SFEntry *entry;
+
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
+ if (!(dir->nEntries)) {
+ continue;
+ }
+ for (entry = &(dir->entries[dir->nEntries - 1]);
+ entry >= dir->entries; entry--) {
+ if (!(entry->statDone)) {
+ (void)SFstatAndCheck(dir, entry);
+ return False;
+ }
+ }
+ }
+
+ SFworkProcAdded = 0;
+
+ return True;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfDraw.h b/Build/source/texk/xdvik/gui/sfDraw.h
new file mode 100644
index 00000000000..e9199793df8
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDraw.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef SFDRAW_H_
+#define SFDRAW_H_
+
+#include "xdvi-config.h"
+
+#if !defined(MOTIF) /* for xdvik */
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Cardinals.h>
+
+#define SF_DO_SCROLL 1
+#define SF_DO_NOT_SCROLL 0
+
+extern Pixel SFfore, SFback;
+
+void SFinitFont(void);
+void SFcreateGC(void);
+void SFclearList(int n, int doScroll);
+void SFdrawList(int n, int doScroll);
+void SFdrawLists(int doScroll);
+void SFenterList(Widget w, int n, XEnterWindowEvent *event);
+void SFleaveList(Widget w, int n, XEvent *event);
+void SFmotionList(Widget w, int n, XMotionEvent *event);
+void SFvFloatSliderMovedCallback(Widget w, int n, float *fnew);
+void SFvSliderMovedCallback(Widget w, int n, int new);
+void SFvAreaSelectedCallback(Widget w, int n, int pnew);
+void SFhSliderMovedCallback(Widget w, int n, float *new);
+void SFhAreaSelectedCallback(Widget w, int n, int pnew);
+void SFpathSliderMovedCallback(Widget w, XtPointer client_data, float *new);
+void SFpathAreaSelectedCallback(Widget w, XtPointer client_data, int pnew);
+Boolean SFworkProc(void);
+extern int (*SFfunc)();
+
+extern Widget selFileField, selFileForm, selFileHScroll, selFileHScrolls[], selFileLists[], selFileVScrolls[];
+extern Display *SFdisplay;
+extern int SFcharWidth, SFcharHeight, SFcharAscent;
+extern XSegment SFsegs[], SFcompletionSegs[];
+extern XawTextPosition SFtextPos;
+
+extern int SFupperX, SFlowerY, SFupperY;
+
+extern int SFtextX, SFtextYoffset;
+
+extern int SFentryWidth, SFentryHeight;
+
+extern int SFlineToTextH, SFlineToTextV;
+
+extern int SFbesideText, SFaboveAndBelowText;
+
+extern int SFcharsPerEntry;
+
+extern int SFlistSize;
+
+extern int SFcurrentInvert[];
+
+extern int SFworkProcAdded;
+
+extern XtAppContext SFapp;
+
+extern int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
+
+extern char SFtextBuffer[];
+
+extern int SFbuttonPressed;
+
+extern XtIntervalId SFdirModTimerId;
+
+#endif /* !defined(MOTIF) */
+
+#endif /* SFDRAW_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfPath.c b/Build/source/texk/xdvik/gui/sfPath.c
new file mode 100644
index 00000000000..3349919391b
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfPath.c
@@ -0,0 +1,908 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+
+#include "kpathsea/c-auto.h"
+#include "kpathsea/config.h"
+#include "kpathsea/c-stat.h"
+
+#include "xdvi.h"
+#include "sfDir.h"
+#include "sfDraw.h"
+#include "sfPath.h"
+#include "sfSelFile.h"
+
+#if !defined(MOTIF) /* entire file */
+
+#include <stdio.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Cardinals.h>
+
+
+#ifdef SEL_FILE_IGNORE_CASE
+#include <ctype.h>
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001
+#endif
+
+#define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))
+
+#include <X11/Xos.h>
+#include <pwd.h>
+#include <X11/Xaw/Scrollbar.h>
+
+typedef struct {
+ char *name;
+ char *dir;
+} SFLogin;
+
+SFDir *SFdirs = NULL;
+
+int SFdirEnd;
+
+int SFdirPtr;
+
+int SFbuttonPressed = 0;
+
+static int SFdoNotTouchDirPtr = 0;
+
+static int SFdoNotTouchVorigin = 0;
+
+static SFDir SFrootDir, SFhomeDir;
+
+static SFLogin *SFlogins;
+
+static int SFtwiddle = 0;
+
+int
+SFchdir(char *path)
+{
+ int result;
+
+ result = 0;
+
+ if (strcmp(path, SFcurrentDir)) {
+ result = chdir(path);
+ if (!result) {
+ (void)strcpy(SFcurrentDir, path);
+ }
+ }
+
+ return result;
+}
+
+static void
+SFfree(int i)
+{
+ SFDir *dir;
+ int j;
+
+ dir = &(SFdirs[i]);
+
+ for (j = dir->nEntries - 1; j >= 0; j--) {
+ if (dir->entries[j].shown != dir->entries[j].real) {
+ XtFree(dir->entries[j].shown);
+ }
+ XtFree(dir->entries[j].real);
+ }
+
+ XtFree((char *)dir->entries);
+
+ XtFree(dir->dir);
+
+ dir->dir = NULL;
+}
+
+static void
+SFstrdup(char **s1, char *s2)
+{
+ *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2);
+}
+
+static void
+SFunreadableDir(SFDir *dir)
+{
+ char *cannotOpen = "<cannot open> ";
+
+ dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
+ dir->entries[0].statDone = 1;
+ SFstrdup(&dir->entries[0].real, cannotOpen);
+ dir->entries[0].shown = dir->entries[0].real;
+ dir->nEntries = 1;
+ dir->nChars = strlen(cannotOpen);
+}
+
+#ifdef SEL_FILE_IGNORE_CASE
+static
+SFstrncmp(char *p, char *q, int n)
+{
+ char c1, c2;
+ char *psave, *qsave;
+ int nsave;
+
+ psave = p;
+ qsave = q;
+ nsave = n;
+
+ c1 = *p++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *q++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+
+ while ((--n >= 0) && (c1 == c2)) {
+ if (!c1) {
+ return strncmp(psave, qsave, nsave);
+ }
+ c1 = *p++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *q++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+ }
+
+ if (n < 0) {
+ return strncmp(psave, qsave, nsave);
+ }
+
+ return c1 - c2;
+}
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+static void
+SFreplaceText(SFDir *dir, char *str)
+{
+ int len;
+
+ *(dir->path) = 0;
+ len = strlen(str);
+ if (str[len - 1] == '/') {
+ (void)strcat(SFcurrentPath, str);
+ }
+ else {
+ (void)strncat(SFcurrentPath, str, len - 1);
+ }
+/* if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) { */
+/* SFsetText(SFcurrentPath); */
+/* } */
+/* else { */
+/* SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); */
+/* } */
+ SFsetText(SFcurrentPath);
+
+ SFtextChanged();
+}
+
+static void
+SFexpand(char *str)
+{
+ int len;
+ int cmp;
+ char *name, *growing;
+ SFDir *dir;
+ SFEntry *entry, *max;
+
+ len = strlen(str);
+
+ dir = &(SFdirs[SFdirEnd - 1]);
+
+ if (dir->beginSelection == -1) {
+ SFstrdup(&str, str);
+ SFreplaceText(dir, str);
+ XtFree(str);
+ return;
+ }
+ else if (dir->beginSelection == dir->endSelection) {
+ SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
+ return;
+ }
+
+ max = &(dir->entries[dir->endSelection + 1]);
+
+ name = dir->entries[dir->beginSelection].shown;
+ SFstrdup(&growing, name);
+
+ cmp = 0;
+ while (!cmp) {
+ entry = &(dir->entries[dir->beginSelection]);
+ while (entry < max) {
+ if ((cmp = strncmp(growing, entry->shown, len))) {
+ break;
+ }
+ entry++;
+ }
+ len++;
+ }
+
+ /*
+ * SFreplaceText() expects filename
+ */
+ growing[len - 2] = ' ';
+
+ growing[len - 1] = 0;
+ SFreplaceText(dir, growing);
+ XtFree(growing);
+}
+
+static int
+SFfindFile(SFDir *dir, char *str)
+{
+ int i, last, max;
+ char *name, save;
+ SFEntry *entries;
+ int len;
+ int begin, end;
+ int result;
+
+ len = strlen(str);
+
+ if (str[len - 1] == ' ') {
+ SFexpand(str);
+ return 1;
+ }
+ else if (str[len - 1] == '/') {
+ len--;
+ }
+
+ max = dir->nEntries;
+
+ entries = dir->entries;
+
+ i = 0;
+ while (i < max) {
+ name = entries[i].shown;
+ last = strlen(name) - 1;
+ save = name[last];
+ name[last] = 0;
+
+#ifdef SEL_FILE_IGNORE_CASE
+ result = SFstrncmp(str, name, len);
+#else /* def SEL_FILE_IGNORE_CASE */
+ result = strncmp(str, name, len);
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+ name[last] = save;
+ if (result <= 0) {
+ break;
+ }
+ i++;
+ }
+ begin = i;
+ while (i < max) {
+ name = entries[i].shown;
+ last = strlen(name) - 1;
+ save = name[last];
+ name[last] = 0;
+
+#ifdef SEL_FILE_IGNORE_CASE
+ result = SFstrncmp(str, name, len);
+#else /* def SEL_FILE_IGNORE_CASE */
+ result = strncmp(str, name, len);
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+ name[last] = save;
+ if (result) {
+ break;
+ }
+ i++;
+ }
+ end = i;
+
+ if (begin != end) {
+ if ((dir->beginSelection != begin) || (dir->endSelection != end - 1)
+ ) {
+ dir->changed = 1;
+ dir->beginSelection = begin;
+ if (str[strlen(str) - 1] == '/') {
+ dir->endSelection = begin;
+ }
+ else {
+ dir->endSelection = end - 1;
+ }
+ }
+ }
+ else {
+ if (dir->beginSelection != -1) {
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ }
+ }
+
+ if (SFdoNotTouchVorigin ||
+ ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))) {
+ SFdoNotTouchVorigin = 0;
+ return 0;
+ }
+
+ i = begin - 1;
+ if (i > max - SFlistSize) {
+ i = max - SFlistSize;
+ }
+ if (i < 0) {
+ i = 0;
+ }
+
+ if (dir->vOrigin != i) {
+ dir->vOrigin = i;
+ dir->changed = 1;
+ }
+
+ return 0;
+}
+
+static void
+SFunselect(void)
+{
+ SFDir *dir;
+
+ dir = &(SFdirs[SFdirEnd - 1]);
+ if (dir->beginSelection != -1) {
+ dir->changed = 1;
+ }
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+}
+
+static int
+SFcompareLogins(const void *vp, const void *vq)
+{
+ const SFLogin *p = vp;
+ const SFLogin *q = vq;
+ return strcmp(p->name, q->name);
+}
+
+static void
+SFgetHomeDirs(void)
+{
+ struct passwd *pw;
+ int alloc;
+ int i;
+ SFEntry *entries = NULL;
+ int len;
+ int maxChars;
+
+ {
+ alloc = 1;
+ i = 1;
+ entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
+ SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
+ entries[0].real = XtMalloc(3);
+ (void)strcpy(entries[0].real, "~");
+ entries[0].shown = entries[0].real;
+ entries[0].statDone = 1;
+ SFlogins[0].name = "";
+ pw = getpwuid((int)getuid());
+ SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
+ maxChars = 0;
+ }
+
+ (void)setpwent();
+
+ while ((pw = (struct passwd *)getpwent()) && (*(pw->pw_name))) {
+ if (i >= alloc) {
+ alloc *= 2;
+ entries = (SFEntry *) XtRealloc(
+ (char *)entries,
+ (unsigned)(alloc *
+ sizeof(SFEntry)));
+ SFlogins =
+ (SFLogin *) XtRealloc((char *)SFlogins,
+ (unsigned)(alloc * sizeof(SFLogin))
+ );
+ }
+ len = strlen(pw->pw_name);
+ entries[i].real = XtMalloc((unsigned)(len + 3));
+ (void)strcat(strcpy(entries[i].real, "~"), pw->pw_name);
+ entries[i].shown = entries[i].real;
+ entries[i].statDone = 1;
+ if (len > maxChars) {
+ maxChars = len;
+ }
+ SFstrdup(&SFlogins[i].name, pw->pw_name);
+ SFstrdup(&SFlogins[i].dir, pw->pw_dir);
+ i++;
+ }
+
+ SFhomeDir.dir = XtMalloc(1);
+ SFhomeDir.dir[0] = 0;
+ SFhomeDir.path = SFcurrentPath;
+ SFhomeDir.entries = entries;
+ SFhomeDir.nEntries = i;
+ SFhomeDir.vOrigin = 0; /* :-) */
+ SFhomeDir.nChars = maxChars + 2;
+ SFhomeDir.hOrigin = 0;
+ SFhomeDir.changed = 1;
+ SFhomeDir.beginSelection = -1;
+ SFhomeDir.endSelection = -1;
+
+#if defined(SVR4) || defined(SYSV) || defined(USG)
+ qsort((char *)entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
+ qsort((char *)SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
+#else /* defined(SVR4) || defined(SYSV) || defined(USG) */
+ qsort((char *)entries, i, sizeof(SFEntry), SFcompareEntries);
+ qsort((char *)SFlogins, i, sizeof(SFLogin), SFcompareLogins);
+#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
+
+ for (i--; i >= 0; i--) {
+ (void)strcat(entries[i].real, "/");
+ }
+}
+
+static int
+SFfindHomeDir(char *begin, char *end)
+{
+ char save;
+ char *theRest;
+ int i;
+
+ save = *end;
+ *end = 0;
+
+ for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
+ if (!strcmp(SFhomeDir.entries[i].real, begin)) {
+ *end = save;
+ SFstrdup(&theRest, end);
+ (void)strcat(strcat(strcpy(SFcurrentPath,
+ SFlogins[i].dir), "/"), theRest);
+ XtFree(theRest);
+ SFsetText(SFcurrentPath);
+ SFtextChanged();
+ return 1;
+ }
+ }
+
+ *end = save;
+
+ return 0;
+}
+
+void
+SFupdatePath(void)
+{
+ static int alloc;
+ static int wasTwiddle = 0;
+ char *begin, *end;
+ int i, j;
+ int prevChange;
+ int SFdirPtrSave, SFdirEndSave;
+ SFDir *dir;
+
+ if (!SFdirs) {
+ SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
+ dir = &(SFdirs[0]);
+ SFstrdup(&dir->dir, "/");
+ (void)SFchdir("/");
+ (void)SFgetDir(dir);
+ for (j = 1; j < alloc; j++) {
+ SFdirs[j].dir = NULL;
+ }
+ dir->path = SFcurrentPath + 1;
+ dir->vOrigin = 0;
+ dir->hOrigin = 0;
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ SFhomeDir.dir = NULL;
+ }
+
+ SFdirEndSave = SFdirEnd;
+ SFdirEnd = 1;
+
+ SFdirPtrSave = SFdirPtr;
+ SFdirPtr = 0;
+
+ begin = NULL;
+
+ if (SFcurrentPath[0] == '~') {
+ if (!SFtwiddle) {
+ SFtwiddle = 1;
+ dir = &(SFdirs[0]);
+ SFrootDir = *dir;
+ if (!SFhomeDir.dir) {
+ SFgetHomeDirs();
+ }
+ *dir = SFhomeDir;
+ dir->changed = 1;
+ }
+ end = SFcurrentPath;
+ SFdoNotTouchDirPtr = 1;
+ wasTwiddle = 1;
+ }
+ else {
+ if (SFtwiddle) {
+ SFtwiddle = 0;
+ dir = &(SFdirs[0]);
+ *dir = SFrootDir;
+ dir->changed = 1;
+ }
+ end = SFcurrentPath + 1;
+ }
+
+ i = 0;
+
+ prevChange = 0;
+
+ while (*end) {
+ while (*end++ == '/') {
+ ;
+ }
+ end--;
+ begin = end;
+ while ((*end) && (*end++ != '/')) {
+ ;
+ }
+ if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
+ SFdirPtr = i - 1;
+ if (SFdirPtr < 0) {
+ SFdirPtr = 0;
+ }
+ }
+ if (*begin) {
+ if (*(end - 1) == '/') {
+ char save = *end;
+
+ if (SFtwiddle) {
+ if (SFfindHomeDir(begin, end)) {
+ return;
+ }
+ }
+ *end = 0;
+ i++;
+ SFdirEnd++;
+ if (i >= alloc) {
+ SFdirs = (SFDir *) XtRealloc(
+ (char *)SFdirs,
+ (unsigned)((alloc *= 2) *
+ sizeof(SFDir))
+ );
+ for (j = alloc / 2; j < alloc; j++) {
+ SFdirs[j].dir = NULL;
+ }
+ }
+ dir = &(SFdirs[i]);
+ if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin)
+ ) {
+ if (dir->dir) {
+ SFfree(i);
+ }
+ prevChange = 1;
+ SFstrdup(&dir->dir, begin);
+ dir->path = end;
+ dir->vOrigin = 0;
+ dir->hOrigin = 0;
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ (void)SFfindFile(dir - 1, begin);
+ if (SFchdir(SFcurrentPath) || SFgetDir(dir)
+ ) {
+ SFunreadableDir(dir);
+ break;
+ }
+ }
+ *end = save;
+ if (!save) {
+ SFunselect();
+ }
+ }
+ else {
+ if (SFfindFile(&(SFdirs[SFdirEnd - 1]), begin)) {
+ return;
+ }
+ }
+ }
+ else {
+ SFunselect();
+ }
+ }
+
+ if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
+ SFunselect();
+ }
+
+ for (i = SFdirEnd; i < alloc; i++) {
+ if (SFdirs[i].dir) {
+ SFfree(i);
+ }
+ }
+
+ if (SFdoNotTouchDirPtr) {
+ if (wasTwiddle) {
+ wasTwiddle = 0;
+ SFdirPtr = SFdirEnd - 2;
+ if (SFdirPtr < 0) {
+ SFdirPtr = 0;
+ }
+ }
+ else {
+ SFdirPtr = SFdirPtrSave;
+ }
+ SFdoNotTouchDirPtr = 0;
+ }
+
+ if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
+ XawScrollbarSetThumb(selFileHScroll,
+ (double)(SFdirPtr) / SFdirEnd,
+ (double)(SFdirEnd < 3 ? SFdirEnd : 3) / SFdirEnd);
+ }
+
+ if (SFdirPtr != SFdirPtrSave) {
+ SFdrawLists(SF_DO_SCROLL);
+ }
+ else {
+ for (i = 0; i < 3; i++) {
+ if (SFdirPtr + i < SFdirEnd) {
+ if (SFdirs[SFdirPtr + i].changed) {
+ SFdirs[SFdirPtr + i].changed = 0;
+ SFdrawList(i, SF_DO_SCROLL);
+ }
+ }
+ else {
+ SFclearList(i, SF_DO_SCROLL);
+ }
+ }
+ }
+}
+
+void
+SFsetText(char *path)
+{
+ XawTextBlock text;
+
+ text.firstPos = 0;
+ text.length = strlen(path);
+ text.ptr = path;
+ text.format = FMT8BIT;
+
+ XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
+ XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
+}
+
+void
+SFbuttonPressList(Widget w, int n, XButtonPressedEvent *event)
+{
+ UNUSED(w);
+ UNUSED(n);
+ UNUSED(event);
+
+ SFbuttonPressed = 1;
+}
+
+void
+SFbuttonReleaseList(Widget w, int n, XButtonReleasedEvent *event)
+{
+ SFDir *dir;
+
+ SFbuttonPressed = 0;
+
+ if (SFcurrentInvert[n] != -1) {
+ if (n < 2) {
+ SFdoNotTouchDirPtr = 1;
+ }
+ SFdoNotTouchVorigin = 1;
+ dir = &(SFdirs[SFdirPtr + n]);
+ SFreplaceText(dir,
+ dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
+ SFmotionList(w, n, (XMotionEvent *)event);
+ }
+}
+
+static int
+SFcheckDir(int n, SFDir *dir)
+{
+ struct stat statBuf;
+ int i;
+
+ if ((!stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime)
+ ) {
+
+ /*
+ * If the pointer is currently in the window that we are about
+ * to update, we must warp it to prevent the user from
+ * accidentally selecting the wrong file.
+ */
+ if (SFcurrentInvert[n] != -1) {
+ XWarpPointer(SFdisplay,
+ None, XtWindow(selFileLists[n]), 0, 0, 0, 0, 0, 0);
+ }
+
+ for (i = dir->nEntries - 1; i >= 0; i--) {
+ if (dir->entries[i].shown != dir->entries[i].real) {
+ XtFree(dir->entries[i].shown);
+ }
+ XtFree(dir->entries[i].real);
+ }
+ XtFree((char *)dir->entries);
+ if (SFgetDir(dir)) {
+ SFunreadableDir(dir);
+ }
+ if (dir->vOrigin > dir->nEntries - SFlistSize) {
+ dir->vOrigin = dir->nEntries - SFlistSize;
+ }
+ if (dir->vOrigin < 0) {
+ dir->vOrigin = 0;
+ }
+ if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
+ dir->hOrigin = dir->nChars - SFcharsPerEntry;
+ }
+ if (dir->hOrigin < 0) {
+ dir->hOrigin = 0;
+ }
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ SFdoNotTouchVorigin = 1;
+ if ((dir + 1)->dir) {
+ (void)SFfindFile(dir, (dir + 1)->dir);
+ }
+ else {
+ (void)SFfindFile(dir, dir->path);
+ }
+
+ if (!SFworkProcAdded) {
+ (void)XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
+ SFworkProcAdded = 1;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+SFcheckFiles(SFDir *dir)
+{
+ int from, to;
+ int result;
+ char old, new;
+ int i;
+ char *str;
+ int last;
+ struct stat statBuf;
+
+ result = 0;
+
+ from = dir->vOrigin;
+ to = dir->vOrigin + SFlistSize;
+ if (to > dir->nEntries) {
+ to = dir->nEntries;
+ }
+
+ for (i = from; i < to; i++) {
+ str = dir->entries[i].real;
+ last = strlen(str) - 1;
+ old = str[last];
+ str[last] = 0;
+ if (stat(str, &statBuf)) {
+ new = ' ';
+ }
+ else {
+ new = SFstatChar(&statBuf);
+ }
+ str[last] = new;
+ if (new != old) {
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+void
+SFdirModTimer(XtPointer cl, XtIntervalId *id)
+{
+ static int n = -1;
+ static int f = 0;
+ char save;
+ SFDir *dir;
+
+ UNUSED(cl);
+ UNUSED(id);
+
+ fprintf(stderr, "sfdirmodtimer called!\n");
+
+ if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
+ n++;
+ if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) {
+ n = 0;
+ f++;
+ if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) {
+ f = 0;
+ }
+ }
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = *(dir->path);
+ *(dir->path) = 0;
+ if (SFchdir(SFcurrentPath)) {
+ *(dir->path) = save;
+
+ /*
+ * force a re-read
+ */
+ *(dir->dir) = 0;
+
+ SFupdatePath();
+ }
+ else {
+ *(dir->path) = save;
+ if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir))
+ ) {
+ SFdrawList(n, SF_DO_SCROLL);
+ }
+ }
+ }
+
+ SFdirModTimerId = XtAppAddTimeOut(SFapp, 1500UL,
+ SFdirModTimer, (XtPointer) NULL);
+}
+
+/* Return a single character describing what kind of file STATBUF is. */
+
+char
+SFstatChar(struct stat *statBuf)
+{
+ if (S_ISDIR(statBuf->st_mode)) {
+ return '/';
+ }
+ else if (S_ISREG(statBuf->st_mode)) {
+ return S_ISXXX(statBuf->st_mode) ? '*' : ' ';
+#ifdef S_ISSOCK
+ }
+ else if (S_ISSOCK(statBuf->st_mode)) {
+ return '=';
+#endif /* S_ISSOCK */
+ }
+ else {
+ return ' ';
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfPath.h b/Build/source/texk/xdvik/gui/sfPath.h
new file mode 100644
index 00000000000..d087c0f804c
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfPath.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef SFPATH_H_
+#define SFPATH_H_
+
+#include "xdvi-config.h"
+
+#ifndef MOTIF
+
+extern int SFchdir(char *path);
+extern void SFupdatePath(void);
+extern void SFsetText(char *path);
+extern void SFbuttonPressList(Widget w, int n, XButtonPressedEvent *event);
+extern void SFbuttonReleaseList(Widget w, int n, XButtonReleasedEvent *event);
+extern void SFdirModTimer(XtPointer cl, XtIntervalId *id);
+extern char SFstatChar(struct stat *statBuf);
+
+extern char SFcurrentPath[], SFstartDir[], SFcurrentDir[];
+extern SFDir *SFdirs;
+extern int SFdirEnd, SFdirPtr;
+
+#endif /* MOTIF */
+
+#endif /* SFPATH_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfSelFile.c b/Build/source/texk/xdvik/gui/sfSelFile.c
new file mode 100644
index 00000000000..9964c69ad37
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfSelFile.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+
+#include "xdvi.h"
+#include "dvi-init.h" /* for dviErrFlagT */
+#include "message-window.h"
+
+#include "kpathsea/c-stat.h"
+
+#include <string.h>
+
+#include "sfDir.h"
+#include "sfPath.h"
+#include "sfDraw.h"
+#include "sfSelFile.h"
+#include "util.h"
+
+#include <ctype.h>
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+
+#if !defined(MOTIF) /* entire file */
+
+
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#define SEL_FILE_CANCEL -1
+#define SEL_FILE_OK 0
+#define SEL_FILE_NULL 1
+#define SEL_FILE_TEXT 2
+
+/*
+ * Author's address:
+ *
+ * erik@sra.co.jp
+ * OR
+ * erik%sra.co.jp@uunet.uu.net
+ * OR
+ * erik%sra.co.jp@mcvax.uucp
+ * OR
+ * try junet instead of co.jp
+ * OR
+ * Erik M. van der Poel
+ * Software Research Associates, Inc.
+ * 1-1-1 Hirakawa-cho, Chiyoda-ku
+ * Tokyo 102 Japan. TEL +81-3-234-2692
+ */
+
+#include <sys/param.h>
+#include <X11/cursorfont.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Composite.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Cardinals.h>
+
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif /* ndef MAXPATHLEN */
+
+/* global vars for communication with sfDraw.c */
+char SFstartDir[MAXPATHLEN], SFcurrentPath[MAXPATHLEN], SFcurrentDir[MAXPATHLEN];
+Widget selFileField, selFileForm, selFileHScroll, selFileHScrolls[3], selFileLists[3], selFileVScrolls[3];
+Display *SFdisplay;
+Pixel SFfore, SFback;
+XSegment SFsegs[2], SFcompletionSegs[2];
+XawTextPosition SFtextPos;
+int SFupperX, SFlowerY, SFupperY;
+int SFtextX, SFtextYoffset;
+int SFentryWidth, SFentryHeight;
+int SFlineToTextH = 3;
+int SFlineToTextV = 3;
+int SFbesideText = 3;
+int SFaboveAndBelowText = 2;
+int SFcharsPerEntry = 15;
+int SFlistSize = 10;
+int SFworkProcAdded = 0;
+XtAppContext SFapp;
+int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
+char SFtextBuffer[MAXPATHLEN];
+XtIntervalId SFdirModTimerId;
+int (*SFfunc) ();
+
+static int SFstatus = SEL_FILE_NULL;
+
+static Widget selFile, selFileCancel, selFileOK, selFilePrompt;
+/* For file filter. */
+static Widget selFileLabel, selFileMask, selFileHide;
+
+#define MASKWIDTH 16
+static char fileMask[MASKWIDTH + 2] = "*.dvi";
+
+static Atom SFwmDeleteWindow;
+
+static char *oneLineTextEditTranslations =
+ "<Key>Return: redraw-display()\n"
+ "Ctrl<Key>M: redraw-display()\n";
+
+#if !defined (HAVE_STRERROR) && !defined (strerror)
+static char *
+strerror(int errnum)
+{
+ return 0 < errnum && errnum <= sys_nerr
+ ? sys_errlist[errnum] : "Unknown system error";
+}
+#endif /* not HAVE_STRERROR && not strerror */
+
+void
+raise_file_selector(void)
+{
+ if (selFile != 0) {
+ XRaiseWindow(DISP, XtWindow(selFile));
+ }
+}
+
+static void
+SFexposeList(Widget w, XtPointer n, XEvent *event, Boolean *cont)
+{
+ UNUSED(w);
+ UNUSED(cont);
+
+ if ((event->type == NoExpose) || event->xexpose.count) {
+ return;
+ }
+
+ SFdrawList((int)n, SF_DO_NOT_SCROLL);
+}
+
+static void
+SFmodVerifyCallback(Widget w, XtPointer client_data, XEvent *event, Boolean *cont)
+{
+ char buf[2];
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(cont);
+
+ if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
+ ((*buf) == '\r')) {
+ SFstatus = SEL_FILE_OK;
+ }
+ else {
+ SFstatus = SEL_FILE_TEXT;
+ }
+}
+
+static void
+SFokCallback(Widget w, XtPointer cl, XtPointer cd)
+{
+ UNUSED(w);
+ UNUSED(cl);
+ UNUSED(cd);
+
+ SFstatus = SEL_FILE_OK;
+}
+
+static XtCallbackRec SFokSelect[] = {
+ {SFokCallback, (XtPointer) NULL},
+ {NULL, (XtPointer) NULL},
+};
+
+static void
+SFcancelCallback(Widget w, XtPointer cl, XtPointer cd)
+{
+ UNUSED(w);
+ UNUSED(cl);
+ UNUSED(cd);
+
+ SFstatus = SEL_FILE_CANCEL;
+}
+
+static XtCallbackRec SFcancelSelect[] = {
+ {SFcancelCallback, (XtPointer) NULL},
+ {NULL, (XtPointer) NULL},
+};
+
+static void
+SFdismissAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (event->type == ClientMessage && (unsigned)(event->xclient.data.l[0]) != SFwmDeleteWindow)
+ return;
+
+ SFstatus = SEL_FILE_CANCEL;
+}
+
+static char *wmDeleteWindowTranslation = "<Message>WM_PROTOCOLS: SelFileDismiss()\n";
+
+static XtActionsRec sf_actions[] = {
+ {"SelFileDismiss", SFdismissAction},
+};
+
+/* Don't show files that don't get through the filter. */
+
+/* return 1 if file is masked (mask does not match filename), 0 otherwise */
+static int
+maskFile(const char *mask, char *filename)
+{
+ int c, c1;
+
+ while ((c = *mask++)) {
+ if (c == '*') {
+ while ((c1 = *mask++)) {
+ if (c1 != '*') {
+ if (!(*filename))
+ return 1;
+ if (c1 != '?') {
+ while ((filename = strchr(filename, c1))) {
+ if (!maskFile(mask, ++filename))
+ return 0;
+ }
+ return 1;
+ }
+ else
+ filename++;
+ }
+ }
+ return 0;
+ }
+ if (c == '?') {
+ if (!*filename)
+ return 1;
+ }
+ else if (c != *filename)
+ return 1;
+ filename++;
+ }
+ return (*filename) ? 1 : 0;
+}
+
+Boolean hideFlag = False;
+static int
+showEntry(char *entryReal, char **entryShown, struct stat *statBuf)
+{
+ UNUSED(entryShown);
+
+ if ((hideFlag && entryReal[0] == '.') || (!S_ISDIR(statBuf->st_mode) && maskFile(fileMask, entryReal)))
+ return 0;
+ entryReal[strlen(entryReal)] = SFstatChar(statBuf);
+ return 1;
+}
+
+static void
+maskChanged(Widget w, XtPointer client_data, XEvent *call_data, Boolean *cont)
+{
+ char buf[2];
+ SFDir *dir;
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(cont);
+
+ if ((XLookupString((XKeyPressedEvent *)call_data, buf, 2, NULL, NULL) == 1) && ((*buf) == '\r')) {
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ *(dir->dir) = 0; /* force a re-read */
+ SFupdatePath();
+ }
+}
+
+static void
+hideFiles(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ SFDir *dir;
+ SFEntry *entry;
+
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ hideFlag = !hideFlag;
+ if (hideFlag) {
+ XtVaSetValues(w, XtNlabel, "hidden", NULL);
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
+ if (!(dir->nEntries))
+ continue;
+ dir->vOrigin = 0;
+ for (entry = &(dir->entries[dir->nEntries - 1]);
+ entry >= dir->entries; entry--)
+ entry->statDone = 0;
+ SFdrawLists(SF_DO_SCROLL);
+ }
+ }
+ else {
+ XtVaSetValues(w, XtNlabel, "shown", NULL);
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ *(dir->dir) = 0; /* force a re-read */
+ SFupdatePath();
+ }
+}
+
+
+static Widget
+SFcreateWidgets(Widget parent, const char *title, const char *prompt, const char *ok, const char *cancel)
+{
+ Cardinal i, n;
+ int listWidth, listHeight;
+ int listSpacing = 10;
+ int scrollThickness = 15;
+ int hScrollX, hScrollY;
+ int vScrollX, vScrollY;
+ Cursor xtermCursor, sbRightArrowCursor, arrowCursor;
+ Arg arglist[20];
+ Widget paned, box;
+
+ i = 0;
+ XtSetArg(arglist[i], XtNtransientFor, parent);
+ XtSetArg(arglist[i], XtNtitle, title);
+ i++;
+
+ selFile = XtAppCreateShell("xdviSelFile", "XdviSelFile",
+ transientShellWidgetClass, SFdisplay,
+ arglist, i);
+
+ /* Add WM_DELETE_WINDOW protocol */
+ XtAppAddActions(XtWidgetToApplicationContext(selFile),
+ sf_actions, XtNumber(sf_actions));
+ XtOverrideTranslations(selFile,
+ XtParseTranslationTable(wmDeleteWindowTranslation));
+
+ paned = XtVaCreateManagedWidget("paned", panedWidgetClass, selFile, NULL);
+ i = 0;
+ XtSetArg(arglist[i], XtNdefaultDistance, 6);
+ i++;
+ selFileForm = XtCreateManagedWidget("selFileForm",
+ formWidgetClass, paned, arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, prompt);
+ i++;
+ XtSetArg(arglist[i], XtNresizable, True);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNborderWidth, 0);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 20);
+ i++;
+ selFilePrompt = XtCreateManagedWidget("selFilePrompt",
+ labelWidgetClass, selFileForm,
+ arglist, i);
+
+#if 1
+ i = 0;
+ XtSetArg(arglist[i], XtNforeground, &SFfore);
+ i++;
+ XtSetArg(arglist[i], XtNbackground, &SFback);
+ i++;
+ XtGetValues(selFilePrompt, arglist, i);
+#endif
+
+ SFinitFont();
+
+ SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth + SFbesideText;
+ SFentryHeight = SFaboveAndBelowText + SFcharHeight + SFaboveAndBelowText;
+
+ listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
+ scrollThickness;
+ listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV + 1 + scrollThickness;
+
+ SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
+
+ hScrollX = -1;
+ hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight + SFlineToTextV;
+ SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
+
+ vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
+ vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
+ SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV;
+
+ SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
+ SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV;
+ SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight - 1;
+
+ SFtextX = SFlineToTextH + SFbesideText;
+ SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
+
+ SFsegs[0].x1 = 0;
+ SFsegs[0].y1 = vScrollY;
+ SFsegs[0].x2 = vScrollX - 1;
+ SFsegs[0].y2 = vScrollY;
+ SFsegs[1].x1 = vScrollX;
+ SFsegs[1].y1 = 0;
+ SFsegs[1].x2 = vScrollX;
+ SFsegs[1].y2 = vScrollY - 1;
+
+ SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
+ SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
+ SFlineToTextH + SFentryWidth - 1;
+
+ i = 0;
+/* XtSetArg(arglist[i], XtNwidth, 3 * listWidth + 2 * listSpacing + 4 - w - 10); */
+ XtSetArg(arglist[i], XtNwidth, 3 * listWidth + 2 * listSpacing + 4);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+
+/* XtSetArg(arglist[i], XtNfromHoriz, selFilePrompt); */
+/* i++; */
+/* XtSetArg(arglist[i], XtNhorizDistance, 10); */
+ XtSetArg(arglist[i], XtNfromVert, selFilePrompt);
+ i++;
+/* XtSetArg(arglist[i], XtNvertDistance, 0); */
+/* i++; */
+ XtSetArg(arglist[i], XtNresizable, True);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNstring, SFtextBuffer);
+ i++;
+ XtSetArg(arglist[i], XtNlength, MAXPATHLEN);
+ i++;
+ XtSetArg(arglist[i], XtNeditType, XawtextEdit);
+ i++;
+ XtSetArg(arglist[i], XtNwrap, XawtextWrapWord);
+ i++;
+ XtSetArg(arglist[i], XtNresize, XawtextResizeHeight);
+ i++;
+ XtSetArg(arglist[i], XtNuseStringInPlace, True);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 5);
+ i++;
+ selFileField = XtCreateManagedWidget("selFileField",
+ asciiTextWidgetClass, selFileForm,
+ arglist, i);
+
+ XtOverrideTranslations(selFileField,
+ XtParseTranslationTable
+ (oneLineTextEditTranslations));
+/* XtSetKeyboardFocus(selFileForm, selFileField);
+ need focus for selFileMask widget to set the filter */
+
+ i = 0;
+ XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);
+ i++;
+ XtSetArg(arglist[i], XtNwidth, SFpathScrollWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, scrollThickness);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromVert, selFileField);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 30);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileHScroll = XtCreateManagedWidget("selFileHScroll",
+ scrollbarWidgetClass, selFileForm,
+ arglist, i);
+
+ XtAddCallback(selFileHScroll, XtNjumpProc,
+ (XtCallbackProc)SFpathSliderMovedCallback, (XtPointer) NULL);
+ XtAddCallback(selFileHScroll, XtNscrollProc,
+ (XtCallbackProc)SFpathAreaSelectedCallback, (XtPointer) NULL);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNwidth, listWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, listHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromVert, selFileHScroll);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 10);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileLists[0] = XtCreateManagedWidget("selFileList1",
+ compositeWidgetClass, selFileForm,
+ arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNwidth, listWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, listHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromHoriz, selFileLists[0]);
+ i++;
+ XtSetArg(arglist[i], XtNfromVert, selFileHScroll);
+ i++;
+ XtSetArg(arglist[i], XtNhorizDistance, listSpacing);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 10);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileLists[1] = XtCreateManagedWidget("selFileList2",
+ compositeWidgetClass, selFileForm,
+ arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNwidth, listWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, listHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromHoriz, selFileLists[1]);
+ i++;
+ XtSetArg(arglist[i], XtNfromVert, selFileHScroll);
+ i++;
+ XtSetArg(arglist[i], XtNhorizDistance, listSpacing);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 10);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileLists[2] = XtCreateManagedWidget("selFileList3",
+ compositeWidgetClass, selFileForm,
+ arglist, i);
+
+ for (n = 0; n < 3; n++) {
+
+ i = 0;
+ XtSetArg(arglist[i], XtNx, vScrollX);
+ i++;
+ XtSetArg(arglist[i], XtNy, vScrollY);
+ i++;
+ XtSetArg(arglist[i], XtNwidth, scrollThickness);
+ i++;
+ XtSetArg(arglist[i], XtNheight, SFvScrollHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ selFileVScrolls[n] = XtCreateManagedWidget("selFileVScroll",
+ scrollbarWidgetClass,
+ selFileLists[n], arglist, i);
+
+ XtAddCallback(selFileVScrolls[n], XtNjumpProc,
+ (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer) n);
+ XtAddCallback(selFileVScrolls[n], XtNscrollProc,
+ (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer) n);
+
+ i = 0;
+
+ XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);
+ i++;
+ XtSetArg(arglist[i], XtNx, hScrollX);
+ i++;
+ XtSetArg(arglist[i], XtNy, hScrollY);
+ i++;
+ XtSetArg(arglist[i], XtNwidth, SFhScrollWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, scrollThickness);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ selFileHScrolls[n] = XtCreateManagedWidget("selFileHScroll",
+ scrollbarWidgetClass,
+ selFileLists[n], arglist, i);
+
+ XtAddCallback(selFileHScrolls[n], XtNjumpProc,
+ (XtCallbackProc)SFhSliderMovedCallback, (XtPointer) n);
+ XtAddCallback(selFileHScrolls[n], XtNscrollProc,
+ (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer) n);
+ }
+
+ /* Do the file filter stuff. */
+ selFileLabel = XtVaCreateManagedWidget("selFileLabel",
+ labelWidgetClass, selFileForm,
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+/* XtNfromHoriz, selFileCancel, */
+/* XtNhorizDistance, 60, */
+ XtNlabel, "File Mask:",
+ XtNborderWidth, 0,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop, NULL);
+
+ selFileMask = XtVaCreateManagedWidget("selFileMask",
+ asciiTextWidgetClass, selFileForm,
+ XtNwidth, MASKWIDTH / 2 * SFcharWidth,
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNfromHoriz, selFileLabel,
+ XtNhorizDistance, 0,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNstring, fileMask,
+ XtNlength, MASKWIDTH,
+ XtNeditType, XawtextEdit,
+ XtNwrap, XawtextWrapNever,
+ XtNuseStringInPlace, True, NULL);
+
+ for (i = 0; i < 3; i++)
+ XtSetKeyboardFocus(selFileLists[i], selFileField);
+
+ XtOverrideTranslations(selFileMask,
+ XtParseTranslationTable
+ (oneLineTextEditTranslations));
+
+ XtAddEventHandler(selFileMask, KeyPressMask, False,
+ (XtEventHandler)maskChanged, (XtPointer) NULL);
+
+ selFileLabel = XtVaCreateManagedWidget("selFileLabel",
+ labelWidgetClass, selFileForm,
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNfromHoriz, selFileMask,
+ XtNhorizDistance, 40,
+ XtNlabel, "Dot files are:",
+ XtNborderWidth, 0,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop, NULL);
+
+ selFileHide = XtVaCreateManagedWidget("selFileHide",
+ commandWidgetClass, selFileForm,
+/* XtNwidth, 7 * SFcharWidth, */
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNfromHoriz, selFileLabel,
+ XtNhorizDistance, 2,
+ XtNlabel, hideFlag ? "hidden" : "shown",
+/* XtNborderWidth, 1, */
+ XtNtop, XtChainTop,
+/* XtNjustify, XtJustifyLeft, */
+ XtNbottom, XtChainTop,
+ NULL);
+ XtAddCallback(selFileHide, XtNcallback, (XtCallbackProc)hideFiles, NULL);
+
+ box = XtVaCreateManagedWidget("box", formWidgetClass,
+ paned,
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6,
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ selFileOK = XtVaCreateManagedWidget("selFileOK", commandWidgetClass,
+ box,
+ XtNlabel, ok,
+ XtNcallback, SFokSelect,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+ selFileCancel = XtVaCreateManagedWidget("selFileCancel", commandWidgetClass,
+ box,
+ XtNlabel, cancel,
+ XtNcallback, SFcancelSelect,
+/* XtNborderColor, SFfore, */
+ XtNfromHoriz, selFileOK,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ NULL);
+
+ XtSetMappedWhenManaged(selFile, False);
+ XtRealizeWidget(selFile);
+
+ /* Add WM_DELETE_WINDOW protocol */
+ SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
+
+ SFcreateGC();
+
+ xtermCursor = XCreateFontCursor(SFdisplay, XC_xterm);
+
+ sbRightArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_right_arrow);
+ arrowCursor = XCreateFontCursor(SFdisplay, XC_left_ptr);
+
+ XDefineCursor(SFdisplay, XtWindow(selFileForm), arrowCursor);
+ XDefineCursor(SFdisplay, XtWindow(selFileField), xtermCursor);
+
+ for (n = 0; n < 3; n++) {
+ XDefineCursor(SFdisplay, XtWindow(selFileLists[n]), sbRightArrowCursor);
+ }
+ XDefineCursor(SFdisplay, XtWindow(selFileOK), arrowCursor);
+ XDefineCursor(SFdisplay, XtWindow(selFileCancel), arrowCursor);
+
+ for (n = 0; n < 3; n++) {
+ XtAddEventHandler(selFileLists[n], ExposureMask, True,
+ (XtEventHandler)SFexposeList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
+ (XtEventHandler)SFenterList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
+ (XtEventHandler)SFleaveList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
+ (XtEventHandler)SFmotionList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
+ (XtEventHandler)SFbuttonPressList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
+ (XtEventHandler)SFbuttonReleaseList, (XtPointer) n);
+ }
+
+ XtAddEventHandler(selFileField, KeyPressMask, False,
+ (XtEventHandler)SFmodVerifyCallback, (XtPointer) NULL);
+
+ SFapp = XtWidgetToApplicationContext(selFile);
+ return selFile;
+}
+
+/* position widget under the cursor */
+void
+SFpositionWidget(Widget w)
+{
+ Arg args[3];
+ Cardinal num_args;
+ Dimension width, height, b_width;
+ int x, y, max_x, max_y;
+ Window root, child;
+ int dummyx, dummyy;
+ unsigned int dummymask;
+
+ XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
+ &dummyx, &dummyy, &dummymask);
+ num_args = 0;
+ XtSetArg(args[num_args], XtNwidth, &width);
+ num_args++;
+ XtSetArg(args[num_args], XtNheight, &height);
+ num_args++;
+ XtSetArg(args[num_args], XtNborderWidth, &b_width);
+ num_args++;
+ XtGetValues(w, args, num_args);
+
+ width += 2 * b_width;
+ height += 2 * b_width;
+
+ x -= ((Position) width / 2);
+ if (x < 0)
+ x = 0;
+ if (x > (max_x = (Position) (XtScreen(w)->width - width)))
+ x = max_x;
+
+ y -= ((Position) height / 2);
+ if (y < 0)
+ y = 0;
+ if (y > (max_y = (Position) (XtScreen(w)->height - height)))
+ y = max_y;
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNx, x);
+ num_args++;
+ XtSetArg(args[num_args], XtNy, y);
+ num_args++;
+ XtSetValues(w, args, num_args);
+}
+
+
+FILE *
+SFopenFile(const char *name, const char *mode, const char *prompt, const char *failed)
+{
+ Arg args[1];
+ FILE *fp;
+
+ UNUSED(args);
+ UNUSED(prompt);
+ UNUSED(failed);
+
+ SFchdir(SFstartDir);
+ errno = 0;
+ if (!name || *name == 0 || (fp = XFOPEN(name, mode)) == NULL) {
+ XBell(DISP, 0);
+ return NULL;
+ }
+ return fp;
+}
+
+void
+SFtextChanged(void)
+{
+ if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) {
+ (void)strcpy(SFcurrentPath, SFtextBuffer);
+
+ SFtextPos = XawTextGetInsertionPoint(selFileField);
+ }
+ else {
+ (void)strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
+
+ SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
+ }
+
+ if (!SFworkProcAdded) {
+ (void)XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
+ SFworkProcAdded = 1;
+ }
+
+ SFupdatePath();
+}
+
+static void
+SFprepareToReturn(void)
+{
+ SFstatus = SEL_FILE_NULL;
+ /* XtRemoveGrab(selFile); */
+ XtUnmapWidget(selFile);
+
+ if (SFdirModTimerId) {
+ XtRemoveTimeOut(SFdirModTimerId);
+ SFdirModTimerId = 0;
+ }
+ if (SFchdir(SFstartDir)) {
+ XtAppError(SFapp, "XsraSelFile: can't return to current directory");
+ }
+}
+
+void
+XsraSelFile(Widget parent, struct filesel_callback *callback)
+/* const char *title, const char *prompt, */
+/* const char *ok, const char *cancel, */
+/* const char *init_path, */
+/* const char *mask, */
+/* Boolean must_exist, */
+/* Widget *ret_widget */
+{
+ static Boolean firstTime = True;
+ Widget w;
+ Cardinal i;
+ Arg arglist[20];
+ XEvent event;
+
+ if (!callback->prompt) {
+ callback->prompt = "Pathname:";
+ }
+
+ if (!callback->title) {
+ callback->title = "Xdvi: select filename";
+ }
+
+ if (!callback->ok) {
+ callback->ok = "OK";
+ }
+
+ if (!callback->cancel) {
+ callback->cancel = "Cancel";
+ }
+
+ if (firstTime) {
+ firstTime = False;
+ SFdisplay = XtDisplay(parent);
+ w = SFcreateWidgets(parent, callback->title, callback->prompt, callback->ok, callback->cancel);
+ }
+ else {
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, callback->prompt);
+ i++;
+ XtSetValues(selFilePrompt, arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, callback->ok);
+ i++;
+ XtSetValues(selFileOK, arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, callback->cancel);
+ i++;
+ XtSetValues(selFileCancel, arglist, i);
+ }
+
+ SFpositionWidget(selFile);
+ XtMapWidget(selFile);
+
+ {
+ char *cwd = xgetcwd();
+ strcpy(SFstartDir, cwd);
+ free(cwd);
+ }
+ if (SFstartDir[0] == 0) {
+ XtAppError(SFapp, "XsraSelFile: can't get current directory");
+ }
+ (void)strcat(SFstartDir, "/");
+ (void)strcpy(SFcurrentDir, SFstartDir);
+
+ if (callback->init_path) {
+ if (callback->init_path[0] == '/') {
+ (void)strcpy(SFcurrentPath, callback->init_path);
+ if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
+ SFsetText(SFcurrentPath);
+ }
+ else {
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+ }
+ }
+ else {
+ (void)strcat(strcpy(SFcurrentPath, SFstartDir), callback->init_path);
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+ }
+ }
+ else {
+ SFsetText(SFcurrentDir);
+ (void)strcpy(SFcurrentPath, SFstartDir);
+ }
+
+ SFfunc = showEntry;
+
+ SFtextChanged();
+
+ /* don't grab the pointer so that warning popups still work */
+ /* XtAddGrab(selFile, True, True); */
+
+ SFdirModTimerId = XtAppAddTimeOut(SFapp, 1200UL,
+ SFdirModTimer, (XtPointer) NULL);
+
+ if (strcmp(fileMask, callback->filemask) != 0) { /* if mask changed */
+ SFDir *dir;
+ strncpy(fileMask, callback->filemask, MASKWIDTH);
+ XtVaSetValues(selFileMask, XtNstring, fileMask, NULL);
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ *(dir->dir) = 0; /* force a re-read */
+ SFupdatePath();
+ }
+
+ while (1) {
+ XtAppNextEvent(SFapp, &event);
+ switch (event.type) {
+ Widget w;
+#if 0 /* don't do this, it may send the X server into a busy loop if the File selector
+ is positioned over a window that is `on top' by default */
+ case Expose:
+ if (!raise_message_windows())
+ raise_file_selector();
+ break;
+#endif
+ case KeyPress:
+ case ButtonPress:
+ /* beep if keypress was inside main window */
+ w = XtWindowToWidget(DISP, event.xany.window);
+ while ((w != NULL) && (w != selFile)) {
+ /* exception: message windows */
+ if (is_message_window(w))
+ break;
+ w = XtParent(w);
+ }
+ if (w == NULL || w == globals.widgets.top_level) {
+ XBell(DISP, 0);
+ }
+ break;
+ }
+
+ XtDispatchEvent(&event);
+
+ switch (SFstatus) {
+ case SEL_FILE_TEXT:
+ SFstatus = SEL_FILE_NULL;
+ SFtextChanged();
+ break;
+ case SEL_FILE_OK:
+ if (callback->must_exist) {
+ FILE *tmp_fp = XFOPEN(SFtextBuffer, "r");
+ dviErrFlagT errflag = NO_ERROR;
+ if (tmp_fp == NULL) {
+ popup_message(selFile,
+ MSG_ERR, NULL, "Could not open %s: %s.\n",
+ SFtextBuffer, strerror(errno));
+ SFstatus = SEL_FILE_NULL;
+ break;
+ }
+ else if (!process_preamble(tmp_fp, &errflag)
+ || !find_postamble(tmp_fp, &errflag)
+ || !read_postamble(tmp_fp, &errflag, False)) {
+ popup_message(selFile,
+ MSG_ERR, NULL, "Error opening %s:\n%s.",
+ SFtextBuffer, get_dvi_error(errflag));
+ fclose(tmp_fp);
+ SFstatus = SEL_FILE_NULL;
+ break;
+ }
+ else { /* file is OK */
+ fclose(tmp_fp);
+ SFprepareToReturn();
+ callback->func_ptr(SFtextBuffer, callback->data);
+ return;
+/* return xstrdup(SFtextBuffer); */
+ }
+ }
+ else {
+ SFprepareToReturn();
+ callback->func_ptr(SFtextBuffer, callback->data);
+ return;
+/* return xstrdup(SFtextBuffer); */
+ }
+ case SEL_FILE_CANCEL:
+ SFprepareToReturn();
+ if (callback->exit_on_cancel)
+ exit(0);
+ return;
+/* return NULL; */
+ case SEL_FILE_NULL:
+ break;
+ }
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfSelFile.h b/Build/source/texk/xdvik/gui/sfSelFile.h
new file mode 100644
index 00000000000..298d15ea45a
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfSelFile.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef SFSELFILE_H_
+#define SFSELFILE_H_
+
+struct filesel_callback {
+ const char *title;
+ const char *prompt;
+ const char *ok;
+ const char *cancel;
+ const char *init_path;
+ const char *filemask;
+ Boolean must_exist;
+ Boolean exit_on_cancel;
+ void (*func_ptr)(const char *filename, void *data);
+ void *data;
+};
+
+extern void SFpositionWidget(Widget w);
+extern FILE *SFopenFile(const char *name, const char *mode, const char *prompt, const char *failed);
+extern void SFtextChanged(void);
+extern void XsraSelFile(Widget parent, struct filesel_callback *callback);
+void raise_file_selector(void);
+
+#endif /* SF_SEL_FILE_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfinternal.h b/Build/source/texk/xdvik/gui/sfinternal.h
new file mode 100644
index 00000000000..c776bfc6c97
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfinternal.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#undef wchar_t
+
+#define SEL_FILE_CANCEL -1
+#define SEL_FILE_OK 0
+#define SEL_FILE_NULL 1
+#define SEL_FILE_TEXT 2
+
+#define SF_DO_SCROLL 1
+#define SF_DO_NOT_SCROLL 0
+
+
+extern void
+ SFenterList(),
+ SFleaveList(),
+ SFmotionList(),
+ SFbuttonPressList(),
+ SFbuttonReleaseList();
+
+extern void
+ SFvSliderMovedCallback(),
+ SFvFloatSliderMovedCallback(),
+ SFhSliderMovedCallback(),
+ SFpathSliderMovedCallback(),
+ SFvAreaSelectedCallback(),
+ SFhAreaSelectedCallback(),
+ SFpathAreaSelectedCallback();
+
+
diff --git a/Build/source/texk/xdvik/gui/statusline.c b/Build/source/texk/xdvik/gui/statusline.c
new file mode 100644
index 00000000000..16715283cf4
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/statusline.c
@@ -0,0 +1,531 @@
+/*------------------------------------------------------------
+ statusline for the xdvi(k) previewer
+
+ written by S. Ulrich (ulrich@cis.uni-muenchen.de) 2000/02/25
+
+ 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.
+ ------------------------------------------------------------*/
+
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+#include "statusline.h"
+#include "xm_menu.h"
+#include "x_util.h"
+#include "pagehist.h"
+#include "util.h"
+
+#include "kpathsea/c-vararg.h"
+#include "my-vsnprintf.h"
+
+#include <ctype.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+# ifdef MOTIF
+# include <Xm/Label.h>
+# include <Xm/Frame.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# else
+# include <X11/Xaw/Viewport.h>
+# include <X11/Xaw/Label.h>
+# endif
+
+
+Widget statusline;
+
+static Boolean initialized = False;
+
+/*
+ * only print MAX_LEN characters to the statusline
+ * (it's only 1 line after all)
+ */
+#define MAX_LEN 512
+
+/* for saving the statusline string if the statusline is
+ * destroyed and recreated
+ */
+static char g_string_savebuf[MAX_LEN + 2];
+
+int global_statusline_h = 20;
+
+#if MOTIF
+static void
+handle_statusline_event(Widget w, XtPointer client_data,
+ XEvent *ev, Boolean *cont)
+{
+/* const char *text = (const char *)client_data; */
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(cont);
+
+/* fprintf(stderr, "text: |%s|; event: %p\n", text, ev); */
+ /* only used to do this if page history was already active, but it's probably
+ nicer to be able to get the history by clicking on the statusline ...
+ */
+ if (/* strncmp(text, "Page history:", sizeof "Page history:" - 1) == 0 && */ ev != NULL) {
+ XmTextPosition pos = XmTextGetCursorPosition(statusline);
+ char *ptr1, *ptr2;
+ int diff = 0;
+/* fprintf(stderr, "pos: %d\n", pos); */
+ if (pos == 0) { /* just display the page history */
+ page_history_move(0);
+ return;
+ }
+ ptr1 = g_string_savebuf + pos;
+ ptr2 = strchr(g_string_savebuf, '[');
+ if (ptr2 == NULL) { /* some other string, also display the page history */
+ page_history_move(0);
+ return;
+ }
+/* fprintf(stderr, "ptr1: |%s|; ptr2: |%s|\n", ptr1, ptr2); */
+ while (ptr1 < ptr2) {
+ if (*ptr1 == ' ' && *(ptr1 + 1) != '-') /* separator */
+ diff--;
+ ptr1++;
+ }
+
+ while (ptr1 > ptr2) {
+ if (*ptr1 == ' ' && *(ptr1 - 1) != '-') /* separator */
+ diff++;
+ ptr1--;
+ }
+/* fprintf(stderr, "diff: %d\n", diff); */
+ page_history_move(diff);
+ }
+}
+#endif /* MOTIF */
+
+/*
+ * Create the statusline widget. To be called at the beginning
+ * of the program, and when expert mode is switched off.
+ *
+ * Side effects:
+ * sets <global_statusline_h> to the height of the statusline in pixels.
+ */
+
+Widget
+create_statusline(
+#ifdef MOTIF
+ Widget parent
+#else
+ void
+#endif
+ )
+{
+#ifndef MOTIF
+ Position vport_h;
+ Position clip_x;
+ Position clip_w;
+ static Position my_h = 0;
+#endif
+
+ /*
+ * FIXME: is there a better way to set the y position depending on
+ * the height of the widget?
+ * It doesn't work to change the value of XtNy *after* creating
+ * the widget!
+ */
+
+ if (!initialized) {
+#ifndef MOTIF
+ /*
+ * determine height of statusline (depending on the font used).
+ * This is not changeable at runtime, so it's determined once and
+ * for all at program start.
+ */
+ statusline = XtVaCreateWidget("statusline", labelWidgetClass, globals.widgets.vport_widget,
+ XtNlabel, (XtArgVal) "test",
+ NULL);
+ XtVaGetValues(statusline, XtNheight, &my_h, NULL);
+ global_statusline_h = my_h;
+ XtDestroyWidget(statusline);
+#endif
+ initialized = True;
+ /* initialize g_string_savebuf */
+ sprintf(g_string_savebuf, "This is xdvik %s", XDVI_TERSE_VERSION_INFO);
+ }
+#ifndef MOTIF
+ /* determine position and width of statusline */
+ XtVaGetValues(globals.widgets.clip_widget, XtNx, &clip_x, XtNwidth, &clip_w, NULL);
+ XtVaGetValues(globals.widgets.vport_widget, XtNheight, &vport_h, NULL);
+ if (vport_h - my_h <= 0) {
+ XDVI_FATAL((stderr, "Window height too small for statusline (minimum value: %d).", my_h));
+ return NULL;
+ }
+ statusline = XtVaCreateManagedWidget("statusline",
+ labelWidgetClass, globals.widgets.vport_widget,
+ XtNlabel, (XtArgVal) g_string_savebuf,
+ XtNwidth, clip_w,
+ XtNx, clip_x - 1, /* so that left border becomes invisible */
+ XtNy, vport_h - my_h,
+ XtNjustify, XtJustifyLeft,
+ /* same as for the buttons line */
+ XtNborder, (XtArgVal) resource.fore_Pixel,
+ NULL);
+#else
+ statusline = XtVaCreateManagedWidget("statusline",
+ xmTextFieldWidgetClass, parent,
+ XmNalignment, XmALIGNMENT_END,
+ XmNdepth, (XtArgVal) G_depth,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftOffset, 1,
+ XmNrightOffset, 1,
+ XmNbottomOffset, 1,
+ XmNtopOffset, 0,
+ XmNcursorPositionVisible, False,
+ XmNautoShowCursorPosition, False,
+ XmNmarginWidth, 4,
+ XmNmarginHeight, 1,
+ XmNeditable, False,
+ XmNtraversalOn, False,
+ XmNvalue, g_string_savebuf,
+ NULL);
+
+ /* Block processing of most interactive events on this widget, except
+ * for button events that should navigate the page history.
+ */
+ XtInsertEventHandler(statusline,
+ KeyPressMask | KeyReleaseMask |
+ PointerMotionMask| PointerMotionHintMask |
+ ButtonMotionMask |
+#if !MOTIF
+ ButtonPressMask | ButtonReleaseMask |
+#endif
+ FocusChangeMask,
+ /* ButtonPressMask | ButtonReleaseMask | */
+ /* PointerMotionMask| PointerMotionHintMask | */
+ /* ButtonMotionMask | */
+ True, block_event_callback,
+ (XtPointer)0, 0);
+#if MOTIF
+ XtInsertEventHandler(statusline,
+ /* suboptimal, but needs to be release not press
+ * since we want to query the current cursor position,
+ * and that may not be set yet in the press event(?).
+ */
+ ButtonReleaseMask,
+ True, handle_statusline_event,
+ (XtPointer)g_string_savebuf, XtListTail);
+
+#endif /* MOTIF */
+
+#endif
+
+ return statusline;
+}
+
+
+void
+toggle_statusline(void)
+{
+#ifdef MOTIF
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0)
+ XtUnmanageChild(statusline);
+ else
+ XtManageChild(statusline);
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+#else
+ set_show_statusline_option();
+#endif
+#else
+ static Boolean initialized = False;
+ static Boolean statusline_mapped = False;
+
+ Boolean make_statusline_visible = False;
+ Boolean make_statusline_invisible = False;
+
+ if (!initialized) {
+ statusline_mapped = (resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0;
+ initialized = True;
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) {
+ if (statusline_mapped)
+ make_statusline_invisible = True;
+ }
+ else {
+ if (!statusline_mapped)
+ make_statusline_visible = True;
+ }
+
+ if (make_statusline_invisible) {
+ XtDestroyWidget(statusline);
+ statusline_mapped = False;
+ }
+ if (make_statusline_visible) {
+ static Dimension window_w, window_h;
+
+ static Arg arg_wh[] = {
+ {XtNwidth, (XtArgVal) &window_w},
+ {XtNheight, (XtArgVal) &window_h},
+ };
+#ifdef MOTIF
+ XtGetValues(globals.widgets.main_window, arg_wh, XtNumber(arg_wh));
+#else
+ XtGetValues(globals.widgets.vport_widget, arg_wh, XtNumber(arg_wh));
+#endif
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
+ TRACE_GUI((stderr, "statusline: w %d, h %d", window_w, window_h));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, (XtArgVal)window_w, XtNheight, (XtArgVal)window_h, NULL);
+ TRACE_GUI((stderr, "after statusline"));
+ create_statusline();
+ statusline_mapped = True;
+ }
+#endif /* MOTIF */
+}
+
+
+/*------------------------------------------------------------
+ * handle_statusline_resize
+ *
+ * Arguments:
+ * void
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Resize the statusline when the total window size changes.
+ *
+ *------------------------------------------------------------*/
+
+void
+handle_statusline_resize(void)
+{
+#ifndef MOTIF
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) {
+ return;
+ }
+
+ if (!statusline)
+ return;
+
+ /* apparently the x,y values of a widget can only be set at creation time, so
+ * the following won't work:
+ */
+
+#if 0
+ /*
+ BROKEN Position vport_h, clip_x, clip_w;
+ BROKEN static Position my_h = 0;
+ BROKEN
+ BROKEN XtVaGetValues(globals.widgets.clip_widget,
+ BROKEN XtNx, &clip_x,
+ BROKEN XtNwidth, &clip_w,
+ BROKEN NULL);
+ BROKEN XtVaGetValues(globals.widgets.vport_widget,
+ BROKEN XtNheight, &vport_h,
+ BROKEN NULL);
+ BROKEN
+ BROKEN XtUnmanageChild(statusline);
+ BROKEN XtVaSetValues(statusline,
+ BROKEN XtNlabel, (XtArgVal) "",
+ BROKEN XtNwidth, clip_w,
+ BROKEN XtNx, clip_x - 1,
+ BROKEN XtNy, vport_h - my_h,
+ BROKEN XtNborderWidth, 1,
+ BROKEN XtNjustify, XtJustifyLeft,
+ BROKEN XtNborder, (XtArgVal) resource.fore_Pixel,
+ BROKEN NULL);
+ BROKEN XtManageChild(statusline);
+ BROKEN XFlush(DISP);
+ */
+#endif
+
+ /* only this will: */
+ XtDestroyWidget(statusline);
+ create_statusline();
+#endif
+}
+
+
+
+
+/*
+ * clear statusline by printing an empty message to it.
+ */
+
+
+static void
+clear_statusline(void)
+{
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) {
+# ifdef MOTIF
+ XmTextFieldSetString(statusline, " ");
+# else
+ XtVaSetValues(statusline, XtNlabel, " ", NULL);
+# endif
+ XFlush(DISP);
+ }
+ strcpy(g_string_savebuf, " ");
+}
+
+
+/* force a statusline update, no matter how busy the application is.
+ Use this with care (only for important messages).
+*/
+void
+force_statusline_update(void)
+{
+#ifdef MOTIF
+ XmUpdateDisplay(globals.widgets.top_level);
+#else
+ XEvent event;
+ XSync(DISP, False);
+ while (XCheckMaskEvent(DISP, ExposureMask, &event))
+ XtDispatchEvent(&event);
+#endif /* MOTIF */
+}
+
+
+/*
+ * timeout - if > 0, timeout in seconds after which the message will
+ * be deleted again. If < 0, message will remain (until
+ * another message overprints it)
+ * fmt - message, a C format string
+ *
+ * If expert mode is off, print <fmt> to the statusline; else, print
+ * <fmt> to stdout, unless the `hushstdout' option is specified.
+ */
+static XtIntervalId clear_timeout_id = 0;
+
+static void
+clear_statusline_timer_proc(XtPointer client_data, XtIntervalId *id)
+{
+ UNUSED(client_data);
+ UNUSED(id);
+
+ if (clear_timeout_id) {
+ clear_statusline();
+ clear_timeout_id = 0;
+ }
+}
+
+static void
+internal_print_statusline(statusTimerT timeout, const char *old_content, const char *fmt, va_list argp)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || !initialized || (resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) {
+ if (!resource.hush_stdout && strlen(fmt) > 0) { /* check for strlen since sometimes we clear the statusline
+ by printing "" to it, and we don't want that on stdout */
+ fprintf(stdout, "xdvi: ");
+ if (old_content != NULL)
+ (void)fputs(old_content, stdout);
+ (void)vfprintf(stdout, fmt, argp);
+ fputc('\n', stdout);
+ fflush(stdout);
+ }
+ }
+ else {
+ char buf[MAX_LEN + 1];
+ size_t offset = 0;
+
+ if (old_content != NULL && old_content[0] != '\0') {
+ offset += strlen(old_content);
+ strncpy(buf, old_content, MAX_LEN);
+ /* append separating space */
+ if (strlen(old_content) < MAX_LEN - 1) {
+ strcat(buf, " ");
+ offset++;
+ }
+ }
+ VSNPRINTF(buf + offset, MAX_LEN - offset, fmt, argp); /* just throw away strings longer than MAX_LEN */
+ buf[MAX_LEN] = '\0'; /* terminate buf */
+ /*
+ * save current contents of statusline so that toggling the statusline
+ * on and off will display the same text again
+ */
+ strcpy(g_string_savebuf, buf);
+#ifdef MOTIF
+ XmTextFieldSetString(statusline, buf);
+#else
+ XtVaSetValues(statusline, XtNlabel, buf, NULL);
+#endif
+/* fprintf(stderr, "timeout: %d, id: %ld\n", timeout, clear_timeout_id); */
+ if (timeout > 0) {
+ timeout *= 1000; /* convert to miliseconds */
+
+ if (clear_timeout_id) {
+/* fprintf(stderr, "clearing!\n"); */
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: removing timeout %ld\n", __FILE__, __LINE__, clear_timeout_id);
+ XtRemoveTimeOut(clear_timeout_id);
+ }
+ clear_timeout_id = XtAppAddTimeOut(app, timeout,
+ clear_statusline_timer_proc, (XtPointer) NULL);
+ }
+ }
+}
+
+/*
+ * Append the varargs-string `fmt' to the currnent contents of the statusline
+ * erasing it after `timeout' seconds if timeout > 0, unless the current statusline
+ * contents matches pattern - in that case, overwrite the contents.
+ */
+void
+statusline_append(statusTimerT timeout, const char *pattern, const char *fmt, ...)
+{
+ const char *buf = NULL;
+ va_list argp;
+
+ if (XtIsRealized(globals.widgets.top_level) && initialized && (resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) {
+ /* get current statusline contents */
+#ifdef MOTIF
+ XtVaGetValues(statusline, XmNvalue, &buf, NULL);
+#else
+ XtVaGetValues(statusline, XtNlabel, &buf, NULL);
+#endif
+ }
+
+ while (buf != NULL && isspace((int)*buf)) /* skip spaces inserted by statusline appending */
+ buf++;
+ va_start(argp, fmt);
+
+ if (buf != NULL && memcmp(buf, pattern, strlen(pattern)) == 0) {
+ buf = NULL;
+ }
+ internal_print_statusline(timeout, buf, fmt, argp);
+ va_end(argp);
+}
+
+/*
+ * Print the varargs-string `fmt' to the currnent contents of the statusline,
+ * erasing it after `timeout' seconds if timeout > 0.
+ */
+
+void
+statusline_print(statusTimerT timeout, const char *fmt, ...)
+{
+ va_list argp;
+ va_start(argp, fmt);
+ internal_print_statusline(timeout, NULL, fmt, argp);
+ va_end(argp);
+}
+
+void
+statusline_clear(void)
+{
+ statusline_print(STATUS_SHORT, "");
+}
diff --git a/Build/source/texk/xdvik/gui/statusline.h b/Build/source/texk/xdvik/gui/statusline.h
new file mode 100644
index 00000000000..5f9f5dcd10c
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/statusline.h
@@ -0,0 +1,52 @@
+#ifndef STATUSLINE_H_
+#define STATUSLINE_H_
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#define STAT_BUF_LEN 512
+
+
+/* statusline stuff. The following function and #defines are also
+ * needed when compiling without statusline support.
+ */
+typedef enum statusTimerT_ {
+ STATUS_FOREVER = 0,
+ STATUS_SHORT = 5,
+ STATUS_MEDIUM = 10,
+ STATUS_LONG = 30
+} statusTimerT;
+
+extern void statusline_clear(void);
+extern void statusline_print(statusTimerT timeout, const char *fmt, ...);
+extern void statusline_append(statusTimerT timeout, const char *pattern, const char *fmt, ...);
+#ifdef MOTIF
+extern Widget create_statusline(Widget parent);
+#else
+extern Widget create_statusline(void);
+#endif
+extern void handle_statusline_resize(void);
+
+extern void force_statusline_update(void);
+extern void toggle_statusline(void);
+
+#endif /* STATUSLINE_H_ */
diff --git a/Build/source/texk/xdvik/gui/topic-window.c b/Build/source/texk/xdvik/gui/topic-window.c
new file mode 100644
index 00000000000..7a87a03b5c8
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/topic-window.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * `Topics' window framework used by help and preferences windows.
+ * Contains a list of topics on the left-hand side, and corresponding
+ * contents on the right-hand side.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#if MOTIF
+# include <Xm/Xm.h>
+# include <Xm/Form.h>
+# include <Xm/DialogS.h>
+# include <Xm/PushB.h>
+# include <Xm/Frame.h>
+# include <Xm/PanedW.h>
+# include <Xm/LabelG.h>
+# include <Xm/Label.h>
+# include <Xm/Protocols.h>
+# include <Xm/List.h>
+# include <Xm/AtomMgr.h>
+#else /* MOTIF */
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Cardinals.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/List.h>
+#endif /* MOTIF */
+
+#include "version.h"
+#include "topic-window.h"
+#include "string-utils.h"
+#include "util.h"
+#include "x_util.h"
+
+#if MOTIF
+
+/* special formatting for headings in right window, if desired */
+const char *const TAG_NORMAL = "NORMAL";
+const char *const TAG_TOPIC_HEADING = "TOPIC_HEADING";
+const char *const TAG_TOPIC_LABEL = "TOPIC_LABEL";
+
+# define SHELL_WIDGET_CLASS xmDialogShellWidgetClass
+# define PANED_WIDGET_CLASS xmPanedWindowWidgetClass
+# define FORM_WIDGET_CLASS xmFormWidgetClass
+
+# define FORM_ARGS XmNhorizontalSpacing, 10, \
+ NULL
+# define HELP_SHELL_ARGS XmNdeleteResponse, XmDO_NOTHING, \
+ XtNmappedWhenManaged, False, \
+ NULL
+# define HELP_PANED_ARGS XmNsashWidth, 1, \
+ XmNuserData, info, \
+ XmNsashHeight, 1, \
+ NULL
+# define LEFT_FORM_ARGS XmNtopAttachment, XmATTACH_FORM, \
+ XmNleftAttachment, XmATTACH_FORM, \
+ XmNbottomAttachment, XmATTACH_FORM, \
+ XmNtopOffset, 9, \
+ XmNbottomOffset, 10, \
+ NULL
+# define RIGHT_FORM_ARGS XmNtopAttachment, XmATTACH_FORM, \
+ XmNleftAttachment, XmATTACH_WIDGET, \
+ XmNleftWidget, left_form, \
+ XmNrightAttachment, XmATTACH_FORM, \
+ XmNbottomAttachment, XmATTACH_FORM, \
+ XmNbottomOffset, 10, \
+ NULL
+# define ACTION_AREA_ARGS NULL
+
+#else /* MOTIF */
+
+# define SHELL_WIDGET_CLASS transientShellWidgetClass
+# define PANED_WIDGET_CLASS panedWidgetClass
+# define FORM_WIDGET_CLASS formWidgetClass
+
+# define FORM_ARGS XtNdefaultDistance, 14, \
+ NULL
+# define HELP_SHELL_ARGS XtNx, 60, \
+ XtNy, 80, \
+ XtNtransientFor, globals.widgets.top_level, \
+ XtNtranslations, xlats, \
+ XtNtransientFor, parent, \
+ XtNallowShellResize, False, \
+ NULL
+# define HELP_PANED_ARGS NULL
+# define LEFT_FORM_ARGS XtNtop, XtChainTop, \
+ XtNbottom, XtChainBottom, \
+ XtNleft, XtChainLeft, \
+ XtNright, XtChainLeft, \
+ XtNborderWidth, 0, \
+ NULL
+# define RIGHT_FORM_ARGS XtNfromHoriz, left_form, \
+ XtNtop, XtChainTop, \
+ XtNbottom, XtChainBottom, \
+ XtNleft, XtChainLeft, \
+ XtNright, XtChainRight, \
+ XtNborderWidth, 0, \
+ NULL
+# define ACTION_AREA_ARGS XtNdefaultDistance, 6, \
+ XtNshowGrip, False, \
+ XtNskipAdjust, True, \
+ NULL
+#endif /* MOTIF */
+
+
+static void
+ok_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "No info passed to callback!");
+
+ if (info->ok_callback != NULL)
+ info->ok_callback(info);
+ XtPopdown(info->shell);
+}
+
+static void
+cancel_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "No info passed to callback!");
+
+ if (info->cancel_callback != NULL)
+ info->cancel_callback(info);
+ XtPopdown(info->shell);
+}
+
+#if MOTIF
+/*
+ * We are overriding this since otherwise the Text widget would attempt to
+ * first move the invisible cursor instead of the scroll bars.
+ */
+/* FIXME: This gives a warning:
+ Warning: Actions not found: scroll-one-line-down, scroll-one-line-up
+*/
+/* "<Key>osfUp: scroll-one-line-down()\n" */
+/* "<Key>osfDown: scroll-one-line-up()\n" */
+#endif
+
+#if MOTIF
+static XmString
+#else
+static char *
+#endif
+create_label_string(const char *title, const char *subtitle)
+{
+#if MOTIF
+ XmString label;
+ if (subtitle == NULL) { /* simple bold label */
+ label = XmStringCreate((char *)title, (char *)TAG_TOPIC_LABEL);
+ }
+ else { /* two-part title with subheading */
+ XmString s1, s2, s3, s4;
+ s1 = XmStringCreate((char *)title, (char *)TAG_TOPIC_HEADING);
+ s2 = XmStringCreate((char *)" ", (char *)TAG_NORMAL);
+ s3 = XmStringCreate((char *)subtitle, (char *)TAG_NORMAL);
+ s4 = XmStringConcat(s1, s2);
+ label = XmStringConcat(s4, s3);
+ XmStringFree(s1);
+ XmStringFree(s2);
+ XmStringFree(s3);
+ XmStringFree(s4);
+ }
+#else
+ char *label = xstrdup(title);
+ if (subtitle != NULL && strlen(subtitle) > 0) {
+ label = xstrcat(label, " - ");
+ label = xstrcat(label, subtitle);
+ }
+#endif
+ return label;
+}
+
+static Widget
+create_label_widget(Widget parent, const char *name, struct topic_info *info)
+{
+ Widget label;
+
+#if MOTIF
+
+ XmString label_string = create_label_string(info->items[0].topic, info->items[0].title);
+ label = XtVaCreateWidget(name, xmLabelWidgetClass, parent,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 14,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNlabelString, label_string,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ XmStringFree(label_string);
+
+#else /* MOTIF */
+
+ char *label_string = create_label_string(info->items[0].topic, info->items[0].title);
+ label = XtVaCreateWidget(name, labelWidgetClass, parent,
+ XtNlabel, label_string,
+ XtNborderWidth, 0,
+ /* XtNinternalHeight, 2, */
+ XtNjustify, XtJustifyLeft,
+ NULL);
+ free(label_string);
+
+#endif /* MOTIF */
+
+ return label;
+}
+
+void
+select_topic(struct topic_info *info, size_t idx)
+{
+#if MOTIF
+ XmString label;
+#else
+ char *label;
+#endif
+
+ /* change the heading in right window */
+ label = create_label_string(info->items[idx].topic, info->items[idx].title);
+ XtVaSetValues(info->topic_label,
+#if MOTIF
+ XmNlabelString,
+#else
+ XtNlabel,
+#endif
+ label, NULL);
+
+#if MOTIF
+ XmStringFree(label);
+ XmListSelectPos(info->topics_list, idx + 1, False);
+#else
+ free(label);
+ XawListHighlight(info->topics_list, idx);
+#endif
+
+ if (info->curr_selected != 0) {
+ XtUnmanageChild(info->curr_selected);
+ }
+ else {
+ /* Note: doesn't matter if not managed yet */
+/* XtUnmanageChild(info->items[0].widget); */
+ }
+
+ XtManageChild(info->items[idx].widget);
+ info->curr_selected = info->items[idx].widget;
+
+#if MOTIF
+ XmUpdateDisplay(info->shell);
+#endif
+}
+
+static void
+select_topic_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ size_t idx;
+
+#if MOTIF
+ idx = ((XmListCallbackStruct *)call_data)->item_position - 1;
+#else
+ idx = ((XawListReturnStruct *)call_data)->list_index;
+#endif
+ UNUSED(w);
+
+ /* ASSERT(idx < info->items_size, "list position exceeds items_size!"); */
+
+ select_topic(info, idx);
+}
+
+static Widget
+create_button(Widget parent, const char *name, Boolean show_as_default, Boolean left_position)
+{
+ Widget button;
+#if MOTIF
+ XmString s1 = XmStringCreateLocalized((char *)name);
+ button = XtVaCreateWidget(name, xmPushButtonWidgetClass, parent,
+ XmNlabelString, s1,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ NULL);
+ if (left_position)
+ XtVaSetValues(button,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 10,
+ NULL);
+ else
+ XtVaSetValues(button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 10,
+ NULL);
+ if (show_as_default)
+ XtVaSetValues(button, XmNshowAsDefault, True, NULL);
+
+ XtManageChild(button);
+ XmStringFree(s1);
+#else /* MOTIF */
+ UNUSED(show_as_default);
+ button = XtVaCreateManagedWidget(name, commandWidgetClass, parent,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ NULL);
+ if (left_position)
+ XtVaSetValues(button,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+ else
+ XtVaSetValues(button,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ NULL);
+#endif /* MOTIF */
+ return button;
+}
+
+static void
+close_topic_window(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ Widget button;
+ void *ptr;
+ struct topic_info *info;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (*num_params < 1) {
+ XDVI_WARNING((stderr, "Wrong argument number (%d) in callback!", *num_params));
+ return;
+ }
+
+ sscanf(*params, "%p", &ptr);
+ info = (struct topic_info *)ptr;
+
+ /* get a callback to close the button, in decreasing order of preference */
+ if (get_widget_by_name(&button, info->shell, "Cancel", False)
+ || get_widget_by_name(&button, info->shell, "Close", False)
+ || get_widget_by_name(&button, info->shell, "OK", False)) {
+ XtCallCallbacks(button,
+#if MOTIF
+ XmNactivateCallback,
+#else
+ XtNcallback,
+#endif
+ info);
+ }
+ else {
+ XDVI_WARNING((stderr, "No button found for widget %p!\n", (void *)info->shell));
+ }
+}
+
+static XtActionsRec popdown_actions[] = {
+#if !MOTIF
+ { "WM_popdown", close_topic_window },
+#endif
+ { "close-topic-window", close_topic_window },
+};
+
+static Widget
+create_list_widget(Widget parent, const char *w_name, struct topic_info *info)
+{
+ Widget list;
+ size_t tnum;
+#if MOTIF
+ XmString *topics = NULL;
+#else
+ static char **topics = NULL;
+#endif
+
+ for (tnum = 0; info->items[tnum].topic != NULL; tnum++) {
+ /* 1 more for terminating NULL needed for Xaw */
+ topics = xrealloc(topics, (tnum + 2) * sizeof *topics);
+#if MOTIF
+ topics[tnum] = XmStringCreateLocalized(info->items[tnum].topic);
+#else
+ topics[tnum] = xstrdup(info->items[tnum].topic);
+#endif
+ }
+
+#ifndef MOTIF
+ /* list needs to be terminated for Xaw */
+ topics[tnum] = NULL;
+#endif
+
+#if MOTIF
+ {
+ size_t i;
+ Arg args[20];
+ int n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNlistSpacing, 4); n++;
+ XtSetArg(args[n], XmNlistMarginHeight, 4); n++;
+ XtSetArg(args[n], XmNlistMarginWidth, 4); n++;
+ XtSetArg(args[n], XmNhighlightThickness, 0); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+
+ list = XmCreateScrolledList(parent, (char *)w_name, args, n);
+
+#if defined(__GNUC__) && DEVEL_MODE
+#warning TODO: make up/down scroll the list, and PgUp/PgDown scroll help text
+#warning TODO: add wheel mouse bindings
+ /*
+ * also fix bug with arrow keys first moving invisible cursor, then scrollbars
+ */
+#endif
+
+ XmListDeleteAllItems(list);
+ XmListAddItems(list, topics, tnum, 0);
+
+ for (i = 0; i < tnum; ++i) {
+ XmStringFree(topics[i]);
+ }
+ free(topics);
+ }
+ XtAddCallback(list, XmNbrowseSelectionCallback, select_topic_cb, info);
+ XmListSelectPos(list, 1, False); /* default position */
+#else /* MOTIF */
+ list = XtVaCreateWidget(w_name, listWidgetClass, parent,
+ XtNlist, topics,
+ XtNdefaultColumns, 1,
+ XtNforceColumns, True,
+ XtNverticalList, True,
+ XtNrowSpacing, 4,
+ XtNheight, 429,
+ NULL);
+ XtAddCallback(list, XtNcallback, select_topic_cb, info);
+ XawListHighlight(list, 0); /* default position */
+#endif /* MOTIF */
+ XtManageChild(list);
+ return list;
+}
+
+
+Widget
+create_topic_window(Widget parent,
+ const char *window_title,
+ const char *widget_name,
+ struct topic_info *info,
+ void (*init_items_func)(struct topic_info *info),
+ /* OK button/callbacks */
+ const char *ok_label,
+ /* Cancel button/callbacks (can be NULL) */
+ const char *cancel_label)
+{
+ Widget topic_window, topics_list, topic_label;
+ Widget pane, form, left_form, right_container_form, right_form;
+ Widget action_area, ok_button, cancel_button;
+ XtTranslations xlats;
+
+ XtAppContext app = NULL;
+ Atom WM_DELETE_WINDOW;
+
+ char *translation_str;
+ size_t i;
+
+#if !MOTIF
+ translation_str = get_string_va("<Message>WM_PROTOCOLS: WM_popdown(%p)", info);
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+#endif
+
+ topic_window = XtVaCreatePopupShell(widget_name, SHELL_WIDGET_CLASS,
+ parent,
+ XtNtitle, window_title,
+ HELP_SHELL_ARGS);
+
+#if MOTIF
+ /* make the window manager destroy action pop down the window */
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(topic_window), "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(topic_window, WM_DELETE_WINDOW, cancel_cb, info);
+#else
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(topic_window), "WM_DELETE_WINDOW", False);
+#endif
+ app = XtWidgetToApplicationContext(topic_window);
+ XtAppAddActions(app, popdown_actions, XtNumber(popdown_actions));
+
+ pane = XtVaCreateWidget("topic_pane", PANED_WIDGET_CLASS, topic_window, HELP_PANED_ARGS);
+
+ form = XtVaCreateWidget("form", FORM_WIDGET_CLASS, pane, FORM_ARGS);
+
+ /* left pane for topics selection */
+ left_form = XtVaCreateWidget("left_form", FORM_WIDGET_CLASS, form, LEFT_FORM_ARGS);
+
+ /* right form for topics display */
+ right_container_form = XtVaCreateWidget("right_container_form", FORM_WIDGET_CLASS, form, RIGHT_FORM_ARGS);
+
+ /*
+ Initialize the topic label and title string with dummy values - the real values
+ are only known inside init_items_func(). For Xaw, the size of the widget will be
+ adjusted below (for Motif it's always the full width of the right form, which is
+ what we want).
+ */
+ /* FIXME: Motif label is still chopped off if it's longer than right form -
+ work around by putting longest possible lable here ... */
+ /* Also, not all children will be sized correctly, e.g. the colors - work around
+ by specifying a rather large dummy text ... */
+ info->items[0].topic = "text text text";
+ info->items[0].title = "text text text text text text text text text text text text text text text text text";
+ topic_label = create_label_widget(right_container_form, "topic_label", info);
+ info->topic_label = topic_label;
+
+ right_form = XtVaCreateWidget("right_form", FORM_WIDGET_CLASS,
+ right_container_form,
+#if MOTIF
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, topic_label,
+ XmNtopOffset, 10,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ XtNborderWidth, 0,
+ XtNfromVert, topic_label,
+ XtNvertDistance, 6,
+#endif /* MOTIF */
+ NULL);
+ info->right_form = right_form;
+
+ /*
+ Call the init_items_func callback. This will populate the info->items list
+ with the appropriate info, and create the forms (info->items[i].widget)
+ which are the children of right_form (which is accessed inside init_items_func()
+ through info->right_form), and all their subchildren.
+
+ It is important that every child form is already managed inside init_items_func
+ so that the total size of the preferences window is set to the maximum size of
+ the children. (The children will be unmanaged again below). All these widgets
+ are never destroyed, and are managed by demand via the list selection callback
+ (select_topic_cb).
+ */
+ init_items_func(info);
+
+ XtManageChild(topic_label);
+
+ topics_list = create_list_widget(left_form, "topics_list", info);
+ info->topics_list = topics_list;
+
+ translation_str = get_string_va("#override \n"
+ "<Key>q:close-topic-window(%p)\n"
+#ifdef MOTIF
+ "<Key>osfCancel:close-topic-window(%p)\n"
+#else
+ "<Key>Escape:close-topic-window(%p)\n"
+#endif
+ "<Key>Return:close-topic-window(%p)",
+ info, info, info);
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+ translation_str = NULL;
+
+ XtOverrideTranslations(pane, xlats);
+ XtOverrideTranslations(topics_list, xlats);
+
+ XtManageChild(left_form);
+
+ XtManageChild(right_form);
+ XtManageChild(right_container_form);
+
+ /* action area at bottom */
+ action_area = XtVaCreateWidget("action_area", FORM_WIDGET_CLASS, pane, ACTION_AREA_ARGS);
+
+ ok_button = create_button(action_area, ok_label, True, True);
+ XtOverrideTranslations(ok_button, xlats);
+
+ if (cancel_label != NULL) {
+ cancel_button = create_button(action_area, cancel_label, False, False);
+ adjust_width(ok_button, cancel_button);
+#if MOTIF
+ XtAddCallback(cancel_button, XmNactivateCallback, cancel_cb, info);
+#else
+ XtAddCallback(cancel_button, XtNcallback, cancel_cb, info);
+#endif
+ XtOverrideTranslations(cancel_button, xlats);
+ }
+
+ XtManageChild(action_area);
+
+ XtManageChild(form);
+
+ XtManageChild(pane);
+
+ XtRealizeWidget(topic_window);
+
+ /* Now unmanage all children of right_form, as described above. */
+ for (i = 0; info->items[i].topic != NULL; i++) {
+ XtUnmanageChild(info->items[i].widget);
+ }
+ info->curr_selected = 0;
+
+#if MOTIF
+ /* enable OK button */
+ XmProcessTraversal(ok_button, XmTRAVERSE_CURRENT);
+ XtOverrideTranslations(ok_button,
+ XtParseTranslationTable("<Key>Return:ArmAndActivate()\n"
+ "<Key>q:ArmAndActivate()"));
+ XtAddCallback(ok_button, XmNactivateCallback, ok_cb, info);
+ XmAddWMProtocolCallback(topic_window, WM_DELETE_WINDOW, cancel_cb, info);
+ { /* disable resizing of lower part of pane (and button) */
+ Dimension h;
+ XtVaGetValues(ok_button, XmNheight, &h, NULL);
+ XtVaSetValues(action_area,
+ XmNpaneMaximum, h + 20,
+ XmNpaneMinimum, h + 20,
+ NULL);
+ }
+#else
+ XSetWMProtocols(XtDisplay(topic_window), XtWindow(topic_window), &WM_DELETE_WINDOW, 1);
+ XtAddCallback(ok_button, XtNcallback, ok_cb, info);
+#endif
+ return topic_window;
+}
diff --git a/Build/source/texk/xdvik/gui/topic-window.h b/Build/source/texk/xdvik/gui/topic-window.h
new file mode 100644
index 00000000000..b9df8f14db7
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/topic-window.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef TOPIC_WINDOW_H_
+#define TOPIC_WINDOW_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+struct topic_info; /* forward declaration */
+
+struct topic_item {
+ /* topic name */
+ char *topic;
+ /* longer title of topic, displayed as heading in the right window */
+ char *title;
+ /* the widget (subwindow of the right window) associated with the topic */
+ Widget widget;
+};
+
+struct topic_info {
+ /* the toplevel shell */
+ Widget shell;
+ /* the topics list */
+ Widget topics_list;
+ /* the right form, parent of the dummy form which
+ contains the right topic-specific window */
+ Widget right_form;
+ /* the topic label in right window */
+ Widget topic_label;
+ /* the currently selected widget */
+ Widget curr_selected;
+ /* callbacks for OK button (may be NULL); it's invoked from within
+ the `real' widget callback and is passed a pointer to this(!) struct topic_info */
+ void (*ok_callback)(XtPointer arg);
+ /* like ok_callback, for the Cancel button */
+ void (*cancel_callback)(XtPointer arg);
+ /* list of topic_items */
+ struct topic_item *items;
+ size_t items_size;
+ /* additional data the callback may need ... */
+ void *data;
+};
+
+extern Widget create_topic_window(Widget parent,
+ const char *window_title,
+ const char *widget_name,
+ struct topic_info *info,
+ void (*init_items_func)(struct topic_info *info),
+ /* OK button label (can be NULL) */
+ const char *ok_label,
+ /* Cancel button label (can be NULL) */
+ const char *cancel_label);
+extern void select_topic(struct topic_info *info, size_t idx);
+#endif /* TOPIC_WINDOW_H_ */
diff --git a/Build/source/texk/xdvik/gui/xaw_bitmaps.c b/Build/source/texk/xdvik/gui/xaw_bitmaps.c
new file mode 100644
index 00000000000..6b45ca60a74
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_bitmaps.c
@@ -0,0 +1,82 @@
+#include "xaw_bitmaps.h"
+
+/*
+ * Bitmaps for indicating checkbuttons and radiobuttons in Xaw popup windows.
+ * The size of these is 16x16.
+ */
+
+/* checkbuttons: rectangular box containing a tick mark if on, empty box else */
+unsigned char button_check_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x80, 0xfc, 0xff, 0x04, 0x60, 0x04, 0x30, 0x04, 0x38,
+ 0x64, 0x2c, 0xe4, 0x26, 0xc4, 0x23, 0x84, 0x21, 0x04, 0x20, 0x04, 0x20,
+ 0x04, 0x20, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00
+};
+unsigned char button_check_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20,
+ 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20,
+ 0x04, 0x20, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00
+};
+
+/* radiobuttons: round and filled with dot if on, empty else */
+unsigned char button_radio_on_bits[] = {
+/* 0x70, 0x00, 0x8c, 0x01, 0x02, 0x02, 0x72, 0x02, 0xf9, 0x04, 0xf9, 0x04, */
+/* 0xf9, 0x04, 0x72, 0x02, 0x02, 0x02, 0x8c, 0x01, 0x70, 0x00 */
+ 0x00,0x00,0x00,0x00,0xc0,0x03,0x30,0x0c,0x08,0x10,0xc8,0x13,0xe4,0x27,0xe4,
+ 0x27,0xe4,0x27,0xe4,0x27,0xc8,0x13,0x08,0x10,0x30,0x0c,0xc0,0x03,0x00,0x00,
+ 0x00,0x00
+};
+unsigned char button_radio_off_bits[] = {
+/* 0x70, 0x00, 0x8c, 0x01, 0x02, 0x02, 0x02, 0x02, 0x01, 0x04, 0x01, 0x04, */
+/* 0x01, 0x04, 0x02, 0x02, 0x02, 0x02, 0x8c, 0x01, 0x70, 0x00 */
+ 0x00,0x00,0x00,0x00,0xc0,0x03,0x30,0x0c,0x08,0x10,0x08,0x10,0x04,0x20,0x04,
+ 0x20,0x04,0x20,0x04,0x20,0x08,0x10,0x08,0x10,0x30,0x0c,0xc0,0x03,0x00,0x00,
+ 0x00,0x00
+};
+
+/*
+ * Bitmaps for left-hand markers in Xaw pulldown menus; these only
+ * use the mark elements from the button markers (dot, or tick).
+ */
+
+/* check options: similar to button_check_*_bits. */
+unsigned char menu_check_on_bits[] = {
+ 0x00, 0x04, 0x00, 0x06, 0x00, 0x03, 0x80, 0x01, 0xc6, 0x00, 0x6e, 0x00,
+ 0x3c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+unsigned char menu_check_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* radio options: tick mark if on, else empty. These are different from
+ the `round' buttons in button_radio_* (not ideal ...) since the round
+ buttons are too large for menus.
+*/
+unsigned char menu_radio_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xf8, 0x00, 0xf8, 0x00,
+ 0xf8, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+unsigned char menu_radio_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* arrow for Xaw submenus */
+unsigned char menu_arrow_bits[] = {
+/* 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00, */
+/* 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00 */
+
+ 0x00, 0x00, 0x20, 0x00, 0x60, 0x00, 0xe0, 0x00, 0xe0, 0x01, 0xe0, 0x03,
+ 0xe0, 0x01, 0xe0, 0x00, 0x60, 0x00, 0x20, 0x00, 0x00, 0x00
+/* 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, */
+/* 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00 */
+/* 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00 */
+};
+
+
+/* double arrow for popup menus */
+unsigned char menu_double_arrow_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0xf8, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xf8, 0x00, 0x70, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/Build/source/texk/xdvik/gui/xaw_bitmaps.h b/Build/source/texk/xdvik/gui/xaw_bitmaps.h
new file mode 100644
index 00000000000..21daf9e2bea
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_bitmaps.h
@@ -0,0 +1,21 @@
+#define BUTTON_BITMAP_H 16
+#define BUTTON_BITMAP_W 16
+extern unsigned char button_check_on_bits[];
+extern unsigned char button_check_off_bits[];
+extern unsigned char button_radio_on_bits[];
+extern unsigned char button_radio_off_bits[];
+
+#define MENU_BITMAP_H 11
+#define MENU_BITMAP_W 11
+extern unsigned char menu_check_on_bits[];
+extern unsigned char menu_check_off_bits[];
+extern unsigned char menu_radio_on_bits[];
+extern unsigned char menu_radio_off_bits[];
+
+#define MENU_ARROW_H 11
+#define MENU_ARROW_W 11
+extern unsigned char menu_arrow_bits[];
+
+#define MENU_DOUBLE_ARROW_H 16
+#define MENU_DOUBLE_ARROW_W 11
+extern unsigned char menu_double_arrow_bits[];
diff --git a/Build/source/texk/xdvik/gui/xaw_menu.c b/Build/source/texk/xdvik/gui/xaw_menu.c
new file mode 100644
index 00000000000..ef9b387f8c1
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_menu.c
@@ -0,0 +1,1449 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Menu bar implementation for the Athena widget set.
+ */
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "c-openmx.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "pagesel.h"
+#include "util.h"
+#include "x_util.h"
+#include "xaw_menu.h"
+#include "message-window.h"
+#include "my-snprintf.h"
+#include "filehist.h"
+#ifdef NEW_MENU_CREATION
+#include "menu.h"
+#endif /* NEW_MENU_CREATION */
+
+#ifndef MOTIF /* entire file */
+
+#include <ctype.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h> /* needed for def. of XtNiconX */
+
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/MenuButton.h>
+#include <X11/Xaw/Sme.h>
+#include <X11/Xaw/SmeBSB.h>
+#include <X11/Xaw/SmeLine.h>
+#include <X11/Xaw/Dialog.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/Panner.h>
+#include <X11/Xaw/Porthole.h>
+#include <X11/Xaw/Command.h>
+
+#ifndef MAX
+# define MAX(i, j) ( (i) > (j) ? (i) : (j) )
+#endif
+
+
+#ifndef NEW_MENU_CREATION
+#define SEP_CHAR ':' /* character separating entries in translations lines */
+#endif
+
+/* needed to count the callbacks */
+static int destroy_count = 0;
+
+/* width of button panel */
+static int my_panel_width = 0;
+
+/* access method for panel width */
+int
+get_panel_width(void)
+{
+ int retval = 0;
+ if (resource.expert_mode & XPRT_SHOW_BUTTONS)
+ retval = my_panel_width;
+ TRACE_GUI((stderr, "get_panel_width: %d", retval));
+ return retval;
+}
+
+#ifndef NEW_MENU_CREATION
+typedef enum { INVALID, /* some error */
+ NONE, /* no new button created */
+ MENU_SEPARATOR, MENU_BUTTON, MENU_ENTRY, COMMAND_BUTTON } buttonTypeT;
+
+struct button_info {
+ struct button_info *next;
+ char *label;
+ struct xdvi_action *action;
+ Widget widget;
+ buttonTypeT type;
+};
+
+static Widget panner = 0;
+static struct button_info *b_head = NULL;
+
+#define MAX_MENU_NUM 128
+#define MAX_BUTTON_NUM 128
+
+static struct menu_list_ {
+ char *name;
+ Widget button_widget;
+ Widget popup_widget;
+} menu_list[MAX_MENU_NUM];
+
+#endif /* not NEW_MENU_CREATION */
+
+#ifdef NEW_MENU_CREATION
+/*
+ ================================================================================
+ Pixmaps indicating the state of menu buttons (radiobutton/checkbox
+ on/off, cascading menu). Inspired by menu.c, `check_bits' in the xterm source.
+ ================================================================================
+*/
+#include "xaw_bitmaps.h"
+static Pixmap menu_check_on_bitmap;
+static Pixmap menu_check_off_bitmap;
+static Pixmap menu_radio_on_bitmap;
+static Pixmap menu_radio_off_bitmap;
+static Pixmap menu_arrow_bitmap;
+#else
+#include "xaw_bitmaps.h"
+/* lifted from menu.c, check_bits in xterm */
+static Pixmap menu_check_bitmap;
+static Pixmap menu_arrow_bitmap;
+#endif /* NEW_MENU_CREATION */
+
+/*
+ ============================================================
+ Hack for pullright menus part I: data
+ ============================================================
+*/
+
+/* There are a few custom widgets for pullright menus out there, but
+ * these are old and potentially buggy, so just do it manually via an
+ * event handler, similar to Motif tooltips.
+ */
+static XtIntervalId m_timeout = 0;
+static Widget m_active_submenu = NULL; /* if not NULL, the currently active pullright */
+static Widget m_submenu = NULL; /* parent of the currently active pullright
+ (i.e. the menu label in the parent window) */
+
+static void ActPopdownSubmenus(Widget w, XEvent *event, String *params, Cardinal *num_params);
+
+/* to safely pop down the pullright, this callback is added to its parent menu */
+static XtActionsRec menu_actions[] = {
+ { "popdown-submenus", ActPopdownSubmenus }
+};
+
+static XtAccelerators menu_accels;
+
+struct pullright_position_info {
+ Position y;
+ Dimension w;
+ Dimension h;
+ Dimension border_width;
+ Widget menu;
+};
+
+
+#ifdef NEW_MENU_CREATION
+/*
+ * Set all pixmaps indicating the state of the wigdet pointed to by `elems'.
+ */
+void
+xaw_set_button_state(struct button_elems *elems, Boolean on)
+{
+ static Arg args[] = {
+ { XtNleftBitmap, (XtArgVal)0 },
+ { XtNrightBitmap, (XtArgVal)0 }
+ };
+
+ if (elems->type == BT_CHECK)
+ args[0].value = on ? menu_check_on_bitmap : menu_check_off_bitmap;
+ else if (elems->type == BT_RADIO)
+ args[0].value = on ? menu_radio_on_bitmap : menu_radio_off_bitmap;
+ if (elems->submenu != NULL)
+ args[1].value = menu_arrow_bitmap;
+
+ XtSetValues(elems->widget, args, XtNumber(args));
+}
+
+/*
+ * Initialize the bitmaps.
+ */
+void
+xaw_initialize_menu_bitmaps(void)
+{
+ static Boolean initialized = False;
+ if (!initialized) {
+ initialized = True;
+ menu_check_on_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_check_on_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_check_off_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_check_off_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_radio_on_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_radio_on_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_radio_off_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_radio_off_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_arrow_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_arrow_bits, MENU_ARROW_W, MENU_ARROW_H);
+ }
+}
+
+#else
+
+/* toggle `checked' symbol on xaw menu w */
+void
+toggle_tick(Boolean val, Widget w)
+{
+ static Arg args = { XtNleftBitmap, (XtArgVal) 0 };
+ if (val)
+ args.value = (XtArgVal) menu_check_bitmap;
+ else
+ args.value = None;
+ XtSetValues(w, &args, 1);
+}
+
+void
+toggle_menu(int val, XtActionProc proc)
+{
+ struct button_info *bp;
+
+ for (bp = b_head; bp != NULL; bp = bp->next) {
+ if (bp->action != NULL && bp->action->proc == proc && bp->action->param != NULL) {
+ TRACE_GUI((stderr, "found proc; param: |%s|", bp->action->param));
+ if (strcmp(bp->action->param, "toggle") == 0) {
+ if (val != 0)
+ toggle_tick(True, bp->widget);
+ else
+ toggle_tick(False, bp->widget);
+ }
+ else if (strcmp(bp->action->param, "a") == 0) {
+ if (val == shrink_to_fit())
+ toggle_tick(True, bp->widget);
+ else
+ toggle_tick(False, bp->widget);
+ }
+ else {
+ int testval = strtoul(bp->action->param, (char **)NULL, 10);
+ if (testval == val) {
+ TRACE_GUI((stderr, "enabling param |%s|", bp->action->param));
+ toggle_tick(True, bp->widget);
+ }
+ else
+ toggle_tick(False, bp->widget);
+ }
+ }
+ }
+}
+
+/* initialize `checked' symbol on xaw menu w */
+static void
+initialize_tick_marks(void)
+{
+ int use_gs;
+ if (menu_check_bitmap == None) {
+ int check_width = 9;
+ int check_height = 8;
+ unsigned char check_bits[] = {
+ 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
+ 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
+ };
+
+ menu_check_bitmap = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)check_bits, check_width, check_height);
+ }
+
+ /* initialize tickmarks for all possible actions */
+ use_gs = resource.postscript;
+#ifdef PS_GS
+ if (!resource.useGS)
+ use_gs = 0;
+#endif
+
+ toggle_menu(use_gs, Act_set_ps);
+ toggle_menu(resource.gs_alpha, Act_set_gs_alpha);
+ toggle_menu(resource.keep_flag, Act_set_keep_flag);
+ toggle_menu(resource.pixels_per_inch / mane.shrinkfactor, Act_shrink_to_dpi);
+ toggle_menu(mane.shrinkfactor, Act_set_shrink_factor);
+ toggle_menu(resource.use_tex_pages, Act_use_tex_pages);
+ toggle_menu(resource.mouse_mode, Act_switch_mode);
+}
+#endif /* NEW_MENU_CREATION */
+
+/* ================================================================================
+ ================================================================================
+*/
+
+static Widget line_widget, panel_widget;
+
+/* used for communication with the pagelist in xaw_create_pagelist */
+static int my_y_pos;
+
+/* access function: panel, height of buttons etc. */
+void
+xaw_create_pagelist(void)
+{
+ Dimension height, width;
+ int button_width = get_panel_width() - 2 * (resource.btn_side_spacing + resource.btn_border_width);
+
+ XtVaGetValues(globals.widgets.clip_widget, XtNheight, &height, NULL);
+ width = MAX(button_width, xaw_get_pagelist_size());
+ height -= resource.btn_top_spacing + resource.btn_border_width + my_y_pos;
+ xaw_create_pagelist_widgets(height, width, my_y_pos, panel_widget);
+}
+
+
+static XtCallbackRec command_call[] = {
+ {handle_command, NULL},
+ {NULL, NULL},
+};
+
+#ifdef NEW_MENU_CREATION
+void xaw_create_menu(struct button_info *items, Widget parent, int menu_depth, int *ret_width)
+{
+
+}
+
+Widget
+xaw_create_menu_widgets(Widget parent)
+{
+ /* hack to disable the magnifier in the panel: */
+ XtTranslations panel_translations = XtParseTranslationTable("#augment <ButtonPress>:");
+
+ line_widget = XtVaCreateWidget("line", widgetClass, parent,
+ XtNbackground, (XtArgVal)resource.fore_Pixel,
+ XtNwidth, (XtArgVal)1,
+ XtNfromHoriz, (XtArgVal)globals.widgets.vport_widget,
+ XtNborderWidth, (XtArgVal)0,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ panel_widget = XtVaCreateWidget("panel", compositeWidgetClass, parent,
+ XtNborderWidth, (XtArgVal)0,
+ XtNfromHoriz, (XtArgVal)line_widget,
+ XtNtranslations, (XtArgVal)panel_translations,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ return panel_widget;
+}
+
+#else /* NEW_MENU_CREATION */
+
+
+static void
+filehist_select_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ char *label, *ptr;
+ int idx;
+
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XtNlabel, &label, NULL);
+
+ idx = strtol(label, &ptr, 10) - 1;
+ while (isspace(*ptr))
+ ptr++;
+ TRACE_GUI((stderr, "User selected: %d, `%s'", idx, ptr));
+ if (idx == 0) {
+ globals.ev.flags |= EV_RELOAD;
+ return;
+ }
+ file_history_open(ptr);
+}
+
+static void
+update_menu_labels(Widget menu)
+{
+ WidgetList children;
+ int num_children;
+ int i;
+
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len;
+
+ XtVaGetValues(menu,
+ XtNnumChildren, &num_children,
+ XtNchildren, &children,
+ NULL);
+ for (i = 0; i < (int)file_history_size(); i++) {
+ int dummy_page;
+ char *filename;
+
+ if ((filename = file_history_get_elem(i, &dummy_page)) == NULL) {
+ XDVI_ERROR((stderr, "Error accessing element %d of file history", i));
+ continue;
+ }
+
+ new_len = LENGTH_OF_INT + strlen(filename) + 1;
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ sprintf(buf, "%d %s", i + 1, filename);
+ XtVaSetValues(children[i], XtNlabel, buf, NULL);
+ TRACE_GUI((stderr, "child %d: `%s'", i, buf));
+ }
+
+ /* if history size < number of menu entries, destroy excess menu entries */
+ for (; i < num_children; i++) {
+ XtDestroyWidget(children[i]);
+ }
+}
+
+void
+filehist_menu_add_entry(const char *filename)
+{
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ Widget menu;
+ /* Don't report an error here, since "filehist_pullright" is only created on-demand
+ when user clicks on menu, but this may be called before from the event loop.
+ (The menu will still contain this entry when it's created later.) */
+ if (get_widget_by_name(&menu, globals.widgets.top_level, "filehist_pullright", False)) {
+ int num_children;
+ Widget w;
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ XtVaGetValues(menu, XtNnumChildren, &num_children, NULL);
+ sprintf(buf, "%d %s", num_children + 1, filename);
+
+ w = XtVaCreateManagedWidget("_filehist", smeBSBObjectClass, menu,
+ XtNlabel, buf,
+ XtNleftMargin, 10,
+ NULL);
+ XtAddCallback(w, XtNcallback, filehist_select_cb, NULL);
+ update_menu_labels(menu);
+ }
+}
+
+void
+filehist_menu_refresh(void)
+{
+ Widget menu;
+
+ /* Don't report an error here, since "filehist_pullright" is only created on-demand
+ when user clicks on menu, but this may be called before from the event loop.
+ (The menu will still contain this entry when it's created later.) */
+ if (get_widget_by_name(&menu, globals.widgets.top_level, "filehist_pullright", False)) {
+ update_menu_labels(menu);
+ }
+}
+
+
+static void
+filehist_insert_submenu(int idx, const char *filename, int pageno, void *data)
+{
+ Widget menu = (Widget)data;
+ Widget w;
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ UNUSED(pageno);
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ sprintf(buf, "%d %s", idx + 1, filename);
+ TRACE_GUI((stderr, "Creating menu `%s'", buf));
+ w = XtVaCreateManagedWidget("_filehist", smeBSBObjectClass, menu,
+ XtNlabel, buf,
+ XtNleftMargin, 10,
+ NULL);
+ XtAddCallback(w, XtNcallback, filehist_select_cb, NULL);
+}
+
+
+/*
+ ============================================================
+ Hack for pullright menus part II: callbacks and functions
+ ============================================================
+*/
+
+/* callback to pop down the currently active pullright */
+static void
+ActPopdownSubmenus(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (m_timeout != 0)
+ XtRemoveTimeOut(m_timeout);
+ m_timeout = 0;
+ if (m_active_submenu != NULL)
+ XtPopdown(m_active_submenu);
+}
+/* create a parent shell for the pullright menu entries */
+static Widget
+create_files_submenu(void)
+{
+ Widget popup = XtCreatePopupShell("filehist_pullright", simpleMenuWidgetClass, globals.widgets.top_level,
+ NULL, 0);
+ file_history_enumerate(filehist_insert_submenu, popup);
+ return popup;
+}
+
+/* Acutally pop up the pullright menu */
+static void
+popup_pullright(XtPointer client_data, XtIntervalId *id)
+{
+ int pos_x, pos_y;
+ Dimension w1;
+ Window dummy;
+ static Widget files_submenu = NULL;
+ struct pullright_position_info *info = (struct pullright_position_info *)client_data;
+
+ UNUSED(id);
+
+ if (files_submenu == NULL)
+ files_submenu = create_files_submenu();
+ /* XtManageChild(files_submenu); */
+ XTranslateCoordinates(DISP, XtWindow(XtParent(m_submenu)), RootWindowOfScreen(SCRN),
+ info->w, info->y, &pos_x, &pos_y, &dummy);
+ XtRealizeWidget(files_submenu);
+ XtVaGetValues(files_submenu, XtNwidth, &w1, NULL);
+ TRACE_GUI((stderr, "Popping up at %d, %d, %d, %d", pos_x, pos_y, w1, WidthOfScreen(SCRN)));
+
+ /* if not sufficient place on the right, pop it up on the left */
+ /* fprintf(stderr, "border_width: %d\n", info->border_width); */
+ if (pos_x + w1 > WidthOfScreen(SCRN)) {
+ /* fprintf(stderr, "%d > %d!\n", pos_x + w1, WidthOfScreen(SCRN)); */
+ pos_x -= (w1 + info->w + 3 * info->border_width);
+ /* fprintf(stderr, "new x: %d\n", pos_x); */
+ }
+ else {
+ pos_x += info->border_width;
+ }
+ XtVaSetValues(files_submenu,
+ XtNx, pos_x,
+ XtNy, pos_y,
+ NULL);
+ /* use XtPopupSpringLoaded() instead of XtPopup() since it does a few things
+ that make the pullright behave like a proper menu, like highlighting the
+ current selection, setting the cursor shape etc. */
+ XtPopupSpringLoaded(files_submenu);
+ m_active_submenu = files_submenu;
+}
+
+/*
+ * This event handler (to be called by read_events(), the main event handling loop)
+ * creates a timeout for the pullright to pop up.
+*/
+void
+SubMenuHandleEvent(XtAppContext app, XEvent *event)
+{
+ static int flag = 0;
+ static struct pullright_position_info info = { -1, 0, 0, 0, NULL };
+
+ UNUSED(app);
+
+ if (m_submenu == NULL)
+ return;
+
+ if (event->type == EnterNotify
+ || event->type == MotionNotify
+ || event->type == LeaveNotify
+ || event->type == ButtonPress) {
+
+/* fprintf(stderr, "SubMenuHandleEvent: 0x%lx, 0x%lx\n", event->xany.window, XtWindow(m_submenu)); */
+
+ /* Could also loop through a list of windows here ...
+ We need to check for the parent of the menu item, since smeBSBObject is not
+ a real window, and then manually check whether the pointer is inside the menu
+ item.
+ */
+ if (XtParent(m_submenu) != NULL &&
+ event->xany.window == XtWindow(XtParent(m_submenu))) {
+ /* don't need to check for x coordinates since we already
+ know that pointer is inside the parent */
+ if (info.y == -1) { /* initialize info */
+ XtVaGetValues(m_submenu,
+ XtNy, &(info.y),
+ XtNwidth, &(info.w),
+ XtNheight, &(info.h),
+ NULL);
+ XtVaGetValues(XtParent(m_submenu),
+ XtNborderWidth, &(info.border_width),
+ NULL);
+
+ info.menu = m_submenu;
+ }
+ if (info.y < event->xbutton.y && info.y + info.h > event->xbutton.y) {
+ if (flag == 0) {
+ /* Create a timeout of 200ms to pop up the menu, so that it doesn't
+ pop up always when the cursor is only moved over the pulldown menu.
+ I think this is about the same delay as the one used by Motif.
+ */
+ flag = 1;
+ TRACE_GUI((stderr, "ENTER: %d, %d, %d; %d, %d",
+ info.y, info.w, info.h, event->xbutton.x, event->xbutton.y));
+ m_timeout = XtAppAddTimeOut(app, 200, popup_pullright, &info);
+ return;
+ }
+ }
+ else if (flag == 1) {
+ flag = 0;
+ TRACE_GUI((stderr, "LEAVE!"));
+ if (m_timeout != 0)
+ XtRemoveTimeOut(m_timeout);
+ m_timeout = 0;
+ if (m_active_submenu != NULL)
+ XtPopdown(m_active_submenu);
+ m_active_submenu = NULL;
+ }
+ }
+ }
+}
+
+static Widget
+create_pulldown_entry(const char *menu_name,
+ Widget parent,
+ const char *item_name,
+ const char *accelerator, /* accelerator, or NULL */
+ struct xdvi_action *action,
+ buttonTypeT *type)
+{
+ Widget w;
+ char buf[1024];
+ char *m_name = xstrdup(menu_name);
+ m_name = xstrcat(m_name, item_name);
+
+#ifdef SHOW_ACCELERATORS
+ if (accelerator != NULL && *accelerator != '\0')
+ SNPRINTF(buf, 1024, "%s [%s]", item_name, accelerator);
+ else
+ strncpy(buf, item_name, 1024);
+#else
+ UNUSED(accelerator);
+ strncpy(buf, item_name, 1024);
+#endif
+
+/* fprintf(stderr, "creating pulldown for parent %p: `%s', `%s'\n", */
+/* (void *)parent, menu_name, item_name); */
+
+ if (strcmp(item_name, "SEP") == 0) { /* it's a separator */
+ *type = MENU_SEPARATOR;
+ w = XtCreateManagedWidget(m_name, smeLineObjectClass, parent, NULL, 0);
+ }
+ else if (action->proc != NULL && action->proc == Act_recent_files) { /* special case: submenu with recent files */
+/* w = recent_files_submenu(m_name, parent, buf); */
+/* *type = MENU_ENTRY; */
+ w = XtVaCreateManagedWidget(m_name, smeBSBObjectClass, parent,
+ XtNlabel, buf,
+ XtNleftMargin, 20,
+ XtNrightMargin, 16,
+ XtNrightBitmap, menu_arrow_bitmap,
+ NULL);
+ m_submenu = w;
+ /* fprintf(stderr, "setting translations for %p\n", (void *)XtParent(parent)); */
+ XtOverrideTranslations(parent, menu_accels);
+ /* XtOverrideTranslations(XtParent(parent), menu_accels); */
+
+ *type = MENU_ENTRY;
+ }
+ else { /* normal menu item */
+ w = XtVaCreateManagedWidget(m_name, smeBSBObjectClass, parent,
+ XtNlabel, buf,
+ XtNleftMargin, 20,
+ NULL);
+ *type = MENU_ENTRY;
+ XtAddCallback(w, XtNcallback, handle_command, action);
+ }
+ free(m_name);
+ return w;
+}
+
+static Widget
+create_pulldown_menu(const char *menu_name,
+ Dimension *width,
+ int *index,
+ Dimension *y_pos,
+ buttonTypeT *type,
+ int *menu_number)
+{
+ int i;
+
+ /* check whether a pulldown menu with this name already exists,
+ and if yes, return its position in index: */
+ for (i = 0; i < *menu_number; i++) {
+ if (menu_list[i].name != NULL && (strcmp(menu_list[i].name, menu_name)) == 0) {
+ *index = i;
+ break;
+ }
+ }
+ if (i == *menu_number) { /* doesn't exist, create one */
+ Dimension w, h;
+ Widget n_button_widget, n_popup_widget;
+ char *button_widget_name = NULL;
+
+ (*menu_number)++;
+ if (*menu_number > MAX_MENU_NUM) {
+ XDVI_WARNING((stderr, "Too many menus (max=%d), skipping all from \"%s\"",
+ MAX_MENU_NUM, menu_name));
+ *type = INVALID;
+ return 0;
+ }
+
+ /* save menu_name to list for later comparison */
+ menu_list[i].name = xrealloc(menu_list[i].name, strlen(menu_name) + 1);
+ strcpy(menu_list[i].name, menu_name);
+
+ button_widget_name = xstrdup(menu_name);
+ button_widget_name = xstrcat(button_widget_name, "B"); /* make it unique */
+
+ if (globals.debug & DBG_ALL) {
+ fprintf(stderr, "ypos: %d; h: %d; between: %d; border: %d\n",
+ *y_pos,
+ h,
+ resource.btn_between_spacing,
+ resource.btn_border_width);
+ }
+
+ n_button_widget = XtVaCreateWidget(menu_list[i].name, menuButtonWidgetClass, panel_widget,
+ XtNmenuName, button_widget_name,
+ XtNx, resource.btn_side_spacing,
+ XtNy, *y_pos,
+ XtNborderWidth, resource.btn_border_width,
+ NULL);
+ n_popup_widget = XtVaCreatePopupShell(button_widget_name, simpleMenuWidgetClass, n_button_widget,
+ NULL);
+ /* Mustn't free this one?? */
+/* free(button_widget_name); */
+ menu_list[i].button_widget = n_button_widget;
+ menu_list[i].popup_widget = n_popup_widget;
+ XtVaGetValues(n_button_widget, XtNwidth, &w, XtNheight, &h, NULL);
+ *width = w;
+ *index = i;
+ *y_pos += h + resource.btn_between_spacing + 2 * resource.btn_border_width;
+ *type = MENU_BUTTON;
+ return n_button_widget;
+ }
+ *type = NONE;
+ return 0;
+}
+
+static struct button_info *
+create_button_info(const char *label, struct xdvi_action *action, Widget w, buttonTypeT type)
+{
+ struct button_info *info = xmalloc(sizeof *info);
+ info->label = xstrdup(label);
+ info->action = action;
+ info->widget = w;
+ info->type = type;
+ return info;
+}
+
+typedef enum shrinkArgT_ { NO_SHRINK_ARG, HASH, PERCENT, UNDERSCORE } shrinkArgT;
+
+static shrinkArgT
+test_for_shrink_arg(const char *item, int *idx)
+{
+ const char *ptr = item;
+ size_t i;
+ for (i = 0; ptr[i] != '\0'; i++) {
+ if (ptr[i] == '$') {
+ i++;
+ if (ptr[i] == '#') {
+ *idx = i;
+ return HASH;
+ }
+ else if (ptr[i] == '%') {
+ *idx = i;
+ return PERCENT;
+ }
+ else if (ptr[i] == '_') {
+ *idx = i;
+ return UNDERSCORE;
+ }
+ }
+ }
+ *idx = 0;
+ return NO_SHRINK_ARG;
+}
+
+static Boolean
+create_shrink_button(char **label, int offset, shrinkArgT type, struct xdvi_action *action)
+{
+ int shrink_arg = 0;
+#define TEMPSTR_LEN 128 /* enough for printing a number into */
+ char tempstr[TEMPSTR_LEN];
+ char *new_label = NULL;
+
+ for (;; action = action->next) {
+ if (action == NULL) {
+ return False;
+ }
+ if (action->proc == Act_set_shrink_factor || action->proc == Act_shrink_to_dpi) {
+ /* NOTE: the shrinkbutton[] resource isn't implemented. It probably makes
+ less sense with the pulldown menu resources??
+ */
+ if (action->num_params > 0) {
+ shrink_arg = atoi(action->param);
+ if (action->proc == Act_shrink_to_dpi)
+ shrink_arg = (double)resource.pixels_per_inch / shrink_arg + 0.5;
+ if (shrink_arg < 1)
+ shrink_arg = 1;
+ else if (shrink_arg > 99)
+ shrink_arg = 99;
+ }
+ break; /* found shrink action */
+ }
+ }
+
+ if (type == HASH)
+ SNPRINTF(tempstr, TEMPSTR_LEN, "%d", shrink_arg);
+ else if (type == PERCENT) {
+ if (shrink_arg <= 15)
+ SNPRINTF(tempstr, TEMPSTR_LEN, "%d", (int)(100.0 / shrink_arg + .5));
+ else
+ SNPRINTF(tempstr, TEMPSTR_LEN, "%.2f", 100.0 / shrink_arg);
+ }
+ /* NOTE: I think UNDERSCORE is related to the shrinkbutton[] resource,
+ which is not implemented */
+
+ /* return resized label */
+ new_label = xmalloc(offset - 1 + strlen(tempstr) + strlen(*label + offset + 1) + 1);
+ memcpy(new_label, *label, offset - 1);
+ strcpy(new_label + offset - 1, tempstr); /* now it's null-terminated */
+ strcat(new_label, *label + offset + 1);
+ free(*label);
+ *label = new_label;
+
+#undef TEMPSTR_LEN
+ return True;
+}
+
+static Dimension
+create_button(int button_number, /* number of this button */
+ int *menu_num, /* number of submenus in this button */
+ char **items, /* description of label and action strings */
+ size_t item_count, /* number of items in description */
+ Widget parent, /* parent of widget to create */
+ struct button_info ***bipp, /* button info to insert new button into */
+ Dimension *y_pos, /* vertical position after creating button */
+ const char *c_ptr, /* entire rest of resource string, for error messages */
+ size_t len) /* length of current line in resource string, for error messages*/
+{
+ int menu_idx = -1, label_idx = -1, accelerator_idx = -1, action_idx = -1;
+#define NAME_LEN 16
+ char name[NAME_LEN];
+ struct button_info *bp;
+ shrinkArgT shrink_arg_type;
+ struct xdvi_action *action;
+ Widget widget;
+ buttonTypeT b_type;
+/* static int menu_num = 0; /\* count number of created menus *\/ */
+ Dimension width = 0;
+
+ ASSERT(item_count >= 2, "Too few items");
+
+ if (item_count == 4) { /* submenu for a button */
+ menu_idx = 0;
+ label_idx = 1;
+ accelerator_idx = 2;
+ action_idx = 3;
+ }
+ else if (item_count == 3) { /* command button */
+ label_idx = 0;
+ accelerator_idx = 1;
+ action_idx = 2;
+ }
+ else { /* separator */
+ if (strcmp(items[1], "SEP") == 0) { /* separator */
+ menu_idx = 0;
+ label_idx = 1;
+ }
+ else {
+ XDVI_WARNING((stderr, "Wrong number of items (%d) in translations line:\n\"%.*s\" (skipping this line).",
+ item_count, (int)len, c_ptr));
+ return 0;
+ }
+ }
+
+ if (action_idx != -1) {
+ int offset;
+ shrink_arg_type = test_for_shrink_arg(items[label_idx], &offset);
+
+/* fprintf(stderr, "compiling action: |%s|\n", items[action_idx]); */
+ if ((action = compile_action(items[action_idx])) == NULL) {
+ XDVI_WARNING((stderr, "Invalid action \"%s\" in translations line:\n\"%.*s\" (skipping this line).",
+ items[action_idx], (int)len, c_ptr));
+ return 0;
+ }
+
+ if (shrink_arg_type != NO_SHRINK_ARG) { /* search for corresponding shrink action */
+ if (!create_shrink_button(&(items[label_idx]), offset, shrink_arg_type, action)) {
+ XDVI_WARNING((stderr, "Non-existent shrink action \"%s\" in translations line:\n\"%.*s\"",
+ items[action_idx], (int)len, c_ptr));
+ return 0;
+ }
+ }
+ }
+ else {
+ action = NULL;
+ }
+
+ command_call[0].closure = (XtPointer) action;
+ SNPRINTF(name, NAME_LEN, "button%d", button_number);
+
+ if (menu_idx != -1) { /* it's a pulldown menu */
+ int index;
+
+ /* create a new pulldown menu if it doesn't exist yet */
+ widget = create_pulldown_menu(items[menu_idx], &width, &index, y_pos, &b_type, menu_num);
+ if (b_type == INVALID)
+ return 0;
+ if (b_type != NONE) { /* it didn't exist yet */
+ bp = create_button_info(items[label_idx], NULL, widget, b_type);
+ **bipp = bp;
+ *bipp = &bp->next;
+ }
+
+ /* create an entry for this item */
+ widget = create_pulldown_entry(menu_list[index].name,
+ menu_list[index].popup_widget,
+ items[label_idx],
+ accelerator_idx > 0 ? items[accelerator_idx] : NULL,
+ action,
+ &b_type);
+ bp = create_button_info(items[label_idx], action, widget, b_type);
+ **bipp = bp;
+ *bipp = &bp->next;
+ }
+ else { /* not a pulldown menu, but a simple command button */
+ command_call[0].closure = (XtPointer) action;
+ widget = XtVaCreateWidget(name, commandWidgetClass, parent,
+ XtNlabel, (XtArgVal)items[label_idx],
+ XtNx, resource.btn_side_spacing,
+ XtNy, (XtArgVal)*y_pos,
+ XtNborderWidth, resource.btn_border_width,
+ XtNcallback, (XtArgVal)command_call,
+ NULL);
+ bp = create_button_info(items[label_idx], action, widget, COMMAND_BUTTON);
+ **bipp = bp;
+ *bipp = &bp->next;
+ }
+#undef NAME_LEN
+ return width;
+}
+
+void
+scroll_x_panner(int x)
+{
+ static int old_x = 0;
+ if (panner != 0 && ABS(x - old_x) > 8) {
+ XtVaSetValues(panner, XtNsliderX, x, NULL);
+ old_x = x;
+ }
+}
+
+void
+scroll_y_panner(int y)
+{
+ static int old_y = 0;
+ if (panner != 0 && ABS(y - old_y) > 8) {
+ XtVaSetValues(panner, XtNsliderY, y, NULL);
+ old_y = y;
+ }
+}
+
+#ifdef USE_PANNER
+static void
+panner_cb(Widget widget, XtPointer closure, XtPointer report_ptr)
+{
+ XawPannerReport *report = (XawPannerReport *)report_ptr;
+ static int orig_x = 0, orig_y = 0;
+ int x = report->slider_x;
+ int y = report->slider_y;
+ static Dimension w, h;
+ static Arg arg_wh_clip[] = {
+ {XtNwidth, (XtArgVal) &w},
+ {XtNheight, (XtArgVal) &h},
+ };
+
+ UNUSED(closure);
+
+ XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
+
+ fprintf(stderr, "w: %d, h: %d, globals.page.w: %d, globals.page.h: %d\n",
+ w, h, globals.page.w, globals.page.h);
+ XtVaSetValues(widget,
+ XtNsliderWidth, w, XtNsliderHeight, h,
+ XtNcanvasWidth, globals.page.w, XtNcanvasHeight, globals.page.h,
+ NULL);
+
+ fprintf(stderr, "panner moved: %d, %d\n", report->slider_x, report->slider_y);
+ if (globals.widgets.x_bar != NULL)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)(x - orig_x));
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer)(y - orig_y));
+ orig_x = x;
+ orig_y = y;
+}
+#endif /* USE_PANNER */
+
+void
+create_menu_buttons(Widget form, int *ret_panel_width)
+{
+ Dimension max_button_width = 0, curr_width;
+ Dimension y_pos;
+ struct button_info **bipp;
+ struct button_info *bp;
+ const char *c_ptr, *e_ptr;
+ int max_size;
+ int button_number = 0;
+ int menu_number = 0; /* number of menus created; passed through to create_pulldown_menu */
+
+ /* disable the magnifier in the panel: */
+ XtTranslations panel_translations = XtParseTranslationTable("#augment <ButtonPress>:");
+
+ XtAppAddActions(XtWidgetToApplicationContext(form), menu_actions, XtNumber(menu_actions));
+ /* add our own popdown-submenus() action to the default translations of this menu */
+ menu_accels = XtParseAcceleratorTable("<BtnUp>:MenuPopdown()notify()unhighlight()popdown-submenus()");
+
+ line_widget = XtVaCreateWidget("line", widgetClass, form,
+ XtNbackground, (XtArgVal)resource.fore_Pixel,
+ XtNwidth, (XtArgVal) 1,
+ XtNfromHoriz, (XtArgVal)globals.widgets.vport_widget,
+ XtNborderWidth, (XtArgVal)0,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ panel_widget = XtVaCreateWidget("panel", compositeWidgetClass, form,
+ XtNborderWidth, (XtArgVal)0,
+ XtNfromHoriz, (XtArgVal)line_widget,
+ XtNtranslations, (XtArgVal)panel_translations,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ menu_arrow_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_arrow_bits, MENU_ARROW_W, MENU_ARROW_H);
+
+ b_head = NULL;
+ bipp = &b_head;
+
+ *ret_panel_width = 0;
+ y_pos = resource.btn_top_spacing;
+
+#define FREE_LINE_ITEMS do { \
+ for (curr = 0; curr < item_count; curr++) { \
+ free(line_items[curr]); \
+ } \
+ free(line_items); \
+ } while (0)
+
+ for (c_ptr = resource.menu_translations;
+ c_ptr != NULL && *c_ptr != '\0';
+ c_ptr = e_ptr + 1) {
+ e_ptr = strchr(c_ptr, '\n');
+ if (e_ptr != NULL) {
+ char **line_items = NULL;
+ size_t len, curr, item_count = 0;
+
+ if (e_ptr == c_ptr) { /* single '\n' marks additional space between buttons */
+ y_pos += resource.btn_between_extra;
+ continue;
+ }
+ len = e_ptr - c_ptr;
+
+ if (++button_number > MAX_BUTTON_NUM) {
+ XDVI_WARNING((stderr, "Too many buttons (max=%d), skipping all from:\n\"%.*s\"",
+ MAX_BUTTON_NUM, (int)len, c_ptr));
+ break;
+ }
+
+ line_items = split_line(c_ptr, SEP_CHAR, 0, len, &item_count);
+ if (item_count < 3 && !(item_count > 1 && strcmp(line_items[1], "SEP") == 0)) {
+ XDVI_WARNING((stderr, "Too few separators \"%c\" in translations line:\n\"%.*s\" (skipping this line).\n",
+ SEP_CHAR, (int)len, c_ptr));
+ FREE_LINE_ITEMS;
+ continue;
+ }
+ curr_width = create_button(button_number,
+ &menu_number,
+ line_items,
+ item_count,
+ panel_widget,
+ &bipp,
+ &y_pos,
+ c_ptr, len);
+ if (curr_width == 0) { /* no button created */
+ FREE_LINE_ITEMS;
+ continue;
+ }
+ /* adjust max_button_width to this new entry */
+ if (curr_width > max_button_width)
+ max_button_width = curr_width;
+
+ FREE_LINE_ITEMS;
+ }
+ }
+
+#undef FREE_LINE_ITEMS
+
+ /* null-terminate button info */
+ *bipp = NULL;
+
+ max_size = xaw_get_pagelist_size();
+ if (max_size > max_button_width) {
+ max_button_width = max_size;
+ }
+
+ *ret_panel_width = max_button_width + 2 * (resource.btn_side_spacing + resource.btn_border_width);
+ TRACE_GUI((stderr, "panel_widget: w: %d", *ret_panel_width));
+ XtVaSetValues(panel_widget, XtNwidth, (XtArgVal)*ret_panel_width, NULL);
+ ++(*ret_panel_width);
+ my_panel_width = *ret_panel_width; /* make it available */
+
+ for (bp = b_head; bp != NULL; bp = bp->next) {
+ if (bp->type == MENU_BUTTON || bp->type == COMMAND_BUTTON) {
+ TRACE_GUI((stderr, "bp->widget: w: %d", max_button_width));
+ XtVaSetValues(bp->widget, XtNwidth, (XtArgVal)max_button_width, NULL);
+ XtManageChild(bp->widget);
+ }
+ }
+
+ my_y_pos = y_pos - resource.btn_between_spacing + resource.btn_top_spacing + 2 * resource.btn_border_width;
+ initialize_tick_marks();
+#ifdef USE_PANNER
+ {
+ static Dimension w, h;
+ static Arg arg_wh_clip[] = {
+ {XtNwidth, (XtArgVal) &w},
+ {XtNheight, (XtArgVal) &h},
+ };
+ XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
+
+ fprintf(stderr, "w: %d, h: %d, globals.page.w: %d, globals.page.h: %d\n",
+ w, h, globals.page.w, globals.page.h);
+ if (w == 0)
+ w = globals.page.w - 2;
+ if (h == 0)
+ h = globals.page.h - 2;
+ panner = XtVaCreateManagedWidget("panner", pannerWidgetClass, panel_widget,
+ XtNx, resource.btn_side_spacing,
+ XtNy, my_y_pos,
+ XtNheight, 60,
+ XtNwidth, max_button_width,
+ XtNshadowThickness, 0,
+ XtNsliderWidth, w,
+ XtNsliderHeight, h,
+ XtNcanvasWidth, globals.page.w,
+ XtNcanvasHeight, globals.page.h,
+ XtNsliderX, 5,
+ XtNsliderY, 7,
+ XtNinternalSpace, 0,
+ NULL);
+ }
+ my_y_pos += 60 + resource.btn_top_spacing + 2 * resource.btn_border_width;
+ XtAddCallback(panner, XtNreportCallback, panner_cb, (XtPointer)NULL);
+
+#endif /* USE_PANNER */
+
+}
+#endif /* NEW_MENU_CREATION */
+
+
+void
+set_button_panel_height(XtArgVal h)
+{
+ TRACE_GUI((stderr, "line_widget: h %d", (int)h));
+ XtVaSetValues(line_widget, XtNheight, h, NULL);
+ XtManageChild(line_widget);
+
+ XtVaSetValues(panel_widget, XtNheight, h, NULL);
+ XtManageChild(panel_widget);
+}
+
+/****************************************************************************
+ * Action handling code.
+ */
+
+
+static void
+handle_destroy_buttons(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ int panel_width;
+ Dimension window_w, window_h;
+
+ UNUSED(widget);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (--destroy_count != 0) {
+ return;
+ }
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
+ XtVaGetValues(globals.widgets.form_widget,
+ XtNwidth, &window_w,
+ XtNheight, &window_h,
+ NULL);
+
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
+ /* destroy buttons */
+ TRACE_GUI((stderr, "globals.widgets.vport_widget: h %d, w %d", window_w, window_h));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
+ }
+ else {
+ create_menu_buttons(globals.widgets.form_widget, &panel_width);
+ window_w -= panel_width;
+ TRACE_GUI((stderr, "globals.widgets.vport_widget: h %d, w %d", window_h, window_w));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
+ set_button_panel_height((XtArgVal) window_h);
+ }
+}
+
+
+static void
+reconfig_window(void) {
+ Dimension x_top, y_top, h_top, w_top;
+ XWindowChanges sizeconfigure;
+ int sizeconfiguremask;
+
+ /* brute-force method to bring the scrollbars back. Apparently a single XConfigureWindow()
+ isn't enough to get the scrollbars back, we actually need to move the window a bit,
+ and then move it back. */
+ sizeconfiguremask = CWWidth | CWHeight;
+ XtVaGetValues(globals.widgets.top_level, XtNx, &x_top, XtNy, &y_top, XtNheight, &h_top, XtNwidth, &w_top, NULL);
+ sizeconfigure.width = w_top + 1;
+ sizeconfigure.height = h_top + 1;
+ XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure);
+ sizeconfigure.width = w_top;
+ sizeconfigure.height = h_top;
+ XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure);
+}
+
+/* toggle scrollbars to state `visible' */
+void
+toggle_scrollbars(void)
+{
+ Widget v_bar = XtNameToWidget(globals.widgets.vport_widget, "vertical");
+ Widget h_bar = XtNameToWidget(globals.widgets.vport_widget, "horizontal");
+ static Dimension bar_thick;
+ static Boolean v_bar_mapped = False, h_bar_mapped = False;
+ static Boolean initialized = False;
+
+ Boolean make_v_bar_visible = False;
+ Boolean make_v_bar_invisible = False;
+
+ Boolean make_h_bar_visible = False;
+ Boolean make_h_bar_invisible = False;
+
+ if (v_bar != 0) {
+ int test_v = 0;
+ XtVaGetValues(v_bar, XtNwidth, &test_v, NULL);
+ if (test_v > 1)
+ v_bar_mapped = True;
+ }
+ if (h_bar != 0) {
+ int test_h = 0;
+ XtVaGetValues(h_bar, XtNheight, &test_h, NULL);
+ if (test_h > 1)
+ h_bar_mapped = True;
+ }
+
+ if (!initialized) {
+ v_bar_mapped = h_bar_mapped = (resource.expert_mode & XPRT_SHOW_SCROLLBARS) != 0;
+ initialized = True;
+ if (v_bar != 0)
+ XtVaGetValues(v_bar, XtNwidth, &bar_thick, NULL);
+ else if (h_bar != 0)
+ XtVaGetValues(h_bar, XtNheight, &bar_thick, NULL);
+ else
+ bar_thick = 15; /* FIXME */
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) == 0) {
+ if (v_bar_mapped)
+ make_v_bar_invisible = True;
+ if (h_bar_mapped)
+ make_h_bar_invisible = True;
+ }
+ else {
+ if (!v_bar_mapped)
+ make_v_bar_visible = True;
+ if (!h_bar_mapped)
+ make_h_bar_visible = True;
+ }
+
+ if (make_h_bar_visible || make_v_bar_visible) {
+ if (make_h_bar_visible && h_bar != 0) {
+ TRACE_GUI((stderr, "h_bar: h %d", bar_thick));
+ XtVaSetValues(h_bar, XtNheight, bar_thick, XtNx, bar_thick, XtNy, 0, XtNborderWidth, 1, NULL);
+ XtManageChild(h_bar);
+ h_bar_mapped = True;
+ }
+ if (make_v_bar_visible && v_bar != 0) {
+ TRACE_GUI((stderr, "v_bar: w %d", bar_thick));
+ XtVaSetValues(v_bar, XtNwidth, bar_thick, XtNx, 0, XtNy, bar_thick, XtNborderWidth, 1, NULL);
+ XtManageChild(v_bar);
+ v_bar_mapped = True;
+ }
+ if (h_bar != 0 || v_bar != 0) { /* need to reconfigure screen */
+ reconfig_window();
+ }
+ }
+ else if (make_h_bar_invisible || make_v_bar_invisible) {
+ if (make_h_bar_invisible && h_bar != 0) {
+ XtUnmanageChild(h_bar);
+ XtVaSetValues(h_bar, XtNheight, 1, XtNx, 0, XtNy, 0, XtNborderWidth, 0, NULL);
+ h_bar_mapped = False;
+ }
+ if (make_v_bar_invisible && v_bar != 0) {
+ XtUnmanageChild(v_bar);
+ XtVaSetValues(v_bar, XtNwidth, 1, XtNy, 0, XtNy, 0, XtNborderWidth, 0, NULL);
+ v_bar_mapped = False;
+ }
+ if (h_bar != 0 || v_bar != 0) { /* need to reconfigure screen */
+ reconfig_window();
+ }
+ }
+
+}
+
+void
+toggle_buttons(void)
+{
+ static Boolean buttons_active = False;
+ static Boolean initialized = False;
+ Dimension window_w, window_h;
+
+
+ Boolean make_buttons_visible = False;
+ Boolean make_buttons_invisible = False;
+
+ int panel_width;
+
+ if (!initialized) {
+ buttons_active = (resource.expert_mode & XPRT_SHOW_BUTTONS) != 0;
+ initialized = True;
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
+ if (buttons_active)
+ make_buttons_invisible = True;
+ }
+ else {
+ if (!buttons_active)
+ make_buttons_visible = True;
+ }
+
+ if (make_buttons_visible) {
+ if (destroy_count != 0) {
+ return;
+ }
+
+ create_menu_buttons(globals.widgets.form_widget, &panel_width);
+ XtVaGetValues(globals.widgets.form_widget,
+ XtNwidth, &window_w,
+ XtNheight, &window_h,
+ NULL);
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
+ window_w -= panel_width;
+ TRACE_GUI((stderr, "globals.widgets.vport_widget: w: %d, h: %d", window_w, window_h));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
+ set_button_panel_height((XtArgVal) window_h);
+ buttons_active = True;
+ }
+ else if (make_buttons_invisible) {
+ if (destroy_count != 0) {
+ return;
+ }
+ /* this counts the callback calls; 1 for the panel, 1 for the line */
+ destroy_count = 2;
+
+ XtAddCallback(panel_widget, XtNdestroyCallback,
+ handle_destroy_buttons, (XtPointer)0);
+ XtAddCallback(panel_widget, XtNdestroyCallback,
+ handle_destroy_pagelist, (XtPointer)0);
+ XtAddCallback(line_widget, XtNdestroyCallback,
+ handle_destroy_buttons, (XtPointer)0);
+ XtDestroyWidget(panel_widget);
+ XtDestroyWidget(line_widget);
+ buttons_active = False;
+/* window_w += get_panel_width(); */
+
+ while (b_head != NULL) {
+ struct button_info *bp = b_head;
+ struct xdvi_action *action;
+
+ b_head = bp->next;
+ free(bp->label);
+ /* free bp->action */
+ for (action = bp->action; action != NULL;) {
+ struct xdvi_action *act2 = action;
+ action = act2->next;
+ if (act2->num_params > 0) {
+ free(act2->param);
+ }
+ free(act2);
+ }
+ free(bp);
+ }
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* ifndef MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xaw_menu.h b/Build/source/texk/xdvik/gui/xaw_menu.h
new file mode 100644
index 00000000000..750f79cfeb5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_menu.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef XAW_MENU_H_
+#define XAW_MENU_H_
+
+#ifdef NEW_MENU_CREATION
+#include "menu.h"
+#endif /* NEW_MENU_CREATION */
+
+#ifndef MOTIF
+
+#ifdef NEW_MENU_CREATION
+extern void xaw_set_button_state(struct button_elems *elems, Boolean on);
+extern void xaw_initialize_menu_bitmaps(void);
+extern Widget xaw_create_menu_widgets(Widget parent);
+extern void xaw_create_menu(struct button_info *items, Widget parent, int *ret_width);
+extern void xaw_set_button_state(struct button_elems *elems, Boolean on);
+
+extern Pixmap menu_check_bitmap;
+extern Pixmap menu_uncheck_bitmap;
+#else
+extern void create_menu_buttons(Widget menu_bar, int *ret_panel_width);
+extern void toggle_menu(int val, XtActionProc proc);
+#endif /* NEW_MENU_CREATION */
+
+extern void SubMenuHandleEvent(XtAppContext app, XEvent *event);
+extern void filehist_menu_add_entry(const char *filename);
+extern int get_panel_width(void);
+
+extern void toggle_tick(Boolean val, Widget w);
+extern void set_button_panel_height(XtArgVal);
+extern void filehist_menu_refresh(void);
+
+extern void xaw_create_pagelist(void);
+extern void toggle_scrollbars(void);
+extern void toggle_buttons(void);
+extern void scroll_y_panner(int y);
+extern void scroll_x_panner(int x);
+#endif /* not MOTIF */
+
+#endif /* XAW_MENU_H_ */
diff --git a/Build/source/texk/xdvik/gui/xicon.c b/Build/source/texk/xdvik/gui/xicon.c
new file mode 100644
index 00000000000..15faa32442a
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xicon.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Implement a nice and well behaved application icon.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "xicon.h"
+#include "util.h"
+#include "xdvi-debug.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+
+#ifdef MOTIF
+# include <Xm/XmStrDefs.h>
+#endif
+
+#if defined(HAVE_X11_XPM_H)
+# include <X11/xpm.h>
+#elif defined(HAVE_XPM_H)
+# include <xpm.h>
+#elif defined(HAVE_XM_XPMP_H)
+# include <Xm/XpmP.h>
+#endif
+
+#include "xdvi.icon"
+#include "pixmaps/xdvi32x32.xpm"
+#include "pixmaps/xdvi16x16.xpm"
+#include "pixmaps/xdvi48x48.xpm"
+void
+add_icon(Widget top_level,
+ String title_name,
+ String icon_name)
+{
+#if !HAVE_XPM
+
+ static Arg args[] = {
+ {XtNiconX, (XtArgVal) 0},
+ {XtNiconY, (XtArgVal) 0},
+ };
+ static Pixmap icon_pm;
+ static Arg temp_args4 = { XtNiconPixmap, (XtArgVal) &icon_pm };
+
+ UNUSED(xdvi16x16_xpm);
+ UNUSED(xdvi32x32_xpm);
+ UNUSED(xdvi48x48_xpm);
+
+ if (resource.icon_geometry != NULL) {
+ int junk;
+
+ (void)XGeometry(DISP, XScreenNumberOfScreen(SCRN),
+ resource.icon_geometry, "",
+ 0, 0, 0, 0, 0,
+ (int *)&args[0].value,
+ (int *)&args[1].value,
+ &junk,
+ &junk);
+ XtSetValues(top_level, args, XtNumber(args));
+ }
+ /* Set icon pixmap */
+ XtGetValues(top_level, &temp_args4, 1);
+ if (icon_pm == (Pixmap) 0) {
+ temp_args4.value =
+ (XtArgVal)XCreateBitmapFromData(DISP,
+ RootWindowOfScreen(SCRN),
+ (const char *)xdvi_bits,
+ xdvi_width,
+ xdvi_height);
+ XtSetValues(top_level, &temp_args4, 1);
+ }
+#else /* HAVE_XPM */
+
+ /* Use Pixmaps, looking much nicer. */
+
+ static Pixmap icon = 0;
+ static Pixmap icon_mask = 0;
+ static const char **pixmap_data = xdvi32x32_xpm;
+ XIconSize *size;
+ int number_sizes;
+ Display *dsp;
+ Screen *scr;
+ XpmAttributes attr;
+
+ UNUSED(xdvi_bits);
+ /*
+ * get the icon size preferred by the window manager
+ */
+ if (XGetIconSizes(XtDisplay(top_level), RootWindowOfScreen(SCRN),
+ &size, &number_sizes) != 0) {
+ if (number_sizes > 0) {
+ if (size->max_height >= 48 && size->max_height >= 48)
+ pixmap_data = xdvi48x48_xpm;
+ else if (size->max_height >= 32 && size->max_height >= 32)
+ pixmap_data = xdvi32x32_xpm;
+ else if (size->max_height >= 16 && size->max_height >= 16)
+ pixmap_data = xdvi16x16_xpm;
+ }
+ }
+
+ dsp = XtDisplay(top_level);
+ scr = XtScreen(top_level);
+
+ attr.valuemask = 0L;
+ attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap | XpmDepth | XpmVisual;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ /* use the same visual/colormap/depth as main window, else BadMatch ... */
+ attr.visual = G_visual;
+ attr.colormap = G_colormap;
+ attr.depth = G_depth;
+
+ if (!icon) {
+ Window rootWindow = XtWindow(globals.widgets.top_level);
+ ASSERT(rootWindow != 0, "");
+ XpmCreatePixmapFromData(dsp, rootWindow, (char **)pixmap_data,
+ &icon, &icon_mask, &attr);
+ }
+
+# ifdef MOTIF
+ XtVaSetValues(top_level, XmNiconPixmap, icon, XmNiconMask, icon_mask, NULL);
+# else
+ XtVaSetValues(top_level, XtNiconPixmap, icon, XtNiconMask, icon_mask, NULL);
+# endif
+
+ XpmFreeAttributes(&attr);
+#endif
+
+ {
+ /* code locality ... */
+ static Arg args[] = {
+ { XtNtitle, (XtArgVal) 0 },
+ { XtNiconName, (XtArgVal) 0 },
+ { XtNinput, (XtArgVal) True },
+ };
+
+ args[0].value = (XtArgVal)title_name;
+ args[1].value = (XtArgVal)icon_name;
+ XtSetValues(top_level, args, XtNumber(args));
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/xicon.h b/Build/source/texk/xdvik/gui/xicon.h
new file mode 100644
index 00000000000..47991b5b092
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xicon.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ *
+ * 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.
+ *
+ */
+
+#ifndef XICON_H_
+#define XICON_H_
+
+extern void add_icon(Widget toplevel, String title_name, String icon_name);
+
+#endif /* XICON_H_ */
diff --git a/Build/source/texk/xdvik/gui/xlwradio.c b/Build/source/texk/xdvik/gui/xlwradio.c
new file mode 100644
index 00000000000..27bb14c3eb2
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xlwradio.c
@@ -0,0 +1,677 @@
+/* adapted from xlwradio.c in the XEmacs distribution.
+ Changes are Copyright (C) 2002-2004 the xdvik development team.
+
+ Note SU: This widget doesn't work with Xaw3d, and I have little
+ inclination to make it work - the design would need to be utterly
+ different, e.g. the radio would need to be a diamond instead of a
+ circle, since 3d-shadowed circles don't look circular; colormap
+ issues would need to be settled, etc. And besides, I don't like Xaw3d ;)
+
+ So instead, the caller should just do:
+
+ myWidget = XtVaCreateManagedWidget("foo",
+ #ifdef XAW
+ radioWidgetClass,
+ #else
+ toggleWidgetClass,
+ #endif
+ ... arglist ...);
+
+ Feel free to submit patches if you want this implemented.
+
+ Original copyright follows:
+*/
+
+/* Radio Widget for XEmacs.
+ Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Synched up with: Radio.c 1.1 */
+
+/*
+ * Radio.c - Radio button widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: June 30, 1997
+ *
+ *
+ * Overview: This widget is identical to the Toggle widget in behavior,
+ * but completely different in appearance. This widget looks like a small
+ * diamond-shaped button with a label to the right.
+ *
+ * To make this work, we subclass the Toggle widget to inherit its behavior
+ * and to inherit the label-drawing function from which Toggle is
+ * subclassed. We then completely replace the Expose, Set, Unset
+ * and Highlight member functions.
+ *
+ * The Set and Unset actions are slightly unorthodox. In Toggle's
+ * ClassInit function, Toggle searches the Command actions list and
+ * "steals" the Set and Unset functions, caching pointers to them in its
+ * class record. It then calls these functions from its own ToggleSet
+ * and Toggle actions.
+ *
+ * We, in turn, override the Set() and Unset() actions in our own ClassRec.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "xdvi-debug.h"
+#include "util.h"
+#include "xaw_bitmaps.h" /* bitmaps for radio/checkbuttons */
+
+#include "xlwradioP.h"
+
+#ifndef MOTIF /* entire file */
+
+#include <stdio.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+/* #include "../src/xmu.h" */
+
+#define BOX_SIZE 16
+#define PIXMAP_OFFSET 2 /* additional space between pixmap and label */
+
+#ifndef UNUSED
+# define UNUSED(x) ((void)(x))
+#endif
+
+#ifndef MAX
+# define MAX(i, j) ( (i) > (j) ? (i) : (j) )
+#endif
+
+
+#define rclass(w) ((RadioWidgetClass)((w)->core.widget_class))
+
+
+#ifdef _ThreeDP_h
+#define swid(rw) ((rw)->threeD.shadow_width)
+#else
+#define swid(rw) ((rw)->core.border_width)
+#endif
+
+#define bsize(rw) (rclass(rw)->radio_class.dsize)
+#define bs(rw) (bsize(rw) + PIXMAP_OFFSET + 2*swid(rw))
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* The translations table from Toggle do not need to be
+ * overridden by Radio
+ */
+
+
+/* Member functions */
+
+static void RadioInit (Widget, Widget, ArgList, Cardinal *);
+static void RadioExpose (Widget, XEvent *, Region);
+static void RadioResize (Widget);
+static void RadioDestroy (Widget);
+static void RadioClassInit (void);
+static void RadioClassPartInit (WidgetClass);
+static Boolean RadioSetValues (Widget, Widget, Widget, ArgList, Cardinal *);
+static void DrawDiamond (Widget);
+static XtGeometryResult RadioQueryGeometry (Widget, XtWidgetGeometry *,
+ XtWidgetGeometry *);
+
+/* Action procs */
+
+static void RadioHighlight (Widget, XEvent *, String *, Cardinal *);
+static void RadioUnhighlight (Widget, XEvent *, String *, Cardinal *);
+
+/* internal privates */
+
+static void RadioSize (RadioWidget, Dimension *, Dimension *);
+
+/* The actions table from Toggle is almost perfect, but we need
+ * to override Highlight, Set, and Unset.
+ */
+
+static XtActionsRec actionsList[] =
+{
+ {"highlight", RadioHighlight},
+ {"unhighlight", RadioUnhighlight},
+};
+
+#define offset(field) XtOffset(RadioWidget, radio.field)
+
+static XtResource resources[] = {
+ {XtNisRadio, XtCIsRadio, XtRBoolean, sizeof(Boolean),
+ offset(isRadio), XtRImmediate, (XtPointer)True },
+};
+#undef offset
+
+#define SuperClass ((ToggleWidgetClass)&toggleClassRec)
+
+RadioClassRec radioClassRec = {
+ {
+ (WidgetClass) SuperClass, /* superclass */
+ "Radio", /* class_name */
+ sizeof(RadioRec), /* size */
+ RadioClassInit, /* class_initialize */
+ RadioClassPartInit, /* class_part_initialize */
+ FALSE, /* class_inited */
+ RadioInit, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ actionsList, /* actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* resource_count */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ RadioDestroy, /* destroy */
+ RadioResize, /* resize */
+ RadioExpose, /* expose */
+ RadioSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ XtInheritTranslations, /* tm_table */
+ RadioQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL /* extension */
+ }, /* CoreClass fields initialization */
+ {
+ XtInheritChangeSensitive /* change_sensitive */
+#ifndef HAVE_OLD_XAW
+ , NULL
+#endif
+ }, /* SimpleClass fields initialization */
+#ifdef _ThreeDP_h
+ {
+ XtInheritXaw3dShadowDraw /* field not used */
+ }, /* ThreeDClass fields initialization */
+#endif
+ {
+ 0 /* field not used */
+ }, /* LabelClass fields initialization */
+ {
+ 0 /* field not used */
+ }, /* CommandClass fields initialization */
+ {
+ RadioSet, /* Set Procedure. */
+ RadioUnset, /* Unset Procedure. */
+ NULL /* extension. */
+ }, /* ToggleClass fields initialization */
+ {
+ BOX_SIZE,
+ DrawDiamond, /* draw procedure */
+ None, /* selected radiobutton */
+ None, /* unselected radiobutton */
+ None, /* selected menubutton */
+ None, /* unselected menubutton */
+ NULL /* extension. */
+ } /* RadioClass fields initialization */
+};
+
+ /* for public consumption */
+WidgetClass radioWidgetClass = (WidgetClass) &radioClassRec;
+
+
+
+
+
+
+/****************************************************************
+ *
+ * Class Methods
+ *
+ ****************************************************************/
+
+static void
+RadioClassInit (void)
+{
+ XawInitializeWidgetSet();
+}
+
+static void
+RadioClassPartInit (WidgetClass class)
+{
+ RadioWidgetClass c = (RadioWidgetClass) class;
+ RadioWidgetClass super = (RadioWidgetClass)c->core_class.superclass;
+
+ if( c->radio_class.drawDiamond == NULL ||
+ c->radio_class.drawDiamond == XtInheritDrawDiamond )
+ {
+ c->radio_class.drawDiamond = super->radio_class.drawDiamond;
+ }
+
+}
+
+
+
+
+static void
+RadioInit (Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ RadioWidget rw = (RadioWidget) new;
+ RadioWidget rw_req = (RadioWidget) request;
+ Dimension w,h;
+
+ UNUSED(args);
+ UNUSED(num_args);
+
+ /* FIXME: should pixmap initialization be here?? */
+
+ /* Select initial size for the widget */
+ if( rw_req->core.width == 0 || rw_req->core.height == 0 ) {
+ RadioSize(rw, &w,&h);
+ if( rw_req->core.width == 0 )
+ rw->core.width = w;
+ if( rw_req->core.height == 0 )
+ rw->core.height = h;
+ rw->core.widget_class->core_class.resize(new);
+ }
+ /*
+ FIXME: access to XtWindow(rw) fails in the init method, so
+ I moved the bitmap creation here -- is there a better way??
+ */
+ /* create pixmaps */
+ rclass(rw)->radio_class.sel_radio
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_radio_on_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+ rclass(rw)->radio_class.unsel_radio
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_radio_off_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+ rclass(rw)->radio_class.sel_menu
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_check_on_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+ rclass(rw)->radio_class.unsel_menu
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_check_off_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+}
+
+/* Function Name: RadioDestroy
+ * Description: Destroy Callback for radio widget.
+ * Arguments: w - the radio widget that is being destroyed.
+ * Returns: none.
+ */
+
+static void
+RadioDestroy (Widget w)
+{
+ RadioWidget rw = (RadioWidget)w;
+ /* de-allocate bitmaps */
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.sel_radio);
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.unsel_radio);
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.sel_menu);
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.unsel_menu);
+}
+
+
+/* React to size change from manager. Label widget will compute some internal
+ * stuff, but we need to override. This code requires knowledge of the
+ * internals of the Label widget.
+ */
+
+static void
+RadioResize (Widget w)
+{
+ RadioWidget rw = (RadioWidget)w;
+
+ /* call parent resize proc */
+ SuperClass->core_class.resize(w);
+
+ /* override label offset */
+
+ switch( rw->label.justify ) {
+ case XtJustifyLeft:
+ rw->label.label_x += (bs(rw) + rw->label.internal_width);
+ break;
+ case XtJustifyRight:
+ break;
+ case XtJustifyCenter:
+ default:
+ rw->label.label_x += (bs(rw) + rw->label.internal_width)/2;
+ break;
+ }
+}
+
+
+/*
+ * Repaint the widget window.
+ */
+
+static void
+RadioExpose (Widget w,
+ XEvent *event,
+ Region region)
+{
+ RadioWidget rw = (RadioWidget) w;
+ Display *dpy = XtDisplay(w);
+ Window win = XtWindow(w);
+ GC gc;
+ Pixmap left_bitmap;
+ extern WidgetClass labelWidgetClass;
+
+ /* Note: the Label widget examines the region to decide if anything
+ * needs to be drawn. I'm not sure that this is worth the effort,
+ * but it bears thinking on.
+ */
+
+ /* Command widget may sometimes override the label GC in order
+ * to draw inverse video. We don't use inverse video, so we need
+ * to restore the label's normal GC.
+ */
+ rw->label.normal_GC = rw->command.normal_GC;
+
+
+ /* Let label widget draw the label. If there was an lbm_x
+ * field, we could let Label draw the bitmap too. But there
+ * isn't, so we need to temporarily remove the bitmap and
+ * draw it ourself later.
+ */
+ left_bitmap = rw->label.left_bitmap;
+ rw->label.left_bitmap = None;
+ labelWidgetClass->core_class.expose(w,event,region);
+ rw->label.left_bitmap = left_bitmap;
+
+ /* now manually draw the left bitmap. TODO: 3-d look, xaw-xpm */
+ gc = XtIsSensitive(w) ? rw->label.normal_GC : rw->label.gray_GC;
+ if( left_bitmap != None && rw->label.lbm_width > 0 )
+ {
+ /* TODO: handle pixmaps */
+ XCopyPlane(dpy, left_bitmap, win, gc,
+ 0,0, rw->label.lbm_width, rw->label.lbm_height,
+ (int) rw->label.internal_width*2 + bs(rw),
+ (int) rw->label.internal_height + rw->label.lbm_y,
+ 1UL);
+ }
+ DrawDiamond(w);
+ /* Finally, the button itself */
+ ((RadioWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w);
+}
+
+
+
+
+/************************************************************
+ *
+ * Set specified arguments into widget
+ *
+ ***********************************************************/
+
+
+/* ARGSUSED */
+static Boolean
+RadioSetValues (Widget current,
+ Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ RadioWidget oldrw = (RadioWidget) current;
+ RadioWidget newrw = (RadioWidget) new;
+
+ UNUSED(request);
+ UNUSED(args);
+ UNUSED(num_args);
+
+ /* Need to find out if the size of the widget changed. Set new size
+ * if it did and resize is permitted. One way to determine of the
+ * widget changed size would be to scan the args list. Another way
+ * is to compare the old and new widgets and see if any of several
+ * size-related fields have been changed. The Label widget chose the
+ * former method, but I choose the latter.
+ */
+
+ if( newrw->label.resize &&
+ ( newrw->core.width != oldrw->core.width ||
+ newrw->core.height != oldrw->core.height ||
+ newrw->core.border_width != oldrw->core.border_width ) )
+ {
+ RadioSize(newrw, &newrw->core.width, &newrw->core.height);
+ }
+
+ /* The label set values routine can resize the widget. We need to
+ * recalculate if this is true.
+ */
+ if (newrw->label.label_x != oldrw->label.label_x)
+ {
+ RadioResize (new);
+ }
+ return FALSE;
+}
+
+static XtGeometryResult
+RadioQueryGeometry (Widget w,
+ XtWidgetGeometry *intended,
+ XtWidgetGeometry *preferred)
+{
+ RadioWidget rw = (RadioWidget) w;
+
+ preferred->request_mode = CWWidth | CWHeight;
+ RadioSize(rw, &preferred->width, &preferred->height);
+
+ if ( ((intended->request_mode & (CWWidth | CWHeight))
+ == (CWWidth | CWHeight)) &&
+ intended->width == preferred->width &&
+ intended->height == preferred->height)
+ return XtGeometryYes;
+ else if (preferred->width == w->core.width &&
+ preferred->height == w->core.height)
+ return XtGeometryNo;
+ else
+ return XtGeometryAlmost;
+}
+
+
+
+
+
+/************************************************************
+ *
+ * Action Procedures
+ *
+ ************************************************************/
+
+/*
+ * Draw the highlight border around the widget. The Command widget
+ * did this by drawing through a mask. We do it by just drawing the
+ * border.
+ */
+
+static void
+DrawHighlight (Widget w,
+ GC gc)
+{
+ RadioWidget rw = (RadioWidget)w;
+ XRectangle rects[4];
+ Dimension ht = rw->command.highlight_thickness;
+
+ if( ht <= 0 ||
+ ht > rw->core.width/2 ||
+ ht > rw->core.height/2 )
+ return;
+
+ if( ! XtIsRealized(w) )
+ return;
+
+ rects[0].x = 0; rects[0].y = 0;
+ rects[0].width = rw->core.width; rects[0].height = ht;
+ rects[1].x = 0; rects[1].y = rw->core.height - ht;
+ rects[1].width = rw->core.width; rects[1].height = ht;
+ rects[2].x = 0; rects[2].y = ht;
+ rects[2].width = ht; rects[2].height = rw->core.height - ht*2;
+ rects[3].x = rw->core.width - ht; rects[3].y = ht;
+ rects[3].width = ht; rects[3].height = rw->core.height - ht*2;
+ XFillRectangles( XtDisplay(w), XtWindow(w), gc, rects, 4);
+}
+
+static void
+RadioHighlight (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ DrawHighlight(w, rw->command.normal_GC);
+}
+
+
+static void
+RadioUnhighlight (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ DrawHighlight(w, rw->command.inverse_GC);
+}
+
+
+void
+RadioSet (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class;
+
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if( rw->command.set )
+ return;
+
+ rw->command.set = TRUE;
+ if( XtIsRealized(w) )
+ class->radio_class.drawDiamond(w);
+}
+
+
+void
+RadioUnset (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class;
+
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if( ! rw->command.set )
+ return;
+
+ rw->command.set = FALSE;
+ if( XtIsRealized(w) )
+ class->radio_class.drawDiamond(w);
+}
+
+
+
+
+/************************************************************
+ *
+ * Internal Procedures
+ *
+ ************************************************************/
+
+
+/* Size of widget. Width is size of box plus width of border around
+ * box plus width of label plus three margins plus the size of the left
+ * bitmap, if any. Height is max(box,bitmap,label) plus two margins.
+ */
+
+static void
+RadioSize (RadioWidget rw,
+ Dimension *w,
+ Dimension *h)
+{
+ *w = rw->label.label_width + bs(rw) + LEFT_OFFSET(rw) +
+ 3 * rw->label.internal_width;
+ *h = MAX( rw->label.label_height, bs(rw) ) +
+ 2 * rw->label.internal_width;
+}
+
+
+static void
+DrawDiamond(Widget w)
+{
+ RadioWidget rw = (RadioWidget) w;
+ Display *dpy = XtDisplay(w);
+ Window win = XtWindow(w);
+
+ Position x = rw->label.internal_width;
+ Position y = rw->core.height/2;
+ GC gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC;
+ Pixmap selected, unselected;
+
+ if (rw->radio.isRadio) { /* it's a radio button */
+ selected = rclass(rw)->radio_class.sel_radio;
+ unselected = rclass(rw)->radio_class.unsel_radio;
+ }
+ else {
+ selected = rclass(rw)->radio_class.sel_menu;
+ unselected = rclass(rw)->radio_class.unsel_menu;
+ }
+
+ ASSERT(selected != None, "");
+ ASSERT(unselected != None, "");
+
+ if(rw->command.set) {
+ XCopyPlane(dpy, selected, win, gc,
+ 0, 0, BUTTON_BITMAP_H, BUTTON_BITMAP_W,
+ x, y - BUTTON_BITMAP_H / 2, 1L);
+ }
+ else {
+ XCopyPlane(dpy, unselected, win, gc,
+ 0, 0, BUTTON_BITMAP_H, BUTTON_BITMAP_W,
+ x, y - BUTTON_BITMAP_H / 2, 1L);
+ }
+}
+
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xlwradio.h b/Build/source/texk/xdvik/gui/xlwradio.h
new file mode 100644
index 00000000000..728c97fcbee
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xlwradio.h
@@ -0,0 +1,119 @@
+/* adapted from xlwradio.c in the XEmacs distribution.
+ Changes are Copyright (C) 2002-2004 the xdvik development team
+ Original copyright follows:
+*/
+
+/* Radio Widget for XEmacs.
+ Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Synched up with: Radio.h 1.1 */
+
+/*
+ * Radio.h - Radio button widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: June 30, 1997
+ */
+
+#ifndef _XawRadio_h
+#define _XawRadio_h
+
+#include "xdvi-config.h"
+
+#ifndef MOTIF /* entire file */
+
+/***********************************************************************
+ *
+ * Radio Widget
+ *
+ * The Radio widget is identical to the Toggle widget in behavior but
+ * not in appearance. The Radio widget looks like a small diamond
+ * shaped button to the left of the label.
+ * (SU: changed this to use a bitmap instead.)
+ *
+ ***********************************************************************/
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Toggle.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ radioGroup RadioGroup Widget NULL
+ radioData RadioData Pointer (XPointer) Widget
+ isRadio IsRadio Booelan True
+ state State Boolean Off
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ callback Callback Pointer NULL
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ font Font XFontStructx* XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ highlightThickness Thickness Dimension 2
+ insensitiveBorder sensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ justify Justify XtJustify XtJustifyCenter
+ label Label String NULL
+ mappedWhenManaged MappedWhenManaged Boolean True
+ resize Resize Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * These should be in StringDefs.h but aren't so we will define
+ * them here if they are needed.
+ */
+
+
+extern WidgetClass radioWidgetClass;
+
+typedef struct _RadioClassRec *RadioWidgetClass;
+typedef struct _RadioRec *RadioWidget;
+
+#define XtNisRadio "isRadio"
+#define XtCIsRadio "IsRadio"
+
+/************************************************************
+ *
+ * Public Functions
+ *
+ ************************************************************/
+
+#endif /* MOTIF */
+
+#endif /* _XawRadio_h */
diff --git a/Build/source/texk/xdvik/gui/xlwradioP.h b/Build/source/texk/xdvik/gui/xlwradioP.h
new file mode 100644
index 00000000000..5ce6f654d7f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xlwradioP.h
@@ -0,0 +1,140 @@
+/* adapted from xlwradio.c in the XEmacs distribution.
+ Changes are Copyright (C) 2002-2004 the xdvik development team
+ Original copyright follows:
+*/
+
+/* Radio Widget for XEmacs.
+ Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/*
+ * RadioP.h - Private definitions for Radio widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: June 30, 1997
+ *
+ */
+
+#ifndef _XawRadioP_h
+#define _XawRadioP_h
+
+#include "xdvi-config.h"
+
+#include "xlwradio.h"
+
+#ifndef MOTIF
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+
+#include <X11/Xaw/ToggleP.h>
+
+/***********************************************************************
+ *
+ * Radio Widget Private Data
+ *
+ ***********************************************************************/
+
+typedef void (*XawDiamondProc) (Widget);
+
+void RadioSet (Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params); /* unused */
+
+void RadioUnset (Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params); /* unused */
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+/* New fields for the Radio widget class record */
+typedef struct _RadioClass {
+ Dimension dsize; /* diamond size */
+ XawDiamondProc drawDiamond;
+ /* pixmaps for the button */
+ Pixmap sel_radio; /* selected state */
+ Pixmap unsel_radio; /* unselected state */
+ Pixmap sel_menu; /* selected state */
+ Pixmap unsel_menu; /* unselected state */
+ /* TODO: 3-d and xaw-xpm features? */
+ XtPointer extension;
+} RadioClassPart;
+
+#define XtInheritDrawDiamond ((XawDiamondProc)_XtInherit)
+
+/* Full class record declaration */
+typedef struct _RadioClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+#ifdef _ThreeDP_h
+ ThreeDClassPart threeD_class;
+#endif
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ ToggleClassPart toggle_class;
+ RadioClassPart radio_class;
+} RadioClassRec;
+
+extern RadioClassRec radioClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+/* New fields for the Radio widget record */
+typedef struct {
+ /* resources */
+ Boolean isRadio; /* radio if True, checkbox else */
+ /* TODO: 3-d and xaw-xpm features? */
+
+ /* private data */
+ XtPointer extension;
+} RadioPart;
+
+ /* Full widget declaration */
+typedef struct _RadioRec {
+ CorePart core;
+ SimplePart simple;
+#ifdef _ThreeDP_h
+ ThreeDPart threeD;
+#endif
+ LabelPart label;
+ CommandPart command;
+ TogglePart toggle;
+ RadioPart radio;
+} RadioRec;
+
+#endif /* MOTIF */
+
+#endif /* _XawRadioP_h */
diff --git a/Build/source/texk/xdvik/gui/xm_colorsel.c b/Build/source/texk/xdvik/gui/xm_colorsel.c
new file mode 100644
index 00000000000..9b91e2c76fd
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_colorsel.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Color selector window showing a range of colors, and sliders to customize them.
+ * Heavily influenced by color_slide.c from ch. 13 of O'Reilly's Motif Programming Manual 1.2.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "Tip.h"
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "xm_prefsP.h"
+#include "xm_prefs.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "util.h"
+#include "topic-window.h"
+#include "search-internal.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/SelectioB.h>
+# include <Xm/AtomMgr.h>
+
+#include <Xm/MwmUtil.h>
+
+#define ROWS 7
+#define COLS 10
+
+/* for passing around information - no global data here ;-) */
+struct color_info {
+ XColor new_color;
+ Widget tooltip;
+ Widget new_sample;
+ Widget r_scale;
+ Widget g_scale;
+ Widget b_scale;
+ struct color_button_info *button_info;
+};
+
+/*
+ * These are the colors of the GTK/Mozilla color picker
+ * (see e.g. http://lxr.mozilla.org/mozilla/source/toolkit/content/widgets/colorpicker.xml)
+ * which has the colors more or less sorted by columns.
+ * It's terminated by NULL just in case the table gets out of sync with
+ * the row/column number.
+ */
+static const char *colors[] = {
+ /* column 1 */
+ "#FFFFFF", "#CCCCCC", "#C0C0C0", "#999999", "#666666", "#333333", "#000000",
+ /* column 2 */
+ "#FFCCCC", "#FF6666", "#FF0000", "#CC0000", "#990000", "#660000", "#330000",
+ /* column 3 */
+ "#FFCC99", "#FF9966", "#FF9900", "#FF6600", "#CC6600", "#993300", "#663300",
+ /* column 4 */
+ "#FFFF99", "#FFFF66", "#FFCC66", "#FFCC33", "#CC9933", "#996633", "#663333",
+ /* column 5 */
+ "#FFFFCC", "#FFFF33", "#FFFF00", "#FFCC00", "#999900", "#666600", "#333300",
+ /* column 6 */
+ "#99FF99", "#66FF99", "#33FF33", "#33CC00", "#009900", "#006600", "#003300",
+ /* column 7 */
+ "#99FFFF", "#33FFFF", "#66CCCC", "#00CCCC", "#339999", "#336666", "#003333",
+ /* column 8 */
+ "#CCFFFF", "#66FFFF", "#33CCFF", "#3366FF", "#3333FF", "#000099", "#000066",
+ /* column 9 */
+ "#CCCCFF", "#9999FF", "#6666CC", "#6633FF", "#6600CC", "#333399", "#330099",
+ /* column 10 */
+ "#FFCCFF", "#FF99FF", "#CC66CC", "#CC33CC", "#993399", "#663366", "#330033",
+ /* safety */
+ NULL
+};
+
+#define MOTIF 1
+
+static void
+popdown_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ Widget dialog;
+ struct prefs_choice *prefs = (struct prefs_choice *)client_data;
+
+ UNUSED(call_data);
+
+ ASSERT(prefs != NULL, "user_data in popdown_cb musn't be NULL!");
+ if (get_widget_by_name(&dialog, widget, Xdvi_COLOR_DIALOG_NAME, True)) {
+/* fprintf(stderr, "popdown!\n"); */
+ remove_from_deplist(prefs, dialog);
+ XtUnmanageChild(dialog);
+ }
+}
+
+static void
+popdown_apply_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = NULL;
+ static XmDrawnButtonCallbackStruct cbs;
+ struct prefs_choice *prefs = (struct prefs_choice *)client_data;
+
+ UNUSED(call_data);
+ ASSERT(prefs != NULL, "struct prefs_choice * in popdown_apply_cb mustn't be NULL!");
+
+ /* To update button to new color, set its button_info color
+ and call the button's expose callback */
+ XtVaGetValues(widget, XmNuserData, &cinfo, NULL);
+ ASSERT(cinfo != NULL, "XmNuserData in popdown_apply_cb musn't be NULL!");
+ cinfo->button_info->pixel = cinfo->new_color.pixel;
+
+ cbs.reason = XmCR_EXPOSE;
+ XtCallCallbacks(cinfo->button_info->w, XmNexposeCallback, &cbs);
+
+ remove_from_deplist(prefs, widget);
+
+ /* Store the current setting -
+ FIXME: better way of converting color or pixel to string? pixel_to_str() in x_util.c is broken! */
+ store_preference(&(prefs->db), cinfo->button_info->resource_name,
+ "#%.2x%.2x%.2x",
+ cinfo->new_color.red >> 8,
+ cinfo->new_color.green >> 8,
+ cinfo->new_color.blue >> 8);
+
+ /* Update the display to use the new foreground/background.
+ * I don't really understand the entire color interface, but
+ * apparently the following works, and nothing else I tried did ... */
+ if (strcmp(cinfo->button_info->resource_name, "foreground") == 0) {
+ XGCValues values;
+
+ fg_initial.r = cinfo->new_color.red;
+ fg_initial.g = cinfo->new_color.green;
+ fg_initial.b = cinfo->new_color.blue;
+
+ values.foreground = resource.fore_Pixel = resource.rule_pixel = cinfo->new_color.pixel;
+ XChangeGC(DISP, globals.gc.ruler, GCForeground, &values);
+
+ scanned_page = scanned_page_color = scanned_page_reset;
+ globals.ev.flags |= EV_NEWPAGE;
+
+ }
+ else if (strcmp(cinfo->button_info->resource_name, "background") == 0) {
+ bg_initial.r = cinfo->new_color.red;
+ bg_initial.g = cinfo->new_color.green;
+ bg_initial.b = cinfo->new_color.blue;
+
+ resource.back_Pixel = cinfo->new_color.pixel;
+ scanned_page = scanned_page_color = scanned_page_reset;
+ globals.ev.flags |= EV_RELOAD; /* EV_NEWPAGE not sufficient with color code ... */
+ }
+ else if (strcmp(cinfo->button_info->resource_name, "highlight") == 0) {
+ XGCValues values;
+ values.foreground = resource.hl_Pixel = cinfo->new_color.pixel;
+ XChangeGC(DISP, globals.gc.high, GCForeground, &values);
+ /* hack to update match GC: fake change in inverted property, redraw
+ so that GC is cleared, then change inverted property back */
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+ search_draw_inverted_regions();
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+ /* end of hack to update match GC */
+ globals.ev.flags |= EV_NEWPAGE; /* force redraw */
+ }
+
+ XtUnmanageChild(widget);
+}
+
+static void
+popdown_cancel_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct prefs_choice *prefs = (struct prefs_choice *)client_data;
+
+/* fprintf(stderr, "popdown cancel; call_data: %p!\n", call_data); */
+ if (call_data != NULL) {
+/* fprintf(stderr, "removing from deplist: %p!!!\n", prefs); */
+ remove_from_deplist(prefs, widget);
+ }
+
+ XtUnmanageChild(widget);
+/* XtPopdown(XtParent(widget)); */
+}
+
+static void
+revert_color_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = (struct color_info *)client_data;
+ Pixel pix;
+ unsigned r, g, b;
+
+ UNUSED(call_data);
+
+ /* get color of old_sample button */
+ XtVaGetValues(widget, XmNbackground, &pix, NULL);
+ /* fprintf(stderr, "Color: 0x%.6lx\n", pix); */
+
+ /* use this instead of XtVaSetValues on XmNbackground so that
+ the foreground color gets also changed appropriately. */
+#if XmVersion >= 1002
+ XmChangeColor(cinfo->new_sample, pix);
+#else
+ XtVaSetValues(cinfo->new_sample, XmNbackground, pix, NULL);
+#endif
+
+ /* update sliders */
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+ pixel_to_color(pix, &(cinfo->new_color), DISP, G_colormap);
+
+ r = cinfo->new_color.red >> 8;
+ g = cinfo->new_color.green >> 8;
+ b = cinfo->new_color.blue >> 8;
+
+/* fprintf(stderr, "Pixel: 0x%.6lx\n", cinfo->new_color.pixel); */
+
+ XtVaSetValues(cinfo->r_scale, XmNvalue, r, NULL);
+ XtVaSetValues(cinfo->g_scale, XmNvalue, g, NULL);
+ XtVaSetValues(cinfo->b_scale, XmNvalue, b, NULL);
+}
+
+static void
+show_color_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = (struct color_info *)client_data;
+ Pixel pix;
+ unsigned r, g, b;
+
+ UNUSED(call_data);
+ XtVaGetValues(widget, XmNbackground, &pix, NULL);
+/* fprintf(stderr, "Color: 0x%.6lx\n", pix); */
+
+ /* use this instead of XtVaSetValues on XmNbackground so that
+ the foreground color gets also changed appropriately. */
+#if XmVersion >= 1002
+ XmChangeColor(cinfo->new_sample, pix);
+#else
+ XtVaSetValues(cinfo->new_sample, XmNbackground, pix, NULL);
+#endif
+
+ /* update sliders */
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+ pixel_to_color(pix, &(cinfo->new_color), DISP, G_colormap);
+
+ r = cinfo->new_color.red >> 8;
+ g = cinfo->new_color.green >> 8;
+ b = cinfo->new_color.blue >> 8;
+
+/* fprintf(stderr, "Pixel: 0x%.6lx\n", cinfo->new_color.pixel); */
+
+ XtVaSetValues(cinfo->r_scale, XmNvalue, r, NULL);
+ XtVaSetValues(cinfo->g_scale, XmNvalue, g, NULL);
+ XtVaSetValues(cinfo->b_scale, XmNvalue, b, NULL);
+}
+
+static void
+slider_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = (struct color_info *)client_data;
+ XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)call_data;
+
+/* fprintf(stderr, "Pixel1 : 0x%.6lx\n", cinfo->new_color.pixel); */
+ /* reuse cinfo->new_color */
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+
+ if (widget == cinfo->r_scale) {
+ cinfo->new_color.red = cbs->value << 8; /* << 8 == * 65535 */
+ }
+ else if (widget == cinfo->g_scale) {
+ cinfo->new_color.green = cbs->value << 8;
+ }
+ else if (widget == cinfo->b_scale) {
+ cinfo->new_color.blue = cbs->value << 8;
+ }
+
+ if (!XAllocColor(DISP, G_colormap, &(cinfo->new_color))) {
+ XDVI_ERROR((stderr, "Couldn't XAllocColor\n"));
+ return;
+ }
+/* fprintf(stderr, "Pixel: 0x%.6lx\n", cinfo->new_color.pixel); */
+
+#if XmVersion >= 1002
+ /* if avaliable, use this so that the foreground color also
+ gets updated appropriately: */
+ XmChangeColor(cinfo->new_sample, cinfo->new_color.pixel);
+#else
+ XtVaSetValues(cinfo->new_sample, XmNbackground, cinfo->new_color.pixel, NULL);
+#endif
+}
+
+static void
+h_init_sliders(struct color_info *cinfo)
+{
+ unsigned r, g, b;
+
+ r = cinfo->new_color.red >> 8;
+ g = cinfo->new_color.green >> 8;
+ b = cinfo->new_color.blue >> 8;
+
+ XtVaSetValues(cinfo->r_scale, XmNvalue, r, NULL);
+ XtVaSetValues(cinfo->g_scale, XmNvalue, g, NULL);
+ XtVaSetValues(cinfo->b_scale, XmNvalue, b, NULL);
+}
+
+static Widget
+h_create_color_matrix(Widget parent, Widget top, struct color_info *cinfo)
+{
+ int i, j;
+ const char **color_ptr = colors;
+
+ Widget matrix =
+ XtVaCreateManagedWidget("color_matrix", xmRowColumnWidgetClass,
+ parent,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNpacking, XmPACK_COLUMN,
+ XmNnumColumns, COLS,
+ XmNorientation, XmVERTICAL,
+ XmNbackground, BlackPixelOfScreen(XtScreen(parent)),
+ XmNspacing, 1,
+ XmNmarginWidth, 1,
+ XmNmarginHeight, 1,
+ NULL);
+
+ for (i = 0; i < ROWS; i++) {
+ for (j = 0; j < COLS; j++) {
+ Pixel pix = BlackPixelOfScreen(XtScreen(parent));
+ Widget button;
+ if (*color_ptr == NULL) /* safety */
+ break;
+ str_to_pixel(top, *color_ptr++, &pix);
+ /* fprintf(stderr, "creating button %d, %d - %s\n", i, j, k % 2 ? "b" : "w"); */
+ button = XtVaCreateManagedWidget("c_button", xmDrawnButtonWidgetClass,
+ matrix,
+ XmNbackground, pix,
+ XmNheight, 19,
+ XmNwidth, 19,
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 0,
+ NULL);
+ XtAddCallback(button, XmNactivateCallback, show_color_cb, cinfo);
+ }
+ }
+ return matrix;
+}
+
+static void
+h_create_sliders(Widget parent, Widget top, struct color_info *cinfo)
+{
+ XmString str;
+ Widget r_label, g_label, b_label;
+ Widget r_scale, g_scale, b_scale;
+ Dimension curr, max;
+
+ Arg scale_args[8];
+ Arg label_args[8];
+ int scale_n = 0;
+
+ XtSetArg(scale_args[scale_n], XmNmaximum, 255); scale_n++;
+ /* True is an older setting of XmNshowValue that should also work with 2.x */
+ XtSetArg(scale_args[scale_n], XmNshowValue, True); scale_n++;
+ XtSetArg(scale_args[scale_n], XmNorientation, XmHORIZONTAL); scale_n++;
+#if XmVersion >= 2000
+ XtSetArg(scale_args[scale_n], XmNshowArrows, XmEACH_SIDE); scale_n++;
+ /* XmVersion < 2000 only had `True' which was the default anyway */
+#endif
+
+ str = XmStringCreateLocalized("Red");
+ XtSetArg(label_args[0], XmNlabelString, str);
+ r_label = XtCreateManagedWidget("r_label", xmLabelGadgetClass, parent, label_args, 1);
+ XmStringFree(str);
+
+ r_scale = XtCreateWidget("r_scale", xmScaleWidgetClass, parent, scale_args, scale_n);
+ cinfo->r_scale = r_scale;
+ XtAddCallback(r_scale, XmNdragCallback, slider_cb, cinfo);
+ XtAddCallback(r_scale, XmNvalueChangedCallback, slider_cb, cinfo);
+
+ str = XmStringCreateLocalized("Green");
+ XtSetArg(label_args[0], XmNlabelString, str);
+ g_label = XtCreateManagedWidget("g_label", xmLabelGadgetClass, parent, label_args, 1);
+ XmStringFree(str);
+
+ g_scale = XtCreateWidget("g_scale", xmScaleWidgetClass, parent, scale_args, scale_n);
+ cinfo->g_scale = g_scale;
+ XtAddCallback(g_scale, XmNdragCallback, slider_cb, cinfo);
+ XtAddCallback(g_scale, XmNvalueChangedCallback, slider_cb, cinfo);
+
+ str = XmStringCreateLocalized("Blue");
+ XtSetArg(label_args[0], XmNlabelString, str);
+ b_label = XtCreateManagedWidget("b_label", xmLabelGadgetClass, parent, label_args, 1);
+ XmStringFree(str);
+
+ b_scale = XtCreateWidget("b_scale", xmScaleWidgetClass, parent, scale_args, scale_n);
+ cinfo->b_scale = b_scale;
+ XtAddCallback(b_scale, XmNdragCallback, slider_cb, cinfo);
+ XtAddCallback(b_scale, XmNvalueChangedCallback, slider_cb, cinfo);
+
+ /* get max width of labels, and adjust scale size to what's left */
+ XtVaGetValues(r_label, XmNwidth, &curr, NULL);
+ XtVaGetValues(g_label, XmNwidth, &max, NULL);
+ if (curr > max)
+ max = curr;
+ XtVaGetValues(b_label, XmNwidth, &curr, NULL);
+ if (curr > max)
+ max = curr;
+ /* we know the width of the color selector is about 200 pixels (10 fields each 20 wide),
+ so we use that as max length */
+ curr = 200 - max - 2; /* some additional offset */
+
+ /* fprintf(stderr, "width of slider: %d\n", curr); */
+ /* fprintf(stderr, "width of string: %d\n", max); */
+
+ /* attach widgets; needs to be done after creating them since r_label
+ attachment references g_label etc. */
+ XtVaSetValues(r_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, g_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ NULL);
+ XtVaSetValues(r_scale,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, g_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ XmNscaleWidth, curr,
+ NULL);
+ XtVaSetValues(g_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, b_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ NULL);
+ XtVaSetValues(g_scale,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, b_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ XmNscaleWidth, curr,
+ NULL);
+ XtVaSetValues(b_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 15,
+ NULL);
+ XtVaSetValues(b_scale,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 15,
+ XmNscaleWidth, curr,
+ NULL);
+
+ XtManageChild(r_scale);
+ XtManageChild(g_scale);
+ XtManageChild(b_scale);
+
+ h_init_sliders(cinfo);
+
+}
+
+static Widget
+h_create_shell(Widget parent, struct color_info *cinfo)
+{
+ Widget shell, dialog, form, button_row, color_matrix;
+ Widget old_sample, new_sample;
+ Widget tip_shell;
+ Atom WM_DELETE_WINDOW;
+ Arg args[32];
+ int n;
+
+ XmString str;
+
+ Pixel old_pixel = cinfo->button_info->pixel;
+ /* hack to disable resizing of the shell, since this messes up the color matrix badly */
+ int decoration = MWM_DECOR_ALL | MWM_DECOR_RESIZEH | MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE;
+ int functions = MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE;
+
+ struct color_button_info *binfo = cinfo->button_info;
+ struct topic_info *tinfo = binfo->tinfo;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+/* struct prefs_choice *prefs; */
+
+ n = 0;
+ XtSetArg(args[n], XmNuserData, cinfo); n++;
+
+/* XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++; */
+/* XtSetArg(args[n], XmNnoResize, True); n++; */
+/* XtSetArg(args[n], XmNmwmFunctions, functions); n++; */
+/* XtSetArg(args[n], XmNmwmDecorations, decoration); n++; */
+ XtSetArg(args[n], XtNtitle, "Xdvik: Select Color"); n++;
+
+ dialog = XmCreatePromptDialog(parent, Xdvi_COLOR_DIALOG_NAME, args, n);
+ /* unmanage stuff to get a `scratch' widget */
+ XtUnmanageChild(XtNameToWidget(dialog, "Help"));
+ XtUnmanageChild(XtNameToWidget(dialog, "Text"));
+ XtUnmanageChild(XtNameToWidget(dialog, "Selection"));
+
+ shell = XtParent(dialog);
+
+ XtVaSetValues(shell,
+ XmNdeleteResponse, XmDO_NOTHING,
+ XmNnoResize, True,
+ XmNmwmFunctions, functions,
+ XmNmwmDecorations, decoration,
+ NULL);
+
+ /* cinfo->new_color is a allocated/freed by request; initialize it with old_pixel */
+ XAllocColor(DISP, G_colormap, &(cinfo->new_color));
+ cinfo->new_color.flags = DoRed | DoGreen | DoBlue;
+
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+ pixel_to_color(old_pixel, &(cinfo->new_color), DISP, G_colormap);
+
+
+ tip_shell = XtVaCreatePopupShell("tipShell", tipWidgetClass,
+ parent, XtNwidth, 1, XtNheight, 1,
+ NULL);
+ cinfo->tooltip = tip_shell;
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ dialog,
+ XmNhorizontalSpacing, 10,
+ XmNverticalSpacing, 10,
+ XmNallowResize, False,
+ NULL);
+
+ button_row = XtVaCreateManagedWidget("button_row", xmRowColumnWidgetClass,
+ form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNorientation, XmHORIZONTAL,
+ XmNpacking, XmPACK_COLUMN,
+ XmNspacing, 8,
+ XmNmarginWidth, 1,
+ XmNmarginHeight, 1,
+ NULL);
+
+ str = XmStringCreateLocalized("Old");
+ old_sample = XtVaCreateManagedWidget(Xdvi_COLOR_DIALOG_OLD_SAMPLE_NAME, xmPushButtonWidgetClass,
+ button_row,
+ XmNbackground, old_pixel,
+ XmNlabelString, str,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 1,
+ NULL);
+ XtAddCallback(old_sample, XmNactivateCallback, revert_color_cb, cinfo);
+ XmStringFree(str);
+ str = XmStringCreateLocalized("New");
+ new_sample = XtVaCreateManagedWidget("new_sample", xmPushButtonWidgetClass,
+ button_row,
+ XmNbackground, cinfo->new_color.pixel,
+ XmNlabelString, str,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 1,
+ NULL);
+ XmStringFree(str);
+ XtInsertEventHandler(new_sample,
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask| PointerMotionHintMask |
+ ButtonMotionMask | FocusChangeMask,
+ True, block_event_callback,
+ (XtPointer)0, 0);
+ cinfo->new_sample = new_sample;
+
+ color_matrix = h_create_color_matrix(form, button_row, cinfo);
+
+ h_create_sliders(form, color_matrix, cinfo);
+
+ XtManageChild(form);
+
+ XtAddCallback(dialog, XmNokCallback, popdown_apply_cb, prefs);
+ XtAddCallback(dialog, XmNcancelCallback, popdown_cancel_cb, prefs);
+
+ XtManageChild(dialog);
+
+ add_to_deplist(prefs, dialog);
+
+/* h_create_commands(shell, color_globals.widgets.paned, "OK", "Cancel", cinfo); */
+
+/* XtManageChild(color_globals.widgets.paned); */
+
+/* XtRealizeWidget(shell); */
+
+ TipAddWidget(tip_shell, old_sample, "Click to revert to old color");
+ /* TipAddWidget(tip_shell, color_matrix, "Select color"); */
+
+ WM_DELETE_WINDOW = XmInternAtom(DISP, "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, popdown_cb, prefs);
+
+ return dialog;
+}
+
+void
+popup_color_dialog(Widget parent, struct color_button_info *button_info)
+{
+ static Widget shell;
+ static Boolean first_time = True;
+ /* Must be static so that we can pass its address around */
+ static struct color_info cinfo;
+ struct topic_info *tinfo = button_info->tinfo;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+
+ cinfo.button_info = button_info;
+
+ if (first_time) {
+ shell = h_create_shell(parent, &cinfo);
+ first_time = False;
+ }
+ else {
+ /* Already created, but we may need to change the colors of old_sample
+ and new_sample. This is done by changing the value of old_sample and
+ invoking its activate callback, which will `revert' new_sample to
+ the same color. */
+ Widget w;
+ if (get_widget_by_name(&w, shell, Xdvi_COLOR_DIALOG_OLD_SAMPLE_NAME, True)) {
+#if XmVersion >= 1002
+ XmChangeColor(w, cinfo.button_info->pixel);
+#else
+ XtVaSetValues(w, XmNbackground, cinfo.button_info->pixel, NULL);
+#endif
+ XtCallCallbacks(w, XmNactivateCallback, &cinfo);
+ }
+ add_to_deplist(prefs, shell);
+ XtManageChild(shell);
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_colorsel.h b/Build/source/texk/xdvik/gui/xm_colorsel.h
new file mode 100644
index 00000000000..bb4bd38b94a
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_colorsel.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_COLORSEL_H_
+#define XM_COLORSEL_H_
+
+#ifdef MOTIF
+
+struct prefs_choice;
+struct topic_info;
+
+struct color_button_info {
+ Widget w; /* current button */
+ Pixel pixel; /* label color of this button */
+ const char *resource_name; /* resource name to save this color to */
+ struct topic_info *tinfo;
+};
+
+void popup_color_dialog(Widget parent, struct color_button_info *cinfo);
+
+#endif /* MOTIF */
+
+#endif /* XM_COLORSEL_H_ */
diff --git a/Build/source/texk/xdvik/gui/xm_filesel.c b/Build/source/texk/xdvik/gui/xm_filesel.c
new file mode 100644
index 00000000000..e5475f0bbe5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_filesel.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki 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.
+ *
+ */
+
+/*
+ * Implementation of the File selection dialogue for the Motif GUI.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "sfSelFile.h"
+
+#include "dvi.h"
+#include "string-utils.h"
+#include "util.h"
+#include "events.h"
+#include "message-window.h"
+#include "dvi-init.h" /* for dviErrFlagT */
+
+#if defined(MOTIF) /* entire file */
+
+#include <Xm/FileSB.h>
+
+static Widget dialog = NULL;
+static char *browse_fname = NULL;
+
+/*
+ * Process callback from Dialog cancel actions.
+ */
+static void
+cancel_callback(Widget w,
+ XtPointer client_data,
+ XtPointer call_data)
+{
+ struct filesel_callback *callback = (struct filesel_callback *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+#if 0
+ /* DON'T reset browse_fname, so that user gets the current
+ value as default next time when he cancels now */
+ if (browse_fname != NULL)
+ {
+ XtFree(browse_fname);
+ browse_fname = NULL;
+ }
+#endif
+
+ XtUnmanageChild(dialog);
+ if (callback->exit_on_cancel) {
+ exit(0);
+ }
+}
+
+/*
+ * Process callback from Dialog actions.
+ */
+
+static void
+accept_callback(Widget w,
+ XtPointer client_data,
+ XtPointer call_data)
+{
+ XmFileSelectionBoxCallbackStruct *fcb;
+ struct filesel_callback *callback;
+
+ UNUSED(w);
+
+ ASSERT(client_data != NULL, "struct filesel_callback pointer expected in client data");
+ callback = (struct filesel_callback *)client_data;
+
+ if (browse_fname != NULL) {
+ XtFree(browse_fname);
+ browse_fname = NULL;
+ }
+ fcb = (XmFileSelectionBoxCallbackStruct *)call_data;
+
+ /* get the filename from the file selection box */
+ XmStringGetLtoR(fcb->value, G_charset, &browse_fname);
+
+ if (callback->must_exist) {
+ FILE *tmp_fp = XFOPEN(browse_fname, "r");
+ dviErrFlagT errflag = NO_ERROR;
+ if (tmp_fp == NULL) {
+ popup_message(XtParent(dialog),
+ MSG_ERR, NULL, "Could not open %s: %s.\n",
+ browse_fname, strerror(errno));
+ /* leave file selection box open */
+ return;
+ }
+ else if (!process_preamble(tmp_fp, &errflag)
+ || !find_postamble(tmp_fp, &errflag)
+ || !read_postamble(tmp_fp, &errflag, True)) {
+ popup_message(XtParent(dialog),
+ MSG_ERR, NULL, "Error opening %s:\n%s.",
+ browse_fname, get_dvi_error(errflag));
+ fclose(tmp_fp);
+ /* leave file selection box open */
+ return;
+ }
+ else { /* file is OK */
+ fclose(tmp_fp);
+ }
+ }
+
+ /* success; close dialog, and call our callback */
+ XtUnmanageChild(dialog);
+ callback->func_ptr(browse_fname, callback->data);
+}
+
+void raise_file_selector(void)
+{
+ /* dummy */
+ return;
+}
+
+void
+XsraSelFile(Widget parent, struct filesel_callback *callback)
+{
+#define ARG_CNT 4
+ XmString filemask = NULL;
+ XmString directory = NULL;
+ Arg args[ARG_CNT];
+ int i = 0;
+
+ if (dialog == NULL) {
+ dialog = XmCreateFileSelectionDialog(parent, "file", NULL, 0);
+ /* Set ret_dialog to the DialogShell parent, not the command widget
+ returned by the Motif routines. We need the DialogShell, otherwise
+ Motif will crash if ret_dialog is used as parent for popup_message()
+ windows!!!
+ */
+ XtVaSetValues(XtParent(dialog), XmNtitle, callback->title, NULL);
+
+ /* my_must_exist = must_exist; */
+ /* XtAddCallback(dialog, XmNokCallback, accept_callback, (XtPointer)&my_must_exist); */
+ XtAddCallback(dialog, XmNokCallback, accept_callback, (XtPointer)callback);
+ XtAddCallback(dialog, XmNcancelCallback, cancel_callback, (XtPointer)callback);
+ /* We have no help in this window, so hide help button */
+ XtUnmanageChild(XmFileSelectionBoxGetChild(dialog, (unsigned char)XmDIALOG_HELP_BUTTON));
+ }
+ else if (XtIsManaged(dialog)) {
+ XBell(DISP, 10);
+ XRaiseWindow(DISP, XtWindow(dialog));
+ return;
+ }
+
+ /* only show files matching our mask */
+ filemask = XmStringCreateLtoR((char *)callback->filemask, G_charset);
+ XtSetArg(args[i], XmNpattern, filemask); i++;
+
+ /* set directory to last directory used */
+ if (browse_fname != NULL) {
+ char *path = xstrdup(browse_fname);
+ char *ptr = strrchr(path, '/');
+ if (ptr != NULL)
+ *ptr = '\0';
+ directory = XmStringCreateLtoR(path, G_charset);
+ XtSetArg(args[i], XmNdirectory, directory); i++;
+ free(path);
+ }
+
+ ASSERT(i < ARG_CNT, "args list too short");
+ XtSetValues(dialog, args, (Cardinal)i);
+
+ free(filemask);
+ free(directory);
+
+ XtManageChild(dialog);
+#undef ARG_CNT
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/xm_menu.c b/Build/source/texk/xdvik/gui/xm_menu.c
new file mode 100644
index 00000000000..51a2bedbd53
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_menu.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki 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.
+ *
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "xm_menu.h"
+#include "xm_toolbar.h"
+#include "my-snprintf.h"
+#include "util.h"
+#include "x_util.h"
+#include "version.h"
+#include "statusline.h"
+#include "pagehist.h"
+#include "dvi-init.h"
+#include "filehist.h"
+#include "c-openmx.h"
+#include "message-window.h"
+
+#ifdef MOTIF /* needed for `make depend' */
+
+#include <Xm/RowColumn.h>
+#include <Xm/Frame.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/CascadeBG.h>
+#include <Xm/SeparatoG.h>
+#include <Xm/ToggleB.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Separator.h>
+
+
+/*
+ * There's an apparent bug in Motif related to the interaction between
+ * the menubar menus and the magnifier.
+ *
+ * If you click on a menu on the menubar and then click on the drawing
+ * widget to pop up a magnifier, the keyboard and pointer are still
+ * grabbed, leading to a weird situation in which the magnifier stays
+ * around even after you release the pointer. The ungrab_serial
+ * counter works around this bug by ignoring such pointer events.
+ *
+ * This bug occurs in Motif 1.2 and OpenMotif 2.2.2 (at least). It
+ * does not occur in Lesstif.
+ */
+static unsigned long ungrab_event_num = 0;
+
+void
+popdown_callback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ /* Lesstif gives call_data == NULL */
+ if (call_data != NULL && *((XtGrabKind *) call_data) != XtGrabNone) {
+ ungrab_event_num = LastKnownRequestProcessed(DISP);
+ }
+}
+
+Boolean
+pulldown_menu_active(unsigned long event_num)
+{
+ return event_num < ungrab_event_num;
+}
+
+
+void
+toggle_menubar(void)
+{
+ if ((resource.expert_mode & XPRT_SHOW_MENUBAR) == 0)
+ XtUnmanageChild(globals.widgets.menu_bar);
+ else
+ XtManageChild(globals.widgets.menu_bar);
+}
+
+static void
+update_menu_labels(Widget menu)
+{
+ WidgetList children;
+ int num_children;
+ int i;
+
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+
+ XtVaGetValues(menu,
+ XmNnumChildren, &num_children,
+ XmNchildren, &children,
+ NULL);
+
+/* for (i = 0; i < num_children; i++) { */
+ for (i = 0; i < (int)file_history_size(); i++) {
+ int dummy_page;
+ char *filename;
+ size_t new_len;
+ XmString str;
+
+ if ((filename = file_history_get_elem(i, &dummy_page)) == NULL) {
+ XDVI_ERROR((stderr, "Error accessing element %d of file history", i));
+ continue;
+ }
+
+ new_len = LENGTH_OF_INT + strlen(filename) + 1;
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ sprintf(buf, "%d %s", i + 1, filename);
+ str = XmStringCreateLocalized(buf);
+ XtVaSetValues(children[i],
+ XmNlabelString, str,
+ NULL);
+ if (i + 1 < 10) {
+ XtVaSetValues(children[i], XmNmnemonic, buf[0], NULL);
+ }
+ XmStringFree(str);
+ }
+
+ /* if history size < number of menu entries, destroy excess menu entries */
+ for (; i < num_children; i++) {
+ XtDestroyWidget(children[i]);
+ }
+}
+
+static void
+filehist_select_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget menu;
+ XmString label;
+ char *label_ptr;
+ int pageno;
+ char *fname;
+ int idx;
+
+/* UNUSED(w); */
+ UNUSED(call_data);
+ UNUSED(client_data);
+
+ XtVaGetValues(w,
+ XmNuserData, &menu,
+ XmNlabelString, &label,
+ NULL);
+
+ XmStringGetLtoR(label, G_charset, &label_ptr);
+ idx = strtol(label_ptr, (char **)NULL, 10) - 1;
+ XtFree(label_ptr);
+
+ ASSERT(menu != NULL, "XmNuserData in filehist_select_cb musn't be NULL!");
+
+ if (idx == 0) { /* user re-selected current file: reload */
+ globals.ev.flags |= EV_RELOAD;
+ return;
+ }
+ if ((fname = file_history_get_elem(idx, &pageno)) == NULL) {
+ statusline_print(STATUS_MEDIUM, "Error accessing file %d of history", idx);
+ return;
+ }
+
+ file_history_open(fname);
+}
+
+void
+filehist_menu_refresh(void)
+{
+ Widget menu;
+ if (get_widget_by_name(&menu, globals.widgets.menu_bar, Xdvi_FILEHIST_MENU, True)) {
+ update_menu_labels(menu);
+ }
+}
+
+void
+filehist_menu_add_entry(const char *filename)
+{
+ Widget menu;
+
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ if (get_widget_by_name(&menu, globals.widgets.menu_bar, Xdvi_FILEHIST_MENU, True)) {
+ int num_children;
+ Widget w;
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ XtVaGetValues(menu, XmNnumChildren, &num_children, NULL);
+
+ sprintf(buf, "%d %s", num_children + 1, filename);
+
+ w = XtVaCreateManagedWidget(buf, xmPushButtonGadgetClass, menu,
+ XmNuserData, menu,
+ NULL);
+ if (num_children + 1 < 10) {
+ XtVaSetValues(w, XmNmnemonic, buf[0], NULL);
+ }
+ XtAddCallback(w, XmNactivateCallback, filehist_select_cb, (XtPointer)(num_children + 1));
+
+ update_menu_labels(menu);
+
+ }
+}
+
+static void
+filehist_submenu(int idx, const char *filename, int pageno, void *data)
+{
+ Widget menu = (Widget)data;
+ Widget w;
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ UNUSED(pageno);
+
+ sprintf(buf, "%d %s", idx + 1, filename);
+ TRACE_GUI((stderr, "Creating menu `%s'", buf));
+ w = XtVaCreateManagedWidget(buf, xmPushButtonGadgetClass, menu,
+/* XmNmnemonic, buf[0], */
+ XmNuserData, menu,
+ NULL);
+ if (idx + 1 < 10) {
+ XtVaSetValues(w, XmNmnemonic, buf[0], NULL);
+ }
+ XtAddCallback(w, XmNactivateCallback, filehist_select_cb, (XtPointer)idx);
+}
+
+
+
+static Widget
+recent_files_submenu(Widget parent, char *title, char mnemonic)
+{
+ Widget menu = 0, cascade = 0;
+ XmString str;
+
+ menu = XmCreatePulldownMenu(parent, Xdvi_FILEHIST_MENU, NULL, 0);
+ str = XmStringCreateLocalized(title);
+ cascade = XtVaCreateManagedWidget(title, xmCascadeButtonGadgetClass, parent,
+ XmNsubMenuId, menu,
+ XmNlabelString, str,
+ XmNmnemonic, mnemonic,
+ NULL);
+ XmStringFree(str);
+
+ file_history_enumerate(filehist_submenu, menu);
+ return cascade;
+}
+
+Widget
+xm_create_menu(Widget parent, char *title, char mnemonic, struct button_info *item)
+{
+ Widget menu = 0, cascade = 0, w = 0;
+ size_t i;
+ XmString str;
+
+ menu = XmCreatePulldownMenu(parent, "_pulldown", NULL, 0);
+ str = XmStringCreateLocalized(title);
+ cascade = XtVaCreateManagedWidget(title, xmCascadeButtonGadgetClass, parent,
+ XmNsubMenuId, menu,
+ XmNlabelString, str,
+ XmNmnemonic, mnemonic,
+ NULL);
+ XmStringFree(str);
+
+ /* add the menu items */
+ for (i = 0; item != NULL && i < item->size; i++) {
+ item->elems[i].widget = 0;
+ /* if there's a subitem, call this function recursively */
+ if (item->elems[i].submenu != NULL) {
+ w = xm_create_menu(menu, item->elems[i].title,
+ item->elems[i].mnemonic, item->elems[i].submenu);
+ /*
+ workaround for pointer grabbing bug; add additional callback to all menus
+ (they have the same parent)
+ */
+ XtAddCallback(XtParent(menu), XtNpopdownCallback,
+ popdown_callback, (XtPointer) 0);
+ }
+ else if (item->elems[i].action != NULL && item->elems[i].action->proc == Act_recent_files) {
+ /* special case: submenu with recent files */
+ w = recent_files_submenu(menu, item->elems[i].title, item->elems[i].mnemonic);
+ XtAddCallback(XtParent(menu), XtNpopdownCallback,
+ popdown_callback, (XtPointer) 0);
+ }
+ else {
+ switch(item->elems[i].type) {
+ case BT_PUSH:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmPushButtonGadgetClass, menu,
+ NULL);
+ break;
+ case BT_RADIO:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmToggleButtonGadgetClass, menu,
+ XmNindicatorType, XmONE_OF_MANY,
+ NULL);
+ break;
+ case BT_CHECK:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmToggleButtonGadgetClass, menu,
+ XmNindicatorType, XmN_OF_MANY,
+ NULL);
+ break;
+ case BT_SEP:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmSeparatorGadgetClass, menu,
+ NULL);
+ break;
+ default:
+ XDVI_WARNING((stderr, "unrecognized button type %d in menu %s (skipping this item).\n",
+ item->elems[i].type, item->elems[i].title));
+ break;
+ }
+ item->elems[i].widget = w;
+ }
+
+ if (item->elems[i].mnemonic != 0)
+ XtVaSetValues(w, XmNmnemonic, item->elems[i].mnemonic, NULL);
+
+ if (item->elems[i].accelerator != NULL) {
+ str = XmStringCreateLocalized(item->elems[i].accelerator);
+ XtVaSetValues(w, XmNacceleratorText, str, NULL);
+ XmStringFree(str);
+ }
+
+ if (item->elems[i].action != NULL) {
+ String cb_type;
+ if (XmIsToggleButton(w) || XmIsToggleButtonGadget(w))
+ cb_type = XmNvalueChangedCallback;
+ else
+ cb_type = XmNactivateCallback;
+ XtAddCallback(w, cb_type, handle_command, item->elems[i].action);
+ }
+ }
+ return cascade;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_menu.h b/Build/source/texk/xdvik/gui/xm_menu.h
new file mode 100644
index 00000000000..28dab3a384e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_menu.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_MENU_H_
+#define XM_MENU_H_
+
+#include "menu.h"
+
+#ifdef MOTIF
+
+#define Xdvi_FILEHIST_MENU "filehist_menu"
+
+extern Widget xm_create_menu(Widget parent, char *title, char mnemonic,
+ struct button_info *item);
+
+extern Boolean pulldown_menu_active(unsigned long event_num);
+extern void toggle_menubar(void);
+extern void popdown_callback(Widget w, XtPointer client_data, XtPointer call_data);
+extern void filehist_menu_add_entry(const char *filename);
+extern void filehist_menu_refresh(void);
+
+#endif
+
+#endif /* XM_MENU_H_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs.c b/Build/source/texk/xdvik/gui/xm_prefs.c
new file mode 100644
index 00000000000..388ef07ac12
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Preferences dialog for xdvik.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "message-window.h"
+#include "util.h"
+#include "events.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs.h"
+
+#include "xm_prefs_appearance.h"
+#include "xm_prefs_fonts.h"
+#include "xm_prefs_helpers.h"
+#include "xm_prefs_page.h"
+#include "xm_prefs_scroll.h"
+
+/* for reverting preferences, we need access to more prototypes ... */
+#include "dvi-draw.h"
+#include "search-internal.h"
+#include "statusline.h"
+#include "xm_toolbar.h"
+#include "xm_menu.h"
+#include "pagesel.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/Form.h>
+
+#define SCROLLING_DONE 0
+
+#define NUM_PREFS_TOPICS 16 /* should be ample ... */
+
+/* hmm, should maybe move these into xm_prefsP.c ... */
+void
+h_attach_below(Widget x, Widget y) {
+ if (y == NULL) {
+ /* no top widget, attach to form - could just pass NULL as XmNtopWidget, but lesstif warns in that case ... */
+ XtVaSetValues(x,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ }
+ else {
+ XtVaSetValues(x,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, y,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ }
+}
+
+
+static void
+initialize_items(struct topic_info *info)
+{
+ int i = 0;
+
+ info->items[i].widget = prefs_appearance(info);
+ info->items[i].topic = xstrdup("Appearance");
+ info->items[i].title = xstrdup("Change the appearance of xdvi");
+
+ i++;
+ info->items[i].widget = prefs_fonts_and_colors(info);
+ info->items[i].topic = xstrdup("Fonts and Colors");
+ info->items[i].title = xstrdup("Display of fonts and colors in DVI files");
+
+ i++;
+ info->items[i].widget = prefs_paper(info);
+ info->items[i].topic = xstrdup("Page Size");
+ info->items[i].title = xstrdup("Customize the default window and page size");
+
+#if SCROLLING_DONE /* not finished yet */
+ i++;
+ info->items[i].widget = prefs_scrolling(info);
+ info->items[i].topic = xstrdup("Scrolling");
+ info->items[i].title = xstrdup("Customize the scrolling behaviour when switching pages");
+#endif
+
+ i++;
+ info->items[i].widget = prefs_helpers(info);
+#ifdef LESSTIF_VERSION
+ /* compensate for width computation bug by adding extra whitespace at end */
+ info->items[i].topic = xstrdup("Helper Applications ");
+#else
+ info->items[i].topic = xstrdup("Helper Applications");
+#endif
+ info->items[i].title = xstrdup("External programs used by xdvi");
+
+ /* terminate */
+ i++;
+ info->items[i].widget = 0;
+ info->items[i].topic = info->items[i].title = NULL;
+
+ ASSERT(i < NUM_PREFS_TOPICS, "NUM_PREFS_TOPICS too small!");
+}
+
+void
+remove_from_deplist(struct prefs_choice *prefs, Widget w)
+{
+ size_t i;
+ Boolean found = False;
+
+ /* locate this widget */
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ if (prefs->depwin[i] == w) {
+ found = True;
+ break;
+ }
+ }
+
+ if (found) {
+ /* move later widgets down */
+ for (; i < prefs->depwin_cnt - 1; i++) {
+ prefs->depwin[i] = prefs->depwin[i + 1];
+ }
+ prefs->depwin_cnt--;
+ }
+
+#if 0
+ fprintf(stderr, "deplist after removal:\n");
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ fprintf(stderr, "%d: %p\n", i, prefs->depwin[i]);
+ }
+#endif
+}
+
+static void
+update_button(Widget button, Pixel pix)
+{
+ struct color_button_info *cinfo;
+ static XmDrawnButtonCallbackStruct cbs;
+
+ XtVaGetValues(button, XmNuserData, &cinfo, NULL);
+ cinfo->pixel = pix;
+ cbs.reason = XmCR_EXPOSE;
+ XtCallCallbacks(button, XmNexposeCallback, &cbs);
+}
+
+static void
+update_button_by_name(Pixel pix, const char *name)
+{
+ static Widget pref_shell = 0;
+ Widget button;
+
+ if (pref_shell == 0
+ && !get_widget_by_name(&pref_shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, True))
+ return;
+
+ if (get_widget_by_name(&button, pref_shell, name, True)) {
+ update_button(button, pix);
+ }
+}
+
+static Boolean
+revert_colors(Pixel fg, Pixel bg, Pixel hl)
+{
+ XColor color_data[2];
+ Boolean need_redraw = False;
+ Widget button;
+ Pixel visited, unvisited;
+
+ color_data[0].pixel = resource.fore_Pixel;
+ color_data[1].pixel = resource.back_Pixel;
+
+ str_to_pixel(globals.widgets.top_level, resource.visited_link_color, &visited);
+ str_to_pixel(globals.widgets.top_level, resource.link_color, &unvisited);
+
+ XQueryColors(DISP, G_colormap, color_data, 2);
+
+ if (fg != resource.fore_Pixel) {
+ XGCValues values;
+
+ fg_initial.r = color_data[0].red;
+ fg_initial.g = color_data[0].green;
+ fg_initial.b = color_data[0].blue;
+
+ values.foreground = resource.rule_pixel = resource.fore_Pixel;
+ XChangeGC(DISP, globals.gc.ruler, GCForeground, &values);
+
+ scanned_page = scanned_page_color = scanned_page_reset;
+
+ update_button_by_name(resource.fore_Pixel, Xdvi_FG_COLOR_BTN);
+
+ need_redraw = True;
+ }
+ if (bg != resource.back_Pixel) {
+ bg_initial.r = color_data[1].red;
+ bg_initial.g = color_data[1].green;
+ bg_initial.b = color_data[1].blue;
+
+ scanned_page = scanned_page_color = scanned_page_reset;
+
+ update_button_by_name(resource.back_Pixel, Xdvi_BG_COLOR_BTN);
+
+ need_redraw = True;
+ }
+ if (hl != resource.hl_Pixel) {
+ XGCValues values;
+ values.foreground = resource.hl_Pixel;
+ XChangeGC(DISP, globals.gc.high, GCForeground, &values);
+ /* hack to update match GC: fake change in inverted property, redraw
+ so that GC is cleared, then change inverted property back */
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+ search_draw_inverted_regions();
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+
+ update_button_by_name(resource.hl_Pixel, Xdvi_HL_COLOR_BTN);
+
+ need_redraw = True;
+ }
+ /* NOTE: pixels for hyperlinks are not stored anywhere; just update always: */
+ if (get_widget_by_name(&button, globals.widgets.top_level, Xdvi_VISITED_LINKS_BTN, True)) {
+ update_button(button, visited);
+ h_update_hyperlinks(button, visited); /* this already triggers a redraw */
+ }
+ if (get_widget_by_name(&button, globals.widgets.top_level, Xdvi_UNVISITED_LINKS_BTN, True)) {
+ update_button(button, unvisited);
+ h_update_hyperlinks(button, unvisited); /* this already triggers a redraw */
+ }
+ return need_redraw;
+}
+
+static void
+revert_resources(void)
+{
+ Pixel curr_fg = resource.fore_Pixel;
+ Pixel curr_bg = resource.back_Pixel;
+ Pixel curr_hl = resource.hl_Pixel;
+ Boolean need_redraw = False;
+
+ /* save some old values */
+ int save_shrink = resource.shrinkfactor;
+
+ reload_app_resources();
+
+ /* revert from saved values */
+ resource.use_color = globals.curr_use_color;
+ resource.gamma = globals.curr_gamma;
+ resource.paper = globals.curr_paper;
+ resource.shrinkfactor = save_shrink;
+ do_set_shrinkfactor(resource.shrinkfactor, True);
+
+ update_preferences_darkness();
+
+ /* revert expert mode */
+ if (resource.expert)
+ resource.expert_mode = XPRT_SHOW_NONE;
+ update_expert_mode();
+
+ toggle_statusline();
+#ifndef MOTIF
+ if (!BROKEN_RECONFIG)
+ toggle_scrollbars();
+#else
+ toggle_scrollbars();
+#endif
+
+#ifdef MOTIF
+ toggle_pagelist();
+ toggle_toolbar();
+ toggle_menubar();
+#else
+ toggle_buttons();
+#endif
+
+ /* reset tooltips_wait_period, similar to TipAddWidget() in Tip.c */
+ resource.tooltips_wait_period = resource.tooltips_wait_period_bak;
+ if (resource.tooltips_wait_period < 0) {
+ resource.show_tooltips = False;
+ }
+ else if (!resource.show_tooltips) {
+ if (resource.tooltips_wait_period == 0)
+ resource.tooltips_wait_period = -1;
+ else
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+
+ update_preferences_expert();
+ update_preferences_tooltips();
+ update_preferences_search();
+
+ update_preferences_color();
+ update_preferences_hyperlinks();
+
+ update_preferences_windowsize();
+ update_preferences_shrink();
+ update_preferences_paper();
+
+ update_preferences_helpers();
+
+ need_redraw |= revert_colors(curr_fg, curr_bg, curr_hl);
+
+/* if (need_redraw) */
+ /* just reload it always, there's too many exceptions ...
+ redraw isn't always sufficient if file has colors. */
+ globals.ev.flags |= EV_RELOAD;
+
+}
+
+/* add widget w to list of dependent windows */
+void
+add_to_deplist(struct prefs_choice *prefs, Widget w)
+{
+#if 0
+ size_t i;
+#endif
+ prefs->depwin = xrealloc(prefs->depwin,
+ (prefs->depwin_cnt + 1) * sizeof *(prefs->depwin));
+ prefs->depwin[prefs->depwin_cnt] = w;
+ prefs->depwin_cnt++;
+
+#if 0
+ fprintf(stderr, "deplist after adding:\n");
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ fprintf(stderr, "%lu: %p\n", (unsigned long)i, prefs->depwin[i]);
+ }
+#endif
+}
+
+static void
+reread_prefs_cb(Window w)
+{
+ if (w != XtWindow(globals.widgets.top_level)) {
+ XChangeProperty(DISP, w,
+ atom_reread_prefs(), atom_reread_prefs(), 8,
+ PropModeReplace,
+ /* dummy values, since all the other instance needs to do is
+ reread the ~/.xdvirc.tmp file */
+ (unsigned char *)"Y", 1);
+ }
+}
+
+static void
+apply_prefs_cb(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ struct prefs_choice *prefs = (struct prefs_choice *)info->data;
+ size_t i;
+ Widget colorsel;
+
+ if (get_widget_by_name(&colorsel, globals.widgets.top_level, Xdvi_COLOR_DIALOG_NAME, False)) {
+ XtPopdown(XtParent(colorsel));
+ }
+
+ /* pop down dependent windows */
+ TRACE_GUI((stderr, "window count: %lu\n", (unsigned long)prefs->depwin_cnt));
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ TRACE_GUI((stderr, "popping down %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ if (XtIsRealized(prefs->depwin[i])) {
+ XtCallCallbacks(prefs->depwin[i], XmNcancelCallback, NULL);
+ XSync(DISP, True); /* wait for server to catch up */
+ if (XtIsRealized(prefs->depwin[i])) {
+ TRACE_GUI((stderr, "calling XmNokCallback of %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ XtCallCallbacks(prefs->depwin[i], XmNokCallback, NULL);
+ }
+ }
+ }
+ free(prefs->depwin);
+ prefs->depwin = NULL;
+ prefs->depwin_cnt = 0;
+
+ if (prefs->db == NULL) /* callback invoked multiple times? */
+ return;
+
+ merge_into_user_db(prefs->db); /* this destroys prefs->db */
+ prefs->db = NULL;
+
+ /* remember some current values */
+ free(globals.curr_paper);
+ if (resource.paper != NULL)
+ globals.curr_paper = xstrdup(resource.paper);
+
+ free(globals.curr_editor);
+ if (resource.editor != NULL)
+ globals.curr_editor = xstrdup(resource.editor);
+
+ free(globals.curr_browser);
+ if (resource.browser != NULL)
+ globals.curr_browser = xstrdup(resource.browser);
+
+/* fprintf(stderr, "set curr_browser to: |%s|\n", globals.curr_browser); */
+/* fprintf(stderr, "set curr_editor to: |%s|\n", globals.curr_editor); */
+
+ if (get_xdvi_window_id(False, NULL) && save_user_preferences(False)) {
+ /* if other instances of xdvi are running, make them reread the
+ changed preferences by writing them to ~/.xdvirc.tmp and having
+ them read that file; otherwise they would overwrite the file if
+ user quits them after the current instance.
+ */
+ get_xdvi_window_id(False, reread_prefs_cb);
+ }
+}
+
+static void
+revert_prefs_cb(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ struct prefs_choice *prefs = (struct prefs_choice *)info->data;
+ size_t i;
+
+ /* pop down dependent windows */
+ TRACE_GUI((stderr, "window count: %lu", (unsigned long)prefs->depwin_cnt));
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ TRACE_GUI((stderr, "popping down %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ if (XtIsRealized(prefs->depwin[i])) {
+ XtCallCallbacks(prefs->depwin[i], XmNcancelCallback, NULL);
+ XSync(DISP, True); /* wait for server to catch up */
+ if (XtIsRealized(prefs->depwin[i])) {
+ TRACE_GUI((stderr, "calling XmNokCallback of %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ XtCallCallbacks(prefs->depwin[i], XmNokCallback, NULL);
+ }
+ }
+ }
+ free(prefs->depwin);
+ prefs->depwin = NULL;
+ prefs->depwin_cnt = 0;
+
+ if (prefs->db == NULL) { /* callback invoked multiple times, or prefs not changed */
+ return;
+ }
+
+ revert_resources();
+
+ XrmDestroyDatabase(prefs->db);
+ prefs->db = NULL;
+}
+
+static void
+save_prefs_exit(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ apply_prefs_cb(info);
+ XtPopdown(info->shell);
+ XSync(DISP, False);
+ xdvi_exit(EXIT_SUCCESS);
+}
+
+static void
+no_save_prefs_exit(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ revert_prefs_cb(info);
+ XtPopdown(info->shell);
+ XSync(DISP, False);
+ xdvi_exit(EXIT_SUCCESS);
+}
+
+static void
+close_prefs_exit(Widget w, XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ struct prefs_choice *prefs = (struct prefs_choice *)info->data;
+/* Widget dialog; */
+/* if (get_widget_by_name(&dialog, w, Xdvi_MESSAGE_DIALOG_NAME, True)) { */
+/* fprintf(stderr, "!!!!!!!!! removing window from deplist!\n"); */
+/* remove_from_deplist(prefs, dialog); */
+/* } */
+
+ remove_from_deplist(prefs, w);
+
+}
+
+Boolean
+preferences_changed(void)
+{
+ Widget prefs_shell = 0, topic_pane = 0;
+
+ if (get_widget_by_name(&prefs_shell, globals.widgets.top_level, "preferences_window", False)
+ && get_widget_by_name(&topic_pane, prefs_shell, "topic_pane", False)) {
+ struct topic_info *info = NULL;
+ struct prefs_choice *prefs = NULL;
+
+ XtVaGetValues(topic_pane, XmNuserData, &info, NULL);
+ if (info == NULL) {
+ return False;
+ }
+ prefs = (struct prefs_choice *)info->data;
+ if (prefs->db != NULL) { /* prefs changed */
+
+ Widget popup = choice3_dialog(prefs_shell,
+ MSG_QUESTION, NULL,
+#ifndef MOTIF
+ NULL,
+#endif
+ close_prefs_exit, info, /* pre_callbacks */
+ "Save and Exit", save_prefs_exit, info,
+ "Exit, don't Save", no_save_prefs_exit, info,
+ "Cancel", NULL, NULL,
+ "Preferences have been changed, but not saved yet. "
+ "Save them now?");
+ add_to_deplist(prefs, popup);
+ return True;
+ }
+ }
+
+ return False;
+}
+
+void
+popup_preferences_dialog(Widget parent, int arg)
+{
+ static Widget preferences_shell = 0;
+ static struct topic_info info;
+ static struct topic_item items[NUM_PREFS_TOPICS];
+ static struct prefs_choice *prefs = NULL;
+
+ if (preferences_shell == 0) { /* called 1st time; create widget */
+ info.ok_callback = apply_prefs_cb;
+ info.cancel_callback = revert_prefs_cb;
+ info.items = items;
+/* info.items_size = NUM_PREFS_TOPICS; */
+
+ prefs = xmalloc(sizeof *prefs);
+ prefs->depwin_cnt = 0;
+ prefs->depwin = NULL;
+/* prefs->orig = orig_prefs; */
+ /* apply_prefs_cb/revert_prefs_cb are responsible for copying
+ the changed preferences into the current preferences as
+ appropriate, and free()ing prefs.changed */
+/* prefs->changed = xmalloc(sizeof *(prefs->changed)); */
+/* copy_resources(orig_prefs, prefs->changed); */
+ prefs->db = NULL; /* XrmGetStringDatabase(""); */
+ info.data = prefs;
+
+ preferences_shell = create_topic_window(parent,
+ "xdvik: Preferences",
+ Xdvi_PREFS_DIALOG_NAME,
+ &info,
+ initialize_items,
+ "OK", "Cancel");
+ info.shell = preferences_shell;
+ center_window(preferences_shell, parent);
+ select_topic(&info, 0);
+ }
+
+ if (arg >= 0)
+ select_topic(&info, arg);
+
+ XtPopup(preferences_shell, XtGrabNone);
+
+ if (resource.no_init_file) {
+ popup_message(preferences_shell,
+ MSG_WARN,
+ NULL,
+ "You specified the resource `noInitFile' or the `-q' command-line option. "
+ "Any preferences that you set in this dialog will be lost when you exit xdvi.");
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs.h b/Build/source/texk/xdvik/gui/xm_prefs.h
new file mode 100644
index 00000000000..0fb4acee4b8
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_PREFS_H_
+#define XM_PREFS_H_
+
+#ifdef MOTIF
+
+#include "xm_prefsP.h"
+
+extern void popup_preferences_dialog(Widget parent, int arg);
+extern void copy_resources(const struct x_resources *source, struct x_resources *target);
+extern void remove_from_deplist(struct prefs_choice *prefs, Widget w);
+extern void add_to_deplist(struct prefs_choice *prefs, Widget w);
+extern Boolean preferences_changed(void);
+
+#endif
+
+#endif /* XM_PREFS_H_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefsP.h b/Build/source/texk/xdvik/gui/xm_prefsP.h
new file mode 100644
index 00000000000..3ec65ef9607
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefsP.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * `Private' common header for preferences dialogs.
+ */
+
+#ifndef XM_PREFS_P_H_
+#define XM_PREFS_P_H_
+
+#include "xdvi.h"
+#include "xdvi-config.h"
+
+#ifdef MOTIF
+/*
+ * For consistency when also using the names for XtNameToWidget() in callbacks
+ */
+/* widget names */
+#define Xdvi_PREFS_DIALOG_NAME "preferences_window"
+#define Xdvi_COLOR_DIALOG_NAME "color_dialog"
+#define Xdvi_COLOR_DIALOG_OLD_SAMPLE_NAME "old_sample"
+#define Xdvi_BROWSER_MENU_NAME "browser_menu"
+#define Xdvi_BROWSER_COMBO_NAME "browser_combo"
+#define Xdvi_EDITOR_MENU_NAME "editor_menu"
+#define Xdvi_EDITOR_COMBO_NAME "editor_combo"
+#define Xdvi_EDITOR_POPUP_NAME "editor_prompt"
+#define Xdvi_EDITOR_POPUP "editor_prompt_popup"
+#define Xdvi_BROWSER_POPUP_NAME "browser_prompt"
+#define Xdvi_BROWSER_POPUP "browser_prompt_popup"
+#define Xdvi_TIPS_STATUSLINE "tips_statusline"
+#define Xdvi_TIPS_POPUPS "tips_popups"
+#define Xdvi_TIPS_DELAY_TEXT "tips_delay_text"
+#define Xdvi_TIPS_DELAY_LABEL1 "tips_delay_label1"
+#define Xdvi_TIPS_DELAY_LABEL2 "tips_delay_label2"
+#define Xdvi_HOME_POSITION_X_OFF_TEXT "x_off_text"
+#define Xdvi_HOME_POSITION_Y_OFF_TEXT "y_off_text"
+#define Xdvi_HOME_POSITION_UNITS_MENU "units_menu"
+#define Xdvi_HOME_POSITION_UNITS_PULLDOWN "units_pulldown"
+#define Xdvi_DARKNESS_SPINBOX "darkness_spinbox"
+#define Xdvi_DARKNESS_TEXT "darkness_text"
+#define Xdvi_SHRINK_SPINBOX "shrink_spinbox"
+#define Xdvi_SHRINK_TEXT "shrink_text"
+#define Xdvi_PAPER_CASCADE "papersize_option"
+#define Xdvi_PAPER_MENU "papersize_menu"
+
+/* widget labels that are also used as widget names */
+#define Xdvi_TB_BUTTONS_FLAT_STR "Flat"
+#define Xdvi_TB_BUTTONS_RAISED_STR "Raised"
+#define Xdvi_GUI_STATUSLINE_STR "Show Statusline"
+#define Xdvi_GUI_TOOLBAR_STR "Show Toolbar"
+#define Xdvi_GUI_PAGELIST_STR "Show Pagelist"
+#define Xdvi_GUI_SCROLLBARS_STR "Show Scrollbars"
+#define Xdvi_MATCH_INVERTED_STR "Inverted"
+#define Xdvi_MATCH_BOXED_STR "Boxed with Highlight Color"
+#define Xdvi_FG_COLOR_STR "Text:"
+#define Xdvi_FG_COLOR_BTN "fg_button"
+#define Xdvi_BG_COLOR_STR "Background:"
+#define Xdvi_BG_COLOR_BTN "bg_button"
+#define Xdvi_HL_COLOR_BTN "hl_button"
+#define Xdvi_VISITED_LINKS_STR "Visited Links:"
+#define Xdvi_VISITED_LINKS_BTN "visited_links_button"
+#define Xdvi_UNVISITED_LINKS_STR "Unvisited Links:"
+#define Xdvi_UNVISITED_LINKS_BTN "unvisited_links_button"
+#define Xdvi_DOCUMENT_COLORS_STR "Use Document Colors"
+#define Xdvi_LINKS_UNDERLINED_STR "Underlined"
+#define Xdvi_ADD_COMMAND_STR "Other ..."
+#define Xdvi_SCROLL_KEEP_STR "Keep current position"
+#define Xdvi_SCROLL_UNKEEP_STR "Scroll back to home position of page"
+#define Xdvi_HOME_POSITION_STR "Home position at:"
+#define Xdvi_HOME_POSITION_X_STR "x"
+#define Xdvi_HOME_POSITION_Y_STR "y"
+#define Xdvi_SCROLL_CURRENT_STR "Use current position as home position"
+#define Xdvi_REMEMBER_WINDOWSIZE_STR "Remember current window size"
+#define Xdvi_PAPER_PORTRAIT_STR "Portrait"
+#define Xdvi_PAPER_LANDSCAPE_STR "Landscape"
+#define Xdvi_APPLY_STR "Apply"
+
+#define Xdvi_PREFS_BROWSER_DEFAULTS \
+ "mozilla -remote 'openURL(%s,new-window)'\n" \
+ "netscape -raise -remote 'openURL(%s,new-window)'\n" \
+ "xterm -e lynx %s\n" \
+ Xdvi_ADD_COMMAND_STR
+#define Xdvi_PREFS_EDITOR_DEFAULTS \
+ "gnuclient -q +%l %f\n" \
+ "emacsclient --no-wait +%l %f\n" \
+ "gvim --servername xdvi --remote +%l %f\n" \
+ "nc -noask +%l %f\n" \
+ "xterm -e vi +%l %f\n" \
+ Xdvi_ADD_COMMAND_STR
+
+struct prefs_choice {
+ XrmDatabase db;
+/* struct x_resources *orig; */
+/* struct x_resources *changed; */
+ Widget *depwin;
+ size_t depwin_cnt;
+};
+
+extern void h_attach_below(Widget x, Widget y);
+extern void h_update_hyperlinks(Widget w, Pixel pix); /* implemented in xm_prefs_fonts.c */
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_P_H_ */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_appearance.c b/Build/source/texk/xdvik/gui/xm_prefs_appearance.c
new file mode 100644
index 00000000000..b7f966059d5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_appearance.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Panel 1 (Apperance) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "my-snprintf.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "message-window.h"
+#include "util.h"
+#include "events.h"
+
+#include "xm_toolbar.h"
+#include "xm_menu.h"
+#include "statusline.h"
+#include "pagesel.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_appearance.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+
+/*
+ * Handy defaults
+ */
+static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
+static Arg n_of_many = { XmNindicatorType, XmN_OF_MANY };
+static Arg frame_title = { XmNchildType, XmFRAME_TITLE_CHILD };
+static Arg two_cols[] = {
+ { XmNpacking, XmPACK_TIGHT },
+ { XmNnumColumns, 2 },
+ { XmNorientation, XmHORIZONTAL }
+};
+static Arg two_cols_fixed[] = {
+ { XmNpacking, XmPACK_COLUMN },
+ { XmNnumColumns, 2 }
+};
+
+static void
+match_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ Widget inverted, boxed;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+
+ /* force a redraw so that a current match is updated if there was one */
+ globals.ev.flags |= EV_NEWPAGE;
+
+ store_preference(&(prefs->db), "matchInverted", "%s",
+ resource.match_highlight_inverted ? "True" : "False");
+
+ if (get_widget_by_name(&inverted, info->shell, Xdvi_MATCH_INVERTED_STR, True)
+ && get_widget_by_name(&boxed, info->shell, Xdvi_MATCH_BOXED_STR, True)) {
+
+ XmToggleButtonGadgetSetState(inverted, resource.match_highlight_inverted, False);
+ XmToggleButtonGadgetSetState(boxed, !resource.match_highlight_inverted, False);
+ }
+}
+
+static void
+tooltips_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ const char *w_name = XtName(w);
+
+ UNUSED(call_data);
+
+ if (strcmp(w_name, Xdvi_TIPS_STATUSLINE) == 0) {
+ resource.tooltips_in_statusline = !resource.tooltips_in_statusline;
+ store_preference(&(prefs->db), "tooltipsInStatusline", "%s",
+ resource.tooltips_in_statusline ? "True" : "False");
+ }
+ else if (strcmp(w_name, Xdvi_TIPS_POPUPS) == 0) {
+ Widget label1, text, label2;
+
+ resource.show_tooltips = !resource.show_tooltips;
+
+ if (!resource.show_tooltips && resource.tooltips_wait_period >= 0) {
+ if (resource.tooltips_wait_period == 0)
+ resource.tooltips_wait_period = -1;
+ else
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+ else if (resource.show_tooltips && resource.tooltips_wait_period < 0) {
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+ store_preference(&(prefs->db), "showTooltips", "%s", resource.show_tooltips ? "True" : "False");
+
+ if (get_widget_by_name(&label1, info->shell, Xdvi_TIPS_DELAY_LABEL1, True)
+ && get_widget_by_name(&text, info->shell, Xdvi_TIPS_DELAY_TEXT, True)
+ && get_widget_by_name(&label2, info->shell, Xdvi_TIPS_DELAY_LABEL2, True)) {
+
+ XtSetSensitive(label1, resource.show_tooltips);
+ XtSetSensitive(text, resource.show_tooltips);
+ XtSetSensitive(label2, resource.show_tooltips);
+ }
+ }
+ else if (strcmp(w_name, Xdvi_TIPS_DELAY_TEXT) == 0) {
+ char *buf = XmTextFieldGetString(w);
+ int val = strtol(buf, (char **)NULL, 10);
+ XtFree((char *)buf);
+ TRACE_GUI((stderr, "tooltips_cb wait period2: %d\n", val));
+
+ resource.tooltips_wait_period = val;
+ store_preference(&(prefs->db), "tipShell.waitPeriod", "%d", val);
+
+ }
+ else {
+ XDVI_WARNING((stderr, "unexpected widget name `%s' in tooltips_cb", XtName(w)));
+ }
+
+}
+
+#if 0
+static void
+toolbar_buttons_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct x_resources *res = (struct x_resources *)(info->data);
+ Boolean is_flat = False, is_raised = False;
+
+ Widget flat_b, raised_b;
+
+ UNUSED(call_data);
+
+ if (!get_widget_by_name(&flat_b, XtParent(w), TB_BUTTONS_FLAT_STR, True) ||
+ !get_widget_by_name(&raised_b, XtParent(w), TB_BUTTONS_RAISED_STR, True))
+ return;
+
+ if (w == flat_b) {
+ is_flat = True;
+ }
+ else if (w == raised_b) {
+ is_raised = True;
+ }
+ else {
+ unexpected_widget_in_callback(w, "toolbar_buttons_cb()");
+ return;
+ }
+
+ res->toolbar_buttons_raised = is_raised ? True : False;
+
+ XmToggleButtonGadgetSetState(raised_b, is_raised, False);
+ XmToggleButtonGadgetSetState(flat_b, is_flat, False);
+}
+#endif /* 0 */
+
+void update_preferences_expert(void)
+{
+ Widget shell;
+ Widget statusline_b, toolbar_b, pagelist_b, scrollbars_b;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&statusline_b, shell, Xdvi_GUI_STATUSLINE_STR, True)
+ && get_widget_by_name(&toolbar_b, shell, Xdvi_GUI_TOOLBAR_STR, True)
+ && get_widget_by_name(&pagelist_b, shell, Xdvi_GUI_PAGELIST_STR, True)
+ && get_widget_by_name(&scrollbars_b, shell, Xdvi_GUI_SCROLLBARS_STR, True)) {
+
+ XmToggleButtonGadgetSetState(statusline_b, resource.expert_mode & XPRT_SHOW_STATUSLINE ? True : False, False);
+ XmToggleButtonGadgetSetState(toolbar_b, resource.expert_mode & XPRT_SHOW_TOOLBAR ? True : False, False);
+ XmToggleButtonGadgetSetState(pagelist_b, resource.expert_mode & XPRT_SHOW_PAGELIST ? True : False, False);
+ XmToggleButtonGadgetSetState(scrollbars_b, resource.expert_mode & XPRT_SHOW_SCROLLBARS ? True : False, False);
+ }
+}
+
+void update_preferences_tooltips(void)
+{
+ Widget shell;
+ Widget statusline_b, popup_b, label1, text, label2;
+
+ if (resource.toolbar_unusable)
+ return;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, True)
+ && get_widget_by_name(&statusline_b, shell, Xdvi_TIPS_STATUSLINE, True)
+ && get_widget_by_name(&popup_b, shell, Xdvi_TIPS_POPUPS, True)
+ && get_widget_by_name(&label1, shell, Xdvi_TIPS_DELAY_LABEL1, True)
+ && get_widget_by_name(&text, shell, Xdvi_TIPS_DELAY_TEXT, True)
+ && get_widget_by_name(&label2, shell, Xdvi_TIPS_DELAY_LABEL2, True)) {
+
+ char buf[LENGTH_OF_INT];
+
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", ABS(resource.tooltips_wait_period));
+ XtVaSetValues(text, XmNvalue, buf, NULL);
+
+ XmToggleButtonGadgetSetState(statusline_b, resource.tooltips_in_statusline, False);
+ XmToggleButtonGadgetSetState(popup_b, resource.show_tooltips, False);
+
+ XtSetSensitive(label1, resource.show_tooltips);
+ XtSetSensitive(text, resource.show_tooltips);
+ XtSetSensitive(label2, resource.show_tooltips);
+ }
+}
+
+void update_preferences_search(void)
+{
+ Widget shell;
+ Widget inverted, boxed;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, True)
+ && get_widget_by_name(&inverted, shell, Xdvi_MATCH_INVERTED_STR, True)
+ && get_widget_by_name(&boxed, shell, Xdvi_MATCH_BOXED_STR, True)) {
+
+ XmToggleButtonGadgetSetState(inverted, resource.match_highlight_inverted, False);
+ XmToggleButtonGadgetSetState(boxed, !resource.match_highlight_inverted, False);
+ }
+}
+
+static void
+gui_buttons_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ char *name = XtName(w);
+
+ UNUSED(call_data);
+
+ if (strcmp(name, Xdvi_GUI_STATUSLINE_STR) == 0) {
+ resource.expert_mode ^= XPRT_SHOW_STATUSLINE;
+ toggle_statusline();
+ update_expert_mode();
+ }
+ else if (strcmp(name, Xdvi_GUI_TOOLBAR_STR) == 0) {
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ toggle_toolbar();
+ update_expert_mode();
+ }
+ else if (strcmp(name, Xdvi_GUI_PAGELIST_STR) == 0) {
+ resource.expert_mode ^= XPRT_SHOW_PAGELIST;
+ toggle_pagelist();
+ update_expert_mode();
+ }
+ else if (strcmp(name, Xdvi_GUI_SCROLLBARS_STR) == 0) {
+#if defined(LESSTIF_VERSION)
+ static Boolean warned_about_lesstif = False;
+#endif
+ resource.expert_mode ^= XPRT_SHOW_SCROLLBARS;
+ toggle_scrollbars();
+ update_expert_mode();
+#if defined(LESSTIF_VERSION)
+ if (!warned_about_lesstif) {
+ warned_about_lesstif = True;
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ NULL,
+ "This version has been compiled with LessTif; "
+ "toggling the scrollbars won't work with LessTif.");
+ }
+#endif
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "Unexpected label in gui buttons: |%s|!\n", name);
+ }
+ store_preference(&(prefs->db), "expertMode", "%d", resource.expert_mode);
+}
+
+
+#if 0
+static void
+toolbar_buttons_init(struct topic_info *info, Widget raised, Widget flat)
+{
+ Boolean is_flat = False, is_raised = False;
+ struct x_resources *res = (struct x_resources *)(info->data);
+
+ if (res->toolbar_buttons_raised)
+ is_raised = True;
+
+ XmToggleButtonGadgetSetState(raised, is_raised, False);
+ XmToggleButtonGadgetSetState(flat, is_flat, False);
+
+ XtAddCallback(flat, XmNvalueChangedCallback, toolbar_buttons_cb, (XtPointer)info);
+ XtAddCallback(raised, XmNvalueChangedCallback, toolbar_buttons_cb, (XtPointer)info);
+}
+#endif /* 0 */
+
+
+Widget
+prefs_appearance(struct topic_info *info)
+{
+ Widget form;
+ Widget gui_frame, gui_label, gui_rowcol,
+ gui_statusline, gui_toolbar, gui_pagelist, gui_scrollbars;
+ Widget tips_frame, tips_label, tips_form, tips_statusline;
+ Widget tips_popups, tips_delay_text, tips_delay_label1, tips_delay_label2;
+ Widget match_frame, match_label, match_rowcol, match_inverted, match_boxed;
+#if 0
+ Widget tb_buttons_frame, tb_buttons_label, tb_buttons_rowcol,
+ tb_buttons_flat, tb_buttons_raised;
+#endif
+ XmString str;
+ char buf[LENGTH_OF_INT];
+ Arg args[10];
+ int n;
+
+ form = XmCreateForm(info->right_form, "appearance_form", NULL, 0);
+ h_attach_below(form, NULL);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ gui_frame = XmCreateFrame(form, "gui_frame", args, n);
+ h_attach_below(gui_frame, NULL);
+
+ gui_label = XmCreateLabelGadget(gui_frame, "Window Configuration", &frame_title, 1);
+ XtManageChild(gui_label);
+
+ gui_rowcol = XmCreateRowColumn(gui_frame, "gui_rowcol", two_cols_fixed, XtNumber(two_cols_fixed));
+ XtManageChild(gui_rowcol);
+
+ gui_statusline = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_STATUSLINE_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_statusline, resource.expert_mode & XPRT_SHOW_STATUSLINE ? True : False, False);
+ XtManageChild(gui_statusline);
+
+ gui_toolbar = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_TOOLBAR_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_toolbar, resource.expert_mode & XPRT_SHOW_TOOLBAR ? True : False, False);
+ XtManageChild(gui_toolbar);
+
+ gui_pagelist = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_PAGELIST_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_pagelist, resource.expert_mode & XPRT_SHOW_PAGELIST ? True : False, False);
+ XtManageChild(gui_pagelist);
+
+ gui_scrollbars = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_SCROLLBARS_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_scrollbars, resource.expert_mode & XPRT_SHOW_SCROLLBARS ? True : False, False);
+ XtManageChild(gui_scrollbars);
+
+ XtAddCallback(gui_statusline, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+ XtAddCallback(gui_toolbar, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+ XtAddCallback(gui_pagelist, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+ XtAddCallback(gui_scrollbars, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ XtSetArg(args[n], XmNtopOffset, 10); n++;
+ tips_frame = XmCreateFrame(form, "tips_frame", args, n);
+ h_attach_below(tips_frame, gui_frame);
+
+ tips_label = XmCreateLabelGadget(tips_frame, "Show Tooltips", &frame_title, 1);
+ XtManageChild(tips_label);
+
+ tips_form = XmCreateForm(tips_frame, "tips_form", NULL, 0);
+
+ str = XmStringCreateLocalized("As Text in Statusline");
+ tips_statusline = XtVaCreateManagedWidget(Xdvi_TIPS_STATUSLINE,
+ xmToggleButtonGadgetClass, tips_form,
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNset, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ str = XmStringCreateLocalized("As Popups");
+ tips_popups = XtVaCreateManagedWidget(Xdvi_TIPS_POPUPS,
+ xmToggleButtonGadgetClass, tips_form,
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ str = XmStringCreateLocalized("with");
+ tips_delay_label1 = XtVaCreateManagedWidget(Xdvi_TIPS_DELAY_LABEL1,
+ xmLabelGadgetClass, tips_form,
+ XmNlabelString, tips_form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, tips_popups,
+ XmNleftOffset, 0, /* no spacing to prev text */
+ NULL);
+ XmStringFree(str);
+
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", ABS(resource.tooltips_wait_period));
+
+ tips_delay_text = XtVaCreateManagedWidget(Xdvi_TIPS_DELAY_TEXT,
+ xmTextFieldWidgetClass, tips_form,
+ XmNcolumns, 4,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, tips_delay_label1,
+ XmNvalue, buf,
+ NULL);
+
+ str = XmStringCreateLocalized("milliseconds delay");
+ tips_delay_label2 = XtVaCreateManagedWidget(Xdvi_TIPS_DELAY_LABEL2,
+ xmLabelGadgetClass, tips_form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, tips_delay_text,
+ NULL);
+
+ adjust_heights(tips_popups, tips_delay_label1, tips_delay_text, tips_delay_label2, NULL);
+
+ XmToggleButtonGadgetSetState(tips_statusline, resource.tooltips_in_statusline, False);
+ XmToggleButtonGadgetSetState(tips_popups, resource.show_tooltips, False);
+
+ if (resource.toolbar_unusable) {
+ XtSetSensitive(tips_frame, False);
+ }
+ else {
+ XtSetSensitive(tips_delay_label1, resource.show_tooltips);
+ XtSetSensitive(tips_delay_text, resource.show_tooltips);
+ XtSetSensitive(tips_delay_label2, resource.show_tooltips);
+
+ XtAddCallback(tips_statusline, XmNvalueChangedCallback, tooltips_cb, (XtPointer)info);
+ XtAddCallback(tips_popups, XmNvalueChangedCallback, tooltips_cb, (XtPointer)info);
+ XtAddCallback(tips_delay_text, XmNvalueChangedCallback, tooltips_cb, (XtPointer)info);
+ }
+
+#if 0
+ tb_buttons_frame = XmCreateFrame(form, "tb_buttons_frame", &v_off, 1);
+ h_attach_below(tb_buttons_frame, tips_frame);
+
+ tb_buttons_label = XmCreateLabelGadget(tb_buttons_frame, "Toolbar Buttons:", &frame_title, 1);
+ XtManageChild(tb_buttons_label);
+
+ tb_buttons_rowcol = XmCreateRowColumn(tb_buttons_frame, "tb_buttons_rowcol", two_cols, XtNumber(two_cols));
+ XtManageChild(tb_buttons_rowcol);
+
+ tb_buttons_raised = XmCreateToggleButtonGadget(tb_buttons_rowcol, "Raised", &one_of_many, 1);
+ XtManageChild(tb_buttons_raised);
+
+ tb_buttons_flat = XmCreateToggleButtonGadget(tb_buttons_rowcol, "Flat", &one_of_many, 1);
+ XtManageChild(tb_buttons_flat);
+ toolbar_buttons_init((XtPointer)info, tb_buttons_raised, tb_buttons_flat);
+#endif /* 0 */
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ XtSetArg(args[n], XmNtopOffset, 10); n++;
+ match_frame = XmCreateFrame(form, "match_frame", args, n);
+ XtVaSetValues(match_frame,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_frame,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ match_label = XmCreateLabelGadget(match_frame, "String Matches are shown:", &frame_title, 1);
+ XtManageChild(match_label);
+
+ match_rowcol = XmCreateRowColumn(match_frame, "tb_buttons_rowcol", two_cols, XtNumber(two_cols));
+ XtManageChild(match_rowcol);
+
+ match_inverted = XmCreateToggleButtonGadget(match_rowcol, Xdvi_MATCH_INVERTED_STR, &one_of_many, 1);
+ XtManageChild(match_inverted);
+
+ match_boxed = XmCreateToggleButtonGadget(match_rowcol, Xdvi_MATCH_BOXED_STR, &one_of_many, 1);
+ XtManageChild(match_boxed);
+
+ XmToggleButtonGadgetSetState(match_inverted, resource.match_highlight_inverted, False);
+ XmToggleButtonGadgetSetState(match_boxed, !resource.match_highlight_inverted, False);
+
+ XtAddCallback(match_inverted, XmNvalueChangedCallback, match_cb, (XtPointer)info);
+ XtAddCallback(match_boxed, XmNvalueChangedCallback, match_cb, (XtPointer)info);
+
+ /* manage children (order shouldn't matter, since children are already managed, but ...) */
+ XtManageChild(gui_frame);
+
+ XtManageChild(tips_form);
+ XtManageChild(tips_frame);
+
+#if 0
+ XtManageChild(tb_buttons_frame);
+#endif
+
+ XtManageChild(match_frame);
+
+ XtManageChild(form);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_appearance.h b/Build/source/texk/xdvik/gui/xm_prefs_appearance.h
new file mode 100644
index 00000000000..1c94a184d3c
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_appearance.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_PREFS_APPEARANCE_
+#define XM_PREFS_APPEARANCE_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_appearance(struct topic_info *info);
+extern void update_preferences_expert(void);
+extern void update_preferences_tooltips(void);
+extern void update_preferences_search(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_APPEARANCE_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_fonts.c b/Build/source/texk/xdvik/gui/xm_prefs_fonts.c
new file mode 100644
index 00000000000..bf25734bc50
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_fonts.c
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Panel 2 (Fonts and colors) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "events.h"
+#include "hypertex.h"
+#include "my-snprintf.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_fonts.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+
+#if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
+/* spinbox only available with Motif 2.0; the lesstif version (as of 0.93) looks like shit */
+#include <Xm/SpinB.h>
+#define USE_SPINBOX 1
+#else
+#define USE_SPINBOX 0
+#endif
+
+/*
+ * Handy defaults
+ */
+static Arg v_off = { XmNtopOffset, 10 };
+static Arg n_of_many = { XmNindicatorType, XmN_OF_MANY };
+static Arg frame_title = { XmNchildType, XmFRAME_TITLE_CHILD };
+
+
+static void
+underline_toggle_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs;
+ Boolean is_set;
+
+ UNUSED(call_data);
+
+ ASSERT(tinfo != NULL, "struct topic_info * in underline_toggle_cb mustn't be NULL!");
+ prefs = (struct prefs_choice *)tinfo->data;
+
+ XtVaGetValues(w, XmNset, &is_set, NULL);
+ if (is_set)
+ resource.link_style |= 1;
+ else
+ resource.link_style &= ~1;
+
+ store_preference(&(prefs->db), "linkStyle", "%d", resource.link_style);
+
+ /* update display */
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+static void
+colorspecial_toggle_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs;
+
+ UNUSED(w);
+/* UNUSED(client_data); */
+ UNUSED(call_data);
+
+ ASSERT(tinfo != NULL, "struct topic_info * in colorspecial_toggle_cb mustn't be NULL!");
+ prefs = (struct prefs_choice *)tinfo->data;
+
+ do_toggle_color(False);
+ store_preference(&(prefs->db), "color", "%s", resource.use_color ? "True" : "False");
+}
+
+static void
+darkness_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ char *text;
+ int val;
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+#if USE_SPINBOX
+ /* synchronize internal spinbox value. Apparently this loses the insertion position,
+ so we need to save it and set it again. */
+ XmTextPosition pos = XmTextFieldGetInsertionPosition(w);
+
+ UNUSED(call_data);
+ text = XmTextFieldGetString(w);
+ val = strtol(text, (char **)NULL, 10);
+
+ if (val != 0) {
+ XtVaSetValues(w, XmNposition, val, NULL);
+ XmTextFieldSetInsertionPosition(w, pos);
+ }
+#else
+ Widget text_field;
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNuserData, &text_field, NULL);
+ XtVaGetValues(text_field, XmNvalue, &text, NULL);
+ val = strtol(text, (char **)NULL, 10);
+#endif
+ if (XtIsRealized(w)) {
+ do_set_density(val / 100.0, True, False);
+ store_preference(&(prefs->db), "gamma", "%f", val / 100.0);
+ }
+ XtFree(text);
+}
+
+
+#if 0 /* currently unused */
+static void
+darkness_spinbox_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int val;
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNposition, &val, NULL);
+ if (XtIsRealized(w)) {
+ do_set_density(val / 100.0, True, False);
+ /* fprintf(stderr, "storing pref: %d\n", val); */
+ store_preference(&(prefs->db), "gamma", "%f", val / 100.0);
+ }
+
+}
+#endif /* currently unused */
+
+
+void
+h_update_hyperlinks(Widget w, Pixel pix)
+{
+ const char *name = XtName(w);
+ int type = 0;
+
+ if (strcmp(name, Xdvi_UNVISITED_LINKS_BTN) == 0) {
+ type = 1;
+ }
+ else if (strcmp(name, Xdvi_VISITED_LINKS_BTN) == 0) {
+ type = 2;
+ }
+
+ /* fprintf(stderr, "WIDGET: |%s|; type: %d\n", name, type); */
+
+ if (type != 0) {
+ GC new_gc = set_or_make_gc(NULL, GXcopy, pix, resource.back_Pixel);
+ GC old_gc;
+ double r, g, b;
+ double factor = 65535.0;
+ XColor color;
+
+ pixel_to_color(pix, &color, DISP, G_colormap);
+ r = color.red / factor;
+ g = color.green / factor;
+ b = color.blue / factor;
+
+ if (type == 1) {
+ old_gc = globals.gc.linkcolor;
+ sprintf(g_link_color_rgb, "push rgb %.2f %.2f %.2f", r, g, b);
+ }
+ else {
+ old_gc = globals.gc.visited_linkcolor;
+ sprintf(g_visited_link_color_rgb, "push rgb %.2f %.2f %.2f", r, g, b);
+ }
+
+ if (type == 1) {
+ globals.gc.linkcolor = new_gc;
+ XFreeGC(XtDisplay(w), old_gc);
+ }
+ else {
+ globals.gc.visited_linkcolor = new_gc;
+ XFreeGC(XtDisplay(w), old_gc);
+ }
+ /* update display */
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ }
+}
+
+static void
+redraw_or_push_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ XmDrawnButtonCallbackStruct *cbs = (XmDrawnButtonCallbackStruct *)call_data;
+ static GC border_gc = 0;
+ struct color_button_info *cinfo;
+ Pixel pix = (Pixel)client_data;
+
+ if (cbs == NULL) {
+ XDVI_WARNING((stderr, "cinfo mustn't be NULL in redraw_or_push_cb!\n"));
+ return;
+ }
+
+ /* this can also be called via XtCallCallbacks, without call_data */
+ if (cbs->reason == XmCR_EXPOSE) {
+ /* redraw button label */
+ Dimension high_thick, st, wd, ht;
+ Dimension inner_w, inner_h, off_x, off_y;
+ GC label_gc;
+ XGCValues values;
+
+ XtVaGetValues(w,
+ XmNhighlightThickness, &high_thick,
+ XmNshadowThickness, &st,
+ XmNwidth, &wd,
+ XmNheight, &ht,
+ XmNuserData, &cinfo,
+ NULL);
+
+ values.function = GXcopy;
+
+ if (border_gc == 0) {
+ /* create the static GC for drawing the border - Note: never free'd! */
+ values.foreground = BlackPixelOfScreen(XtScreen(w));
+ /* values.line_width = 2; */
+ /* note: never free'd! */
+ border_gc = XCreateGC(XtDisplay(w), XtWindow(w),
+ GCFunction | GCForeground /* | GCLineWidth */, &values);
+ }
+ values.foreground = cinfo->pixel;
+ label_gc = XCreateGC(XtDisplay(w), XtWindow(w),
+ GCFunction | GCForeground, &values);
+
+ off_x = high_thick + st + 4;
+ inner_w = wd - 2 * off_x;
+ off_y = high_thick + st + 4;
+ inner_h = ht - 2 * off_y;
+#if 0
+ fprintf(stderr, "shadow: %d, high: %d\n", st, high_thick);
+ fprintf(stderr, "width: %d, height: %d\n", wd, ht);
+ fprintf(stderr, "inner w: %d, inner h: %d\n", inner_w, inner_h);
+#endif
+
+ XFillRectangle(XtDisplay(w), XtWindow(w), label_gc,
+ off_x, off_y, inner_w, inner_h);
+ XDrawRectangle(XtDisplay(w), XtWindow(w), border_gc,
+ off_x - 1, off_y - 1, inner_w + 1, inner_h + 1);
+ XFreeGC(XtDisplay(w), label_gc);
+
+ if (pix != cinfo->pixel) {
+ h_update_hyperlinks(w, cinfo->pixel);
+ }
+ }
+ else if (cbs->reason == XmCR_ACTIVATE) {
+ /* pushed, open color dialog */
+ XtVaGetValues(w, XmNuserData, &cinfo, NULL);
+ if (cinfo != NULL) {
+ cinfo->w = w;
+ popup_color_dialog(globals.widgets.top_level, cinfo);
+ }
+ else {
+ XDVI_WARNING((stderr, "cinfo mustn't be NULL in redraw_or_push_cb!\n"));
+ return;
+ }
+ }
+ /* else, XmCR_RESIZE - nothing to do */
+}
+
+static Widget
+h_create_colorsample(Widget parent, Widget left,
+ const char *name,
+ const char *resource_name,
+ Pixel pix,
+ struct topic_info *info)
+{
+ struct color_button_info *cinfo = xmalloc(sizeof *cinfo); /* note: never free()d */
+ Widget button;
+
+ UNUSED(left);
+
+ cinfo->pixel = pix;
+ cinfo->tinfo = info;
+ cinfo->resource_name = xstrdup(resource_name); /* note: never free()d */
+
+ button = XtVaCreateManagedWidget(name, xmDrawnButtonWidgetClass, parent,
+ XtNwidth, 42,
+ XtNheight, 28,
+ XmNuserData, cinfo,
+ /* we want the normal button look here to
+ make it obvious that users can press it */
+ XmNshadowType, XmSHADOW_OUT,
+ XmNpushButtonEnabled, True,
+ NULL);
+ XtAddCallback(button, XmNactivateCallback, redraw_or_push_cb, (XtPointer)pix);
+ XtAddCallback(button, XmNexposeCallback, redraw_or_push_cb, (XtPointer)pix);
+ XtAddCallback(button, XmNresizeCallback, redraw_or_push_cb, (XtPointer)pix);
+
+ return button;
+}
+
+
+static Widget
+h_create_fonts_frame(Widget top, struct topic_info *info)
+{
+ Widget darkness_form, darkness_label;
+
+ UNUSED(info);
+
+ darkness_form = XmCreateForm(top, "darkness_form", NULL, 0);
+ XtVaSetValues(darkness_form,
+ XmNverticalSpacing, 10,
+ XmNhorizontalSpacing, 10,
+ NULL);
+
+
+ darkness_label = XmCreateLabelGadget(darkness_form, "Font Darkness: ", NULL, 0);
+ XtVaSetValues(darkness_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XtManageChild(darkness_label);
+ {
+ Widget darkness_text;
+#if USE_SPINBOX
+ Widget darkness_spinbox = XmCreateSpinBox(darkness_form, Xdvi_DARKNESS_SPINBOX, NULL, 0);
+ darkness_text = XmCreateTextField(darkness_spinbox, Xdvi_DARKNESS_TEXT, NULL, 0);
+ XtVaSetValues(darkness_spinbox,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, darkness_label,
+ XmNinitialDelay, 200,
+ XmNrepeatDelay, 50,
+ NULL);
+ XtVaSetValues(darkness_text,
+ XmNspinBoxChildType, XmNUMERIC,
+ XmNminimumValue, 0,
+ XmNmaximumValue, 1000,
+ XmNeditable, True,
+ XmNcolumns, 4,
+ XmNincrementValue, 1,
+ XmNwrap, False, /* too confusing */
+ XmNposition, (int)(resource.gamma * 100.0 + 0.5),
+ NULL);
+ XtAddCallback(darkness_text, XmNactivateCallback, darkness_text_cb, (XtPointer)info);
+ XtAddCallback(darkness_text, XmNvalueChangedCallback, darkness_text_cb, (XtPointer)info);
+
+ adjust_heights(darkness_spinbox, darkness_text, darkness_label, NULL);
+
+ XtManageChild(darkness_text);
+ XtManageChild(darkness_spinbox);
+#else
+ char buf[LENGTH_OF_INT];
+ Widget darkness_button;
+ darkness_text = XmCreateTextField(darkness_form, Xdvi_DARKNESS_TEXT, NULL, 0);
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", (int)(resource.gamma * 100.0 + 0.5));
+ XtVaSetValues(darkness_text,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, darkness_label,
+ XmNcolumns, 4,
+ XmNvalue, buf,
+ XmNuserData, darkness_text,
+ NULL);
+ XtOverrideTranslations(darkness_text, XtParseTranslationTable("<Key>Return:activate()"));
+ XtAddCallback(darkness_text, XmNactivateCallback, darkness_text_cb, (XtPointer)info);
+
+ darkness_button = XmCreatePushButton(darkness_form, Xdvi_APPLY_STR, NULL, 0);
+ XtVaSetValues(darkness_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, darkness_text,
+ XmNuserData, darkness_text,
+ NULL);
+ XtAddCallback(darkness_button, XmNactivateCallback, darkness_text_cb, (XtPointer)info);
+
+ adjust_heights(darkness_label, darkness_text, darkness_button, NULL);
+ XtManageChild(darkness_text);
+ XtManageChild(darkness_button);
+#endif
+ }
+
+/* XtManageChild(darkness_form); */
+
+ return darkness_form;
+}
+
+static Widget
+h_create_colors_form(Widget top, struct topic_info *info)
+{
+ Widget text_bg_frame, text_bg_label, text_bg_form;
+ Widget links_frame, links_label, links_form;
+ Widget fg_label, fg_button;
+ Widget bg_label, bg_button;
+ Widget unvisited_label, unvisited_button;
+ Widget visited_label, visited_button;
+ Widget underline_toggle;
+ Widget colorspecials_toggle;
+
+ Widget form = XmCreateForm(top, "colors_form", NULL, 0);
+ Pixel visited_link_pix, link_pix;
+
+ str_to_pixel(top, resource.visited_link_color, &visited_link_pix);
+ str_to_pixel(top, resource.link_color, &link_pix);
+
+ text_bg_frame = XmCreateFrame(form, "text_bg_frame", NULL, 0);
+ XtVaSetValues(text_bg_frame,
+ XmNmarginWidth, 10,
+ XmNmarginHeight, 10,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_POSITION,
+ XmNrightPosition, 50,
+ XmNrightOffset, 10,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ text_bg_label = XmCreateLabelGadget(text_bg_frame, "Text Color", &frame_title, 1);
+ XtManageChild(text_bg_label);
+
+ text_bg_form = XmCreateForm(text_bg_frame, "fg_form", NULL, 0);
+ XtVaSetValues(text_bg_form, XmNverticalSpacing, 2, NULL);
+
+ fg_label = XmCreateLabelGadget(text_bg_form, Xdvi_FG_COLOR_STR, NULL, 0);
+ fg_button = h_create_colorsample(text_bg_form, fg_label,
+ Xdvi_FG_COLOR_BTN, "foreground",
+ resource.fore_Pixel, info);
+ XtVaSetValues(fg_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtVaSetValues(fg_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ NULL);
+ adjust_heights(fg_label, fg_button, NULL);
+ XtManageChild(fg_label);
+ XtManageChild(fg_button);
+
+ bg_label = XmCreateLabelGadget(text_bg_form, Xdvi_BG_COLOR_STR, NULL, 0);
+ bg_button = h_create_colorsample(text_bg_form, bg_label,
+ Xdvi_BG_COLOR_BTN, "background",
+ resource.back_Pixel, info);
+ XtVaSetValues(bg_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, fg_label,
+ NULL);
+ XtVaSetValues(bg_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, fg_label,
+ NULL);
+ adjust_heights(bg_label, bg_button, NULL);
+ XtManageChild(bg_label);
+ XtManageChild(bg_button);
+
+ colorspecials_toggle = XmCreateToggleButtonGadget(text_bg_form, Xdvi_DOCUMENT_COLORS_STR, &n_of_many, 1);
+ XtVaSetValues(colorspecials_toggle,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, bg_label,
+ NULL);
+ XtManageChild(colorspecials_toggle);
+ XmToggleButtonGadgetSetState(colorspecials_toggle, resource.use_color, False);
+ XtAddCallback(colorspecials_toggle, XmNvalueChangedCallback, colorspecial_toggle_cb, (XtPointer)info);
+
+ links_frame = XmCreateFrame(form, "links_frame", NULL, 0);
+ XtVaSetValues(links_frame,
+ XmNmarginWidth, 10,
+ XmNmarginHeight, 10,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, text_bg_frame,
+ XmNleftOffset, 10,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ links_label = XmCreateLabelGadget(links_frame, "Hyperlinks", &frame_title, 1);
+ XtManageChild(links_label);
+
+ links_form = XmCreateForm(links_frame, "links_form", NULL, 0);
+ XtVaSetValues(links_form,
+ XmNverticalSpacing, 2,
+ NULL);
+
+ unvisited_label = XmCreateLabelGadget(links_form, Xdvi_UNVISITED_LINKS_STR, NULL, 0);
+ unvisited_button = h_create_colorsample(links_form, unvisited_label,
+ Xdvi_UNVISITED_LINKS_BTN, "linkColor",
+ link_pix, info);
+ XtVaSetValues(unvisited_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtVaSetValues(unvisited_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ adjust_heights(unvisited_label, unvisited_button, NULL);
+ XtManageChild(unvisited_label);
+ XtManageChild(unvisited_button);
+
+ visited_label = XmCreateLabelGadget(links_form, Xdvi_VISITED_LINKS_STR, NULL, 0);
+ visited_button = h_create_colorsample(links_form, visited_label,
+ Xdvi_VISITED_LINKS_BTN, "visitedLinkColor",
+ visited_link_pix, info);
+ XtVaSetValues(visited_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, unvisited_label,
+ NULL);
+ XtVaSetValues(visited_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, unvisited_label,
+ NULL);
+ adjust_heights(visited_label, visited_button, NULL);
+ XtManageChild(visited_label);
+ XtManageChild(visited_button);
+
+ underline_toggle = XmCreateToggleButtonGadget(links_form, Xdvi_LINKS_UNDERLINED_STR, &n_of_many, 1);
+ XtVaSetValues(underline_toggle,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, visited_label,
+ NULL);
+ XtManageChild(underline_toggle);
+
+/* if (res->link_style & 1) */
+ if (resource.link_style & 1)
+ XmToggleButtonGadgetSetState(underline_toggle, True, False);
+ else
+ XmToggleButtonGadgetSetState(underline_toggle, False, False);
+
+ XtAddCallback(underline_toggle, XmNvalueChangedCallback, underline_toggle_cb, (XtPointer)info);
+
+ XtManageChild(links_frame);
+ XtManageChild(text_bg_frame);
+
+ XtManageChild(text_bg_form);
+ XtManageChild(links_form);
+
+ return form;
+}
+
+void update_preferences_color(void)
+{
+ Widget shell, button;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&button, shell, Xdvi_DOCUMENT_COLORS_STR, True)) {
+ XmToggleButtonGadgetSetState(button, resource.use_color, False);
+ }
+}
+
+void update_preferences_hyperlinks(void)
+{
+ Widget shell, button;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&button, shell, Xdvi_LINKS_UNDERLINED_STR, True)) {
+ XmToggleButtonGadgetSetState(button, resource.link_style & 1 ? True : False, False);
+ }
+}
+
+void update_preferences_darkness(void)
+{
+ Widget shell, text;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&text, shell, Xdvi_DARKNESS_TEXT, True)) {
+
+ char buf[LENGTH_OF_INT];
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", (int)(resource.gamma * 100.0 + 0.5));
+#if USE_SPINBOX
+ XmTextFieldSetString(text, buf);
+ XtVaSetValues(text, XmNposition, (int)(resource.gamma * 100.0 + 0.5), NULL);
+#else
+ XtVaSetValues(text, XmNvalue, buf, NULL);
+#endif
+ }
+}
+
+Widget
+prefs_fonts_and_colors(struct topic_info *info)
+{
+ Widget form;
+ Widget colors_form;
+ Widget other_colors_frame, fonts_frame;
+
+ form = XmCreateForm(info->right_form, "fonts_colors_form", NULL, 0);
+ h_attach_below(form, NULL);
+
+ colors_form = h_create_colors_form(form, info);
+ h_attach_below(colors_form, NULL);
+ XtManageChild(colors_form);
+
+ { /* other colors - currently only highlight color */
+ Widget other_colors_form, other_colors_label;
+ Widget hl_color_text, hl_color_button;
+
+ other_colors_frame = XmCreateFrame(form, "other_colors_frame", &v_off, 1);
+ XtVaSetValues(other_colors_frame,
+ XmNmarginWidth, 10,
+ NULL);
+ h_attach_below(other_colors_frame, colors_form);
+
+ other_colors_label = XmCreateLabelGadget(other_colors_frame, "Highlight Color", &frame_title, 1);
+ other_colors_form = XmCreateForm(other_colors_frame, "other_colors_form", NULL, 0);
+ XtVaSetValues(other_colors_form, XmNverticalSpacing, 2, NULL);
+
+ hl_color_text = XmCreateLabelGadget(other_colors_form,
+#if defined(LESSTIF_VERSION) /* stupid LessTif doesn't wrap Labels at '\n' */
+ "Color of page border, rulers and bounding boxes.",
+#else
+ "Color used for page border, rulers in `ruler mode', and\n"
+ "bounding boxes for forward search and EPS images.",
+#endif
+ NULL, 0);
+ hl_color_button = h_create_colorsample(other_colors_form, hl_color_text,
+ Xdvi_HL_COLOR_BTN, "highlight",
+ resource.hl_Pixel, info);
+ XtVaSetValues(hl_color_text,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 10,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ XtVaSetValues(hl_color_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtManageChild(hl_color_text);
+ XtManageChild(hl_color_button);
+ XtManageChild(other_colors_form);
+ XtManageChild(other_colors_label);
+ XtManageChild(other_colors_frame);
+ }
+
+ fonts_frame = h_create_fonts_frame(form, info);
+ h_attach_below(fonts_frame, other_colors_frame);
+ XtManageChild(fonts_frame);
+
+ XtManageChild(form);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_fonts.h b/Build/source/texk/xdvik/gui/xm_prefs_fonts.h
new file mode 100644
index 00000000000..b87984cafb2
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_fonts.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_PREFS_FONTS_
+#define XM_PREFS_FONTS_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_fonts_and_colors(struct topic_info *info);
+extern void update_preferences_color(void);
+extern void update_preferences_hyperlinks(void);
+extern void update_preferences_darkness(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_FONTS_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_helpers.c b/Build/source/texk/xdvik/gui/xm_prefs_helpers.c
new file mode 100644
index 00000000000..493e061827f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_helpers.c
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Panel 3 (Helper Applications) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "string-utils.h"
+#include "message-window.h"
+#include "events.h"
+#include "xm_menu.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs.h"
+#include "xm_prefs_helpers.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/PushBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/FileSB.h>
+#include <Xm/SelectioB.h>
+
+struct choice_dialog_info {
+ struct topic_info *tinfo;
+ /* struct prefs_choice *prefs; */
+ Widget combo_box;
+ Widget message_popup;
+};
+
+static char **m_browser_list = NULL;
+static char **m_editor_list = NULL;
+
+/* "mozilla -remote 'openURL(%s,new-window)'", */
+/* "netscape -raise -remote 'openURL(%s,new-window)'", */
+/* "xterm -e lynx %s", */
+/* Xdvi_ADD_COMMAND_STR, */
+/* NULL /\* terminate *\/ */
+/* }; */
+
+/* static const char *editor_list[] = { */
+/* "gnuclient -q +%l %f", */
+/* "emacsclient --no-wait +%l %f", */
+/* "gvim --servername xdvi --remote +%l %f", */
+/* "nc -noask +%l %f", */
+/* "xterm -e vi +%l %f", */
+/* Xdvi_ADD_COMMAND_STR, */
+/* NULL /\* terminate *\/ */
+/* }; */
+
+/* combo box only available with Motif 2.0;
+ * the lesstif version is incomplete
+ */
+#if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
+#include <Xm/ComboBox.h>
+#include <Xm/List.h>
+#define USE_COMBOBOX 1
+#else
+#include <Xm/CascadeBG.h>
+#define USE_COMBOBOX 0
+#endif
+
+static void select_browser_cb(Widget w, XtPointer client_data, XtPointer call_data);
+static void select_editor_cb(Widget w, XtPointer client_data, XtPointer call_data);
+
+/*
+ * Helper functions
+ */
+static char *
+flatten_list(char **list, const char *sep)
+{
+ char *result = xstrdup("");
+ int i;
+
+ for (i = 0; list[i] != NULL; i++) {
+ result = xstrcat(result, list[i]);
+ result = xstrcat(result, sep);
+ }
+ return result;
+}
+
+static char **
+add_to_list(char **list, const char *str)
+{
+ int i, k;
+ /* reallocate with larger capacity */
+ for (i = 0; list[i] != NULL; i++) { ; }
+ i++;
+ list = xrealloc(list, (i + 1) * sizeof *list);
+
+ /* shift old contents down */
+ for (k = i; k > 0; k--) {
+ list[k] = list[k - 1];
+ }
+ /* add new element at beginning */
+ list[0] = xstrdup(str);
+
+ return list;
+}
+
+
+/*
+ * User clicked on `Help' in browser text input prompt
+ */
+static void
+help_browser_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget popup = popup_message(XtParent(w),
+ MSG_HELP,
+ NULL,
+ "The browser is used by xdvi to browse remote documents. "
+ "Please enter the name of the browser (i.e. the executable program) "
+ "you want to use. The browser command may optionally contain a string "
+ "`%%s' which is replaced by the current URL. If no `%%s' is present, "
+ "the URL argument is simply appended to the command.");
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ TRACE_GUI((stderr, "setting user data to %p", (void *)popup));
+ XtVaSetValues(w, XmNuserData, popup, NULL);
+}
+
+/*
+ * User clicked on `Help' in editor text input prompt
+ */
+static void
+help_editor_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget popup = popup_message(XtParent(w),
+ MSG_HELP,
+ NULL,
+ "The editor is used by reverse search to open the TeX source for a DVI file "
+ "(see `Help' -> `Source Specials' for details)."
+ "Please enter the name of the editor executable you want to use. "
+ "The editor command may optionally contain two format strings: "
+ "`%%l' is replaced by the line number in the TeX file, and `%%f' by the file name. "
+ "(If the format strings are not present, they are appended implicitly.)");
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ TRACE_GUI((stderr, "setting user data to %p", (void *)popup));
+ XtVaSetValues(w, XmNuserData, popup, NULL);
+}
+
+/*
+ * User cancelled browser or editor text input prompt
+ */
+static void
+destroy_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+/* Widget browser_combo = (Widget)client_data; */
+ struct choice_dialog_info *info = (struct choice_dialog_info *)client_data;
+ Widget browser_combo = NULL;
+ Widget help_popup;
+#if USE_COMBOBOX
+ Widget browser_list_w;
+#endif
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNuserData, &help_popup, NULL);
+ TRACE_GUI((stderr, "GOT help_popup: %p", (void *)help_popup));
+
+ if (info != NULL)
+ browser_combo = info->combo_box;
+
+ if (browser_combo != NULL) {
+#if USE_COMBOBOX
+ /* Need to unselect the `Other...' entry from the list; to do this,
+ we select the index from XmNuserData if it's >= 0, or the first item. */
+ int idx;
+ XtVaGetValues(browser_combo,
+ XmNlist, &browser_list_w,
+ XmNuserData, &idx,
+ NULL);
+ if (browser_list_w == 0)
+ XDVI_ERROR((stderr, "couldn't get list component of combo box!\n"));
+ else {
+ if (idx < 0)
+ idx = 0;
+ XmListSelectPos(browser_list_w, idx + 1, True);
+ }
+#else
+ Widget parent;
+ if ((parent = XtParent(w)) != NULL) {
+ Widget rowcol, child;
+ if (strcmp(XtName(parent), Xdvi_BROWSER_POPUP) == 0) {
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_BROWSER_COMBO_NAME, True)) {
+ XtVaGetValues(rowcol, XmNuserData, &child, NULL);
+ XtVaSetValues(rowcol, XmNmenuHistory, child, NULL);
+ }
+ }
+ else if (strcmp(XtName(parent), Xdvi_EDITOR_POPUP) == 0) {
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_EDITOR_COMBO_NAME, True)) {
+ XtVaGetValues(rowcol, XmNuserData, &child, NULL);
+ XtVaSetValues(rowcol, XmNmenuHistory, child, NULL);
+ }
+ }
+ else {
+ XDVI_WARNING((stderr, "unexpected widget name `%s' in destroy_dialog_cb", XtName(parent)));
+ }
+ }
+#endif
+ }
+
+ /*
+ * Also popdown dependent help window if it exists before destroying the widget;
+ * otherwise, Motif may even crash in _XmIsFastSubclass() when the help window is moved!
+ *
+ * Since `help_popup' is the top-level xmDialogShellWidget, we need to get its
+ * xmMessageBoxWidget child (by name ...). Don't report an error if it doesn't
+ * exist in case the help window has already been closed.
+ */
+ if (help_popup != NULL) {
+ static Widget message;
+ if (get_widget_by_name(&message, help_popup, Xdvi_MESSAGE_DIALOG_NAME, False))
+ XtCallCallbacks(message, XmNokCallback, NULL);
+ }
+
+ if (info != NULL) {
+ struct prefs_choice *prefs = (struct prefs_choice *)info->tinfo->data;
+ remove_from_deplist(prefs, w);
+ free(info);
+ }
+
+ /* destroy the parent of this dialog (the shell) */
+ XtDestroyWidget(XtParent(w));
+}
+
+static void
+h_get_input_wrapper(const char *listbox_name,
+ Widget w, XtPointer client_data, XtPointer call_data)
+{
+/* Widget combobox = (Widget)client_data; */
+ struct choice_dialog_info *info = (struct choice_dialog_info *)client_data;
+ struct topic_info *tinfo = info->tinfo;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+ Widget combobox, child;
+ /* following need to be allocated since we want to set resource.xyz to it */
+ static char *browser_choice= NULL, *editor_choice = NULL;
+#if !USE_COMBOBOX
+ XtCallbackProc select_cb = NULL;
+#endif
+ XmSelectionBoxCallbackStruct *cbs = (XmSelectionBoxCallbackStruct *)call_data;
+ static char *ptr = NULL;
+ char *tmp_list;
+
+ if (call_data == NULL) /* widget already being destroyed? */
+ return;
+
+ ASSERT(info != NULL, "client_data in h_get_input_wrapper mustn't be NULL!");
+ combobox = info->combo_box;
+ child = info->message_popup;
+ XtVaGetValues(w, XmNuserData, &child, NULL);
+ TRACE_GUI((stderr, "GOT child: %p", (void *)child));
+
+ if (ptr)
+ XtFree((XtPointer)ptr);
+ ptr = NULL;
+ XmStringGetLtoR(cbs->value, G_charset, &ptr);
+ if (strlen(ptr) == 0 || is_spaces_only(ptr)) {
+ popup_message(XtParent(w),
+ MSG_ERR,
+ NULL,
+ "Empty input string");
+ return;
+ }
+
+ if (strcmp(listbox_name, Xdvi_BROWSER_COMBO_NAME) == 0) {
+#if 0
+ int i;
+#endif
+
+ free(browser_choice);
+ browser_choice = xstrdup(ptr);
+ resource.browser = browser_choice;
+
+#if 0
+ for (i = 0; m_browser_list[i] != NULL; i++) {
+ fprintf(stderr, "list %d: |%s|\n", i, m_browser_list[i]);
+ }
+#endif
+ m_browser_list = add_to_list(m_browser_list, ptr);
+#if 0
+ for (i = 0; m_browser_list[i] != NULL; i++) {
+ fprintf(stderr, "NEW list %d: |%s|\n", i, m_browser_list[i]);
+ }
+#endif
+ tmp_list = flatten_list(m_browser_list, "\n");
+#if 0
+ fprintf(stderr, "TMP LIST: |%s|\n", tmp_list);
+#endif /* 0 */
+ store_preference(&(prefs->db), "prefsBrowserList", "%s", tmp_list);
+ free(tmp_list);
+
+ store_preference(&(prefs->db), "wwwBrowser", "%s", ptr);
+#if !USE_COMBOBOX
+ select_cb = select_browser_cb;
+#endif
+ }
+ else if (strcmp(listbox_name, Xdvi_EDITOR_COMBO_NAME) == 0) {
+ free(editor_choice);
+ editor_choice = xstrdup(ptr);
+ resource.editor = editor_choice;
+
+ m_editor_list = add_to_list(m_editor_list, ptr);
+ tmp_list = flatten_list(m_editor_list, "\n");
+ store_preference(&(prefs->db), "prefsEditorList", "%s", tmp_list);
+ free(tmp_list);
+
+ store_preference(&(prefs->db), "editor", "%s", ptr);
+#if !USE_COMBOBOX
+ select_cb = select_editor_cb;
+#endif
+ }
+ else
+ XDVI_WARNING((stderr, "Unexpected name in h_get_input_wrapper: `%s'", listbox_name));
+
+#if USE_COMBOBOX
+ UNUSED(listbox_name);
+ /* add user input to the combo box list, and make it current */
+ XmComboBoxAddItem(combobox, cbs->value, 1, True);
+ XmComboBoxSelectItem(combobox, cbs->value);
+#else
+ {
+ Widget new_menu, parent, grandparent, rowcol;
+ if ((parent = XtParent(w)) != NULL && (grandparent = XtParent(parent)) != NULL) {
+ /* add new item to front of list ... */
+ new_menu = XtVaCreateManagedWidget(ptr, xmPushButtonGadgetClass, grandparent,
+ XmNpositionIndex, 0,
+ XmNuserData, tinfo,
+ NULL);
+ if (select_cb != NULL) {
+ XtAddCallback(new_menu, XmNactivateCallback, select_cb, grandparent);
+ }
+ /* ... and make it current! */
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, listbox_name, True)) {
+ XtVaSetValues(rowcol, XmNmenuHistory, new_menu, NULL);
+ }
+ }
+ }
+#endif
+
+ /* as above: popdown help window */
+ if (child != NULL) {
+ Widget message;
+ if (get_widget_by_name(&message, child, Xdvi_MESSAGE_DIALOG_NAME, False))
+ XtCallCallbacks(message, XmNokCallback, NULL);
+ }
+
+ remove_from_deplist(prefs, w);
+ free(info);
+
+ /* destroy the parent of this dialog (the shell) */
+ XtDestroyWidget(XtParent(w));
+}
+
+static void
+h_selector(const char *prompt_name,
+ const char *title_str, const char *label_str,
+ XtCallbackProc ok_cb,
+ XtCallbackProc destroy_cb,
+ XtCallbackProc help_cb,
+ Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = NULL;
+ struct prefs_choice *prefs = NULL;
+ struct choice_dialog_info *info = NULL;
+ char *choice;
+ /* following need to be allocated since we want to set resource.xyz to it */
+ static char *browser_choice= NULL, *editor_choice = NULL;
+
+#if USE_COMBOBOX
+ XmComboBoxCallbackStruct *cb;
+#else
+ XmString str;
+ UNUSED(client_data);
+ UNUSED(call_data);
+#endif
+
+#if USE_COMBOBOX
+ tinfo = (struct topic_info *)client_data;
+ prefs = (struct prefs_choice *)tinfo->data;
+#endif
+ info = xmalloc(sizeof *info);
+#if USE_COMBOBOX
+ cb = (XmComboBoxCallbackStruct *)call_data;
+
+ if (cb->event == NULL) /* only browsing, no selection */
+ return;
+
+ choice = (char *)XmStringUnparse(cb->item_or_text, XmFONTLIST_DEFAULT_TAG,
+ XmCHARSET_TEXT, XmCHARSET_TEXT,
+ NULL, 0,
+ XmOUTPUT_ALL);
+#else
+ XtVaGetValues(w, XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &choice);
+
+ XtVaGetValues(w, XmNuserData, &tinfo, NULL);
+ ASSERT(tinfo != NULL, "XmNuserData in callback musn't be NULL!");
+ prefs = (struct prefs_choice *)tinfo->data;
+#endif
+
+ if (strcmp(choice, Xdvi_ADD_COMMAND_STR) == 0) {
+ Widget prompt_widget;
+ Arg args[8];
+ int n = 0;
+ XmString title = XmStringCreateLocalized((char *)title_str);
+ XmString label = XmStringCreateLocalized((char *)label_str);
+
+ XtSetArg(args[n], XmNselectionLabelString, label); n++;
+ XtSetArg(args[n], XmNautoUnmanage, False); n++;
+ XtSetArg(args[n], XmNdialogTitle, title); n++;
+ XtSetArg(args[n], XmNuserData, NULL); n++;
+ prompt_widget = XmCreatePromptDialog(
+#if USE_COMBOBOX
+ w,
+#else
+ XtParent(w),
+#endif
+ (char *)prompt_name, args, n);
+/* XmStringFree(label); */
+
+ add_to_deplist(prefs, prompt_widget);
+
+ info->tinfo = tinfo;
+ info->combo_box = w;
+ info->message_popup = NULL;
+
+ /* Note: w is the browser_combo widget */
+ XtAddCallback(prompt_widget, XmNokCallback, ok_cb, (XtPointer)info);
+ XtAddCallback(prompt_widget, XmNcancelCallback, destroy_cb, (XtPointer)info);
+ XtAddCallback(prompt_widget, XmNhelpCallback, help_cb, (XtPointer)info);
+
+ XtManageChild(prompt_widget);
+ }
+ else { /* normal item */
+#if USE_COMBOBOX
+ int i;
+#endif
+
+ if (strcmp(prompt_name, Xdvi_BROWSER_POPUP_NAME) == 0) {
+#if !USE_COMBOBOX
+ Widget rowcol;
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_BROWSER_COMBO_NAME, True)) {
+ XtVaSetValues(rowcol, XmNuserData, w, NULL);
+ }
+#endif
+ free(browser_choice);
+ browser_choice = xstrdup(choice);
+ resource.browser = browser_choice;
+ store_preference(&(prefs->db), "wwwBrowser", "%s", browser_choice);
+ }
+ else if (strcmp(prompt_name, Xdvi_EDITOR_POPUP_NAME) == 0) {
+#if !USE_COMBOBOX
+ Widget rowcol;
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_EDITOR_COMBO_NAME, True)) {
+ XtVaSetValues(rowcol, XmNuserData, w, NULL);
+ }
+#endif
+ free(editor_choice);
+ editor_choice = xstrdup(choice);
+ resource.editor = editor_choice;
+ store_preference(&(prefs->db), "editor", "%s", editor_choice);
+ }
+ else
+ XDVI_ERROR((stderr, "Unknown category `%s' in h_selector()!", prompt_name));
+
+
+#if USE_COMBOBOX
+ /* update the currently selected value */
+ XtVaGetValues(w, XmNselectedPosition, &i, NULL);
+ XtVaSetValues(w, XmNuserData, i, NULL);
+#endif
+ }
+#if USE_COMBOBOX
+ XtFree(choice);
+#endif
+}
+
+/*
+ * User OK'ed browser text input prompt
+ */
+static void
+get_browser_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (XtIsRealized(w)) {
+ h_get_input_wrapper(Xdvi_BROWSER_COMBO_NAME, w, client_data, call_data);
+ }
+}
+
+
+/*
+ * User OK'ed editor text input prompt
+ */
+static void
+get_editor_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (XtIsRealized(w)) {
+ h_get_input_wrapper(Xdvi_EDITOR_COMBO_NAME, w, client_data, call_data);
+ }
+}
+
+
+/*
+ * User selected an item from browser combo box pulldown list
+ */
+static void
+select_browser_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ h_selector(Xdvi_BROWSER_POPUP_NAME,
+ "Xdvi: Add Browser Command",
+ "Browser Command (optional `%s' is replaced by URL): ",
+ get_browser_text_cb, destroy_dialog_cb, help_browser_dialog_cb,
+ w, client_data, call_data);
+}
+
+/*
+ * User selected an item from editor combo box pulldown list
+ */
+static void
+select_editor_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(client_data);
+ h_selector(Xdvi_EDITOR_POPUP_NAME,
+ "Xdvi: Add Editor Command",
+ "Editor Command (optional: `%l' = line number, `%f' = file name): ",
+ get_editor_text_cb, destroy_dialog_cb, help_editor_dialog_cb,
+ w, client_data, call_data);
+}
+
+void
+update_preferences_helpers(void)
+{
+ Widget shell, browser_cascade, editor_cascade;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&browser_cascade, shell, Xdvi_BROWSER_COMBO_NAME, True)
+ && get_widget_by_name(&editor_cascade, shell, Xdvi_EDITOR_COMBO_NAME, True)) {
+
+#if USE_COMBOBOX
+
+ Widget browser_list_w, editor_list_w;
+ XmString str;
+ int i;
+ Boolean found = False;
+
+ XtVaGetValues(browser_cascade, XmNlist, &browser_list_w, NULL);
+ XtVaGetValues(editor_cascade, XmNlist, &editor_list_w, NULL);
+
+ for (i = 0; m_browser_list[i] != NULL; i++) {
+ if (globals.curr_browser != NULL) { /* if this is set, ignore browser setting */
+ if (strcmp(globals.curr_browser, m_browser_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ else if (resource.browser != NULL) {
+ if (strcmp(resource.browser, m_browser_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ }
+ if (!found)
+ i = 0;
+ str = XmStringCreateLtoR((char *)m_browser_list[i], "UNMARKED");
+ XmComboBoxSelectItem(browser_cascade, str);
+ XmStringFree(str);
+
+ for (i = 0; m_editor_list[i] != NULL; i++) {
+ if (globals.curr_editor != NULL) { /* if this is set, ignore editor setting */
+ if (strcmp(globals.curr_editor, m_editor_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ else if (resource.editor != NULL) {
+ if (strcmp(resource.editor, m_editor_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ }
+ if (!found)
+ i = 0;
+ str = XmStringCreateLtoR((char *)m_editor_list[i], "UNMARKED");
+ XmComboBoxSelectItem(editor_cascade, str);
+ XmStringFree(str);
+ /* XmListSetPos(editor_list_w, i); */
+ /* fprintf(stderr, "setting editor list index %d, %s\n", */
+ /* i, editor_list[i-1]); */
+
+
+ /* if (XmListGetSelectedPos(browser_list_w, &browser_items, &browser_cnt) */
+ /* && XmListGetSelectedPos(editor_list_w, &editor_items, &editor_cnt)) { */
+ /* if (browser_cnt > 0 && editor_cnt > 0) { */
+ /* int browser_idx = browser_items[0] - 1; */
+ /* int editor_idx = editor_items[0] - 1; */
+ /* fprintf(stderr, "selected: %s, %s\n", */
+ /* browser_list[browser_idx], */
+ /* editor_list[editor_idx]); */
+ /* } */
+ /* else { */
+ /* XDVI_WARNING((stderr, "Shouldn't happen: No items selected in browser list?")); */
+ /* return; */
+ /* } */
+ /* XtFree((XtPointer)browser_items); */
+ /* XtFree((XtPointer)editor_items); */
+ /* } */
+#else
+ Widget browser_menu, editor_menu;
+ if (get_widget_by_name(&browser_menu, shell, Xdvi_BROWSER_MENU_NAME, True)
+ && get_widget_by_name(&editor_menu, shell, Xdvi_EDITOR_MENU_NAME, True)) {
+ int i, num_buttons;
+ WidgetList buttons;
+
+ XtVaGetValues(browser_menu,
+ XmNnumChildren, &num_buttons,
+ XmNchildren, &buttons,
+ NULL);
+ for (i = 0; i < num_buttons; i++) {
+ XmString str;
+ char *ptr;
+
+ XtVaGetValues(buttons[i], XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &ptr);
+/* fprintf(stderr, "kid %d: %s\n", i, ptr); */
+ if (globals.curr_browser != NULL) { /* if this is set, ignore browser setting */
+ if (strcmp(globals.curr_browser, ptr) == 0) {
+ break;
+ }
+ }
+ else if (resource.browser != NULL) {
+ if (strcmp(resource.browser, ptr) == 0) {
+ break;
+ }
+ }
+ }
+ if (i >= num_buttons) /* not found */
+ i = 0;
+ XtVaSetValues(browser_cascade, XmNmenuHistory, buttons[i], NULL);
+
+ /* same for editor */
+ XtVaGetValues(editor_menu,
+ XmNnumChildren, &num_buttons,
+ XmNchildren, &buttons, NULL);
+ for (i = 0; i < num_buttons; i++) {
+ XmString str;
+ char *ptr;
+
+ XtVaGetValues(buttons[i], XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &ptr);
+/* fprintf(stderr, "kid %d: %s\n", i, ptr); */
+ if (globals.curr_editor != NULL) { /* if this is set, ignore editor setting */
+ if (strcmp(globals.curr_editor, ptr) == 0) {
+ break;
+ }
+ }
+ else if (resource.editor != NULL) {
+ if (strcmp(resource.editor, ptr) == 0) {
+ break;
+ }
+ }
+ }
+ if (i >= num_buttons) /* not found */
+ i = 0;
+ XtVaSetValues(editor_cascade, XmNmenuHistory, buttons[i], NULL);
+
+ }
+#endif
+ /* for browser/editor, try:
+
+ Widget menu;
+ int num_buttons;
+ WidgetList buttons;
+
+ XtVaGetValues( simple_option_widget, XmNsubMenuId, &menu, NULL);
+
+ XtVaGetValues( menu, XmNnumChildren, &num_buttons,
+ XmNchildren, &buttons, NULL ) ;
+
+ */
+ }
+}
+
+static Widget
+h_create_command(const char *name,
+ const char *menu_name,
+ const char *label,
+ const char *curr_value,
+ Widget parent, Widget top,
+ char **command_list,
+ XtCallbackProc select_cb,
+ struct topic_info *tinfo)
+{
+ const char *ptr = NULL;
+ size_t i;
+
+#if USE_COMBOBOX
+ XmStringTable str_list;
+ Widget text_label, combo_box;
+ size_t k, num;
+ int curr_index = -1;
+#else
+ Widget menu, cascade, item;
+ XmString str;
+ Arg args[8];
+ int n;
+#endif
+
+ /* check if we need to add the default resource name */
+ ptr = curr_value;
+
+ /* don't add it if it's already in our list */
+ for (i = 0; ptr != NULL && command_list[i] != NULL; i++) {
+ if (strcmp(command_list[i], ptr) == 0) {
+ ptr = NULL;
+ }
+ }
+#if USE_COMBOBOX
+ UNUSED(menu_name);
+ text_label = XmCreateLabelGadget(parent, (char *)label, NULL, 0);
+ XtVaSetValues(text_label,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNleftAttachment, XmATTACH_FORM,
+/* XmNrightAttachment, XmATTACH_FORM, */
+ NULL);
+
+ /* count elements in command_list */
+ for (num = 0; command_list[num] != NULL; num++) { ; }
+
+ if (ptr != NULL)
+ num++;
+
+ str_list = (XmStringTable)XtMalloc(num * sizeof(XmString *));
+
+ i = 0;
+ if (ptr != NULL)
+ str_list[i++] = XmStringCreateLtoR((char *)ptr, "UNMARKED");
+
+ for (k = 0; i < num; i++, k++) {
+ if (curr_value != NULL && strcmp(command_list[k], curr_value) == 0) {
+ curr_index = i;
+ }
+ if (strcmp(command_list[k], Xdvi_ADD_COMMAND_STR) == 0)
+ str_list[i] = XmStringCreateLtoR((char *)command_list[k], "MARKED");
+ else
+ str_list[i] = XmStringCreateLtoR((char *)command_list[k], "UNMARKED");
+ }
+ combo_box = XtVaCreateWidget(name, xmComboBoxWidgetClass,
+ parent,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top, /* if top == NULL, this used XmATTACH_FORM */
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, text_label,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNcomboBoxType, XmDROP_DOWN_LIST,
+ XmNitems, str_list,
+ XmNitemCount, num,
+ XmNuserData, curr_index,
+ NULL);
+ if (top != NULL) /* FIXME: This assumes we only have 2 items ... */
+ XtVaSetValues(combo_box,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ /* make resource setting current value */
+ if (curr_index >= 0) {
+ XmComboBoxSelectItem(combo_box, str_list[curr_index]);
+ }
+
+ for (i = 0; i < num; i++)
+ XmStringFree(str_list[i]);
+ XtFree((XtPointer)str_list);
+
+ XtAddCallback(combo_box, XmNselectionCallback, select_cb, (XtPointer)tinfo);
+
+ /*
+ * workaround for pointer grabbing bug (see xm_menu.c). We need to use
+ * the popdownCallback of the internal `GrabShell' child of the combo box.
+ */
+ {
+ Widget grab_shell;
+ if (get_widget_by_name(&grab_shell, combo_box, "GrabShell", True))
+ XtAddCallback(grab_shell, XtNpopdownCallback, popdown_callback, NULL);
+ }
+ adjust_heights(text_label, combo_box, NULL);
+
+ XtManageChild(text_label);
+ XtManageChild(combo_box);
+
+ return combo_box;
+#else
+ menu = XmCreatePulldownMenu(parent, (char *)menu_name, NULL, 0);
+/* XtVaSetValues(menu, */
+/* XmNtopAttachment, XmATTACH_WIDGET, */
+/* XmNtopWidget, top, */
+/* XmNleftAttachment, XmATTACH_FORM, */
+/* XmNrightAttachment, XmATTACH_FORM, */
+/* NULL); */
+
+ str = XmStringCreateLocalized((char *)label);
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, menu); n++;
+ XtSetArg(args[n], XmNlabelString, str); n++;
+ XtSetArg(args[n], XmNuserData, NULL); n++;
+ cascade = XmCreateOptionMenu(parent, (char *)name, args, n);
+ if (top)
+ XtVaSetValues(cascade,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ else
+ XtVaSetValues(cascade,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ if (ptr != NULL) {
+ item = XtVaCreateManagedWidget(ptr, xmPushButtonGadgetClass, menu,
+ XmNuserData, tinfo,
+ NULL);
+ XtAddCallback(item, XmNactivateCallback, select_cb, menu);
+ }
+
+ for (i = 0; command_list[i] != NULL; i++) {
+ item = XtVaCreateManagedWidget(command_list[i], xmPushButtonGadgetClass, menu,
+ XmNuserData, tinfo,
+ NULL);
+ XtAddCallback(item, XmNactivateCallback, select_cb, menu);
+ }
+ XtManageChild(cascade);
+ return cascade;
+#endif
+}
+
+Widget
+prefs_helpers(struct topic_info *tinfo)
+{
+/* struct prefs_choice *prefs = (struct prefs_choice *)info->data; */
+ Widget form, /* frame, */ form1;
+ Widget browser_command, editor_command;
+
+ form = XmCreateForm(tinfo->right_form, "helpers_form", NULL, 0);
+
+/* frame = XmCreateFrame(form, "commands_frame", NULL, 0); */
+
+ form1 = XtVaCreateWidget("commands_form", xmFormWidgetClass,
+ form,
+ XmNverticalSpacing, 10,
+ XmNhorizontalSpacing, 0,
+ NULL);
+
+ if (m_browser_list == NULL)
+ m_browser_list = get_separated_list(resource.prefs_browser_list, "\n", False);
+
+ if (m_editor_list == NULL)
+ m_editor_list = get_separated_list(resource.prefs_editor_list, "\n", False);
+
+ browser_command = h_create_command(Xdvi_BROWSER_COMBO_NAME,
+ Xdvi_BROWSER_MENU_NAME,
+ "Web Browser: ",
+ resource.browser,
+ form1, NULL,
+ m_browser_list,
+ select_browser_cb, tinfo);
+
+ editor_command = h_create_command(Xdvi_EDITOR_COMBO_NAME,
+ Xdvi_EDITOR_MENU_NAME,
+ "Editor for Source Specials: ",
+ resource.editor,
+ form1, browser_command,
+ m_editor_list,
+ select_editor_cb, tinfo);
+
+/* #if PS_GS */
+/* Widget b2 = XmCreateLabelGadget(rowcol, "[x] Use Ghostscript to interpret PS specials", NULL, 0); */
+
+ /* TODO: don't need this??? Similar: ps2pdf, dvips conversion?? */
+ /* Widget b3 = XmCreateLabelGadget(rowcol, "Path to Ghostscript: ____________", NULL, 0); */
+
+/* #endif */
+/* Widget b4 = XmCreateLabelGadget(rowcol, "Editor for source specials: <pulldown> [Other ...]", NULL, 0); */
+/* XtManageChild(b1); */
+/* XtManageChild(b2); */
+/* XtManageChild(b3); */
+/* XtManageChild(b4); */
+/* XtManageChild(rowcol); */
+
+ XtManageChild(form1);
+/* XtManageChild(frame); */
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_helpers.h b/Build/source/texk/xdvik/gui/xm_prefs_helpers.h
new file mode 100644
index 00000000000..07b851186b1
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_helpers.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_PREFS_HELPERS_
+#define XM_PREFS_HELPERS_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_helpers(struct topic_info *info);
+extern void update_preferences_helpers(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_HELPERS_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_page.c b/Build/source/texk/xdvik/gui/xm_prefs_page.c
new file mode 100644
index 00000000000..b40f1f63132
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_page.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Panel 4 (Paper size) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "events.h"
+#include "statusline.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_page.h"
+#include "my-snprintf.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/CascadeBG.h>
+
+#if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
+/* spinbox only available with Motif 2.0; the lesstif version (as of 0.93) looks like shit */
+#include <Xm/SpinB.h>
+#define USE_SPINBOX 1
+#else
+#define USE_SPINBOX 0
+#endif
+
+/*
+ * Handy defaults
+ */
+static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
+static Arg n_of_many = { XmNindicatorType, XmN_OF_MANY };
+static Arg frame_title = { XmNchildType, XmFRAME_TITLE_CHILD };
+static Arg one_col[] = {
+ { XmNpacking, XmPACK_TIGHT },
+ { XmNnumColumns, 1 },
+ { XmNorientation, XmVERTICAL }
+};
+
+
+/* this is a small selection from the paper types in xdvi.c
+ * (only the more frequenlty used ones)
+ */
+static struct paper_info {
+ const char *format;
+ const char *resource_format;
+ const char *size;
+ const char *landscape_size;
+} papersizes[] = {
+ { "US (Letter)", "us", "8.5x11in", "11x8.5in" },
+ { "Tabloid", "tabloid", "11x17in", "17x11in" }, /* dvips compatibility */
+ { "Legal", "legal", "8.5x14in", "14x8.5in" },
+ { "A0", "a0", "841x1189mm", "1189x841mm" },
+ { "A1", "a1", "594x841mm", "841x594mm" },
+ { "A2", "a2", "420x594mm", "594x420mm" },
+ { "A3", "a3", "297x420mm", "420x297mm" },
+ { "A4", "a4", "210x297mm", "297x210mm" },
+ { "A5", "a5", "148x210mm", "210x148mm" },
+ { "B5", "b5", "176x250mm", "250x176mm" },
+ { "B6", "b6", "125x176mm", "176x125mm" },
+ { "B7", "b7", "88x125mm", "125x88mm" },
+ { NULL, NULL, NULL, NULL } /* terminate */
+};
+
+void update_preferences_windowsize(void)
+{
+ Widget shell, button;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&button, shell, Xdvi_REMEMBER_WINDOWSIZE_STR, True)) {
+ XmToggleButtonGadgetSetState(button, resource.remember_windowsize, False);
+ }
+}
+
+void update_preferences_shrink(void)
+{
+ Widget shell, text;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&text, shell, Xdvi_SHRINK_TEXT, True)) {
+ char buf[LENGTH_OF_INT];
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", resource.shrinkfactor);
+#if USE_SPINBOX
+ XmTextFieldSetString(text, buf);
+ XtVaSetValues(text, XmNposition, resource.shrinkfactor, NULL);
+#else
+ XtVaSetValues(text, XmNvalue, buf, NULL);
+#endif
+ }
+}
+
+static void
+landscape_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+ Widget portrait_b, landscape_b;
+ Boolean landscape = False, is_set;
+ static char *paper_option = NULL;
+ Boolean match = False;
+ int i;
+
+ UNUSED(call_data);
+
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ /* ignore final `r' when comparing */
+ if (strncmp(resource.paper,
+ papersizes[i].resource_format,
+ strlen(papersizes[i].resource_format)) == 0) {
+ const char *ptr;
+ match = True;
+ if (strcmp(resource.paper, "letter") == 0) /* special case */
+ ptr = "us";
+ else
+ ptr = papersizes[i].resource_format;
+ free(paper_option);
+ paper_option = xstrdup(ptr);
+ break;
+ }
+ }
+
+ if (!match) {
+ XDVI_ERROR((stderr, "paper resource `%s' not found in list!\n", resource.paper));
+ return;
+ }
+
+ if (get_widget_by_name(&portrait_b, tinfo->shell, Xdvi_PAPER_PORTRAIT_STR, True)
+ && get_widget_by_name(&landscape_b, tinfo->shell, Xdvi_PAPER_LANDSCAPE_STR, True)) {
+
+ if (w == portrait_b) {
+ XtVaGetValues(portrait_b, XmNset, &is_set, NULL);
+ landscape = !is_set;
+ }
+ else {
+ XtVaGetValues(landscape_b, XmNset, &is_set, NULL);
+ landscape = is_set;
+ }
+
+/* fprintf(stderr, "++++++++ CALLBACK: setting portrait to %s, landscape to %s\n", */
+/* landscape ? "False" : "True", */
+/* landscape ? "True" : "False"); */
+
+ XmToggleButtonGadgetSetState(portrait_b, !landscape, False);
+ XmToggleButtonGadgetSetState(landscape_b, landscape, False);
+ }
+
+ if (landscape) {
+ paper_option = xstrcat(paper_option, "r");
+ }
+
+ resource.paper = paper_option;
+ store_preference(&(prefs->db), "paper", "%s", paper_option);
+}
+
+static void
+select_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+
+ XmString str;
+ char *choice;
+ int i;
+ static char *curr_choice= NULL;
+ Boolean landscape = False;
+
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &choice);
+
+ if (strlen(resource.paper) > 0 &&
+ strcmp(resource.paper, "letter") != 0 &&
+ resource.paper[strlen(resource.paper) - 1] == 'r')
+ landscape = True;
+
+ free(curr_choice);
+ curr_choice = NULL;
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ if (strcmp(choice, papersizes[i].format) == 0) {
+ curr_choice = xstrdup(papersizes[i].resource_format);
+ }
+ }
+ if (curr_choice == NULL) {
+ XDVI_ERROR((stderr, "choice`%s' not found in list!\n", choice));
+ return;
+ }
+
+ if (landscape) {
+ curr_choice = xstrcat(curr_choice, "r");
+ }
+
+ resource.paper = curr_choice;
+ store_preference(&(prefs->db), "paper", "%s", curr_choice);
+}
+
+void
+update_preferences_paper(void)
+{
+ Widget shell, portrait_button, landscape_button, sizes_menu, sizes_cascade;
+ Boolean landscape = False;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&portrait_button, shell, Xdvi_PAPER_PORTRAIT_STR, True)
+ && get_widget_by_name(&landscape_button, shell, Xdvi_PAPER_LANDSCAPE_STR, True)
+ && get_widget_by_name(&sizes_menu, shell, Xdvi_PAPER_MENU, True)
+ && get_widget_by_name(&sizes_cascade, shell, Xdvi_PAPER_CASCADE, True)) {
+
+ int i;
+ Widget sizes_button;
+
+ if (strlen(resource.paper) > 0 &&
+ strcmp(resource.paper, "letter") != 0 &&
+ resource.paper[strlen(resource.paper) - 1] == 'r') {
+
+ landscape = True;
+ }
+
+#if 0
+ XtVaGetValues(portrait_button, XmNset, &test1, NULL);
+ XtVaGetValues(landscape_button, XmNset, &test2, NULL);
+
+ fprintf(stderr, "+++++++ old state of portrait: %d, landscape: %d\n",
+ test1, test2);
+
+ fprintf(stderr, "+++++++ setting portrait to %s, landscape to %s\n",
+ landscape ? "False" : "True",
+ landscape ? "True" : "False");
+#endif /* 0 */
+
+ /*
+ Apparently there's a bug in Motif (OpenMotif 2.1) in that the button
+ is not properly updated in all cases.
+
+ To reproduce:
+
+ Open Preferences dialog, change `landscape' option, click
+ `OK'. Now open the dialog again, change the option again,
+ but click `Cancel'. This correctly reverts the visible
+ state of the buttons, but when opening the dialog again,
+ the button's internal state is not consistent with the
+ visual appearance: when clicking on the unset button, its
+ ValueChanged callback is not invoked, so nothing happens;
+ but after clicking on another(!) button in the preferences
+ dialog, it works again.
+
+ As a workaround, we destroy the buttons and re-create them from scratch - yuck!
+ */
+ {
+ Widget form = XtParent(portrait_button);
+ Widget cascade;
+ struct topic_info *info;
+
+ XtVaGetValues(portrait_button,
+ XmNleftWidget, &cascade,
+ XmNuserData, &info,
+ NULL);
+ XtDestroyWidget(portrait_button);
+ XtDestroyWidget(landscape_button);
+
+ portrait_button = XmCreateToggleButtonGadget(form, Xdvi_PAPER_PORTRAIT_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(portrait_button, !landscape, False);
+ XtVaSetValues(portrait_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, cascade,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+ landscape_button = XmCreateToggleButtonGadget(form, Xdvi_PAPER_LANDSCAPE_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(landscape_button, landscape, False);
+ XtVaSetValues(landscape_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, portrait_button,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+ XtManageChild(portrait_button);
+ XtManageChild(landscape_button);
+ XtAddCallback(portrait_button, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+ XtAddCallback(landscape_button, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+ }
+#if 0
+ XtVaGetValues(portrait_button, XmNset, &test1, NULL);
+ XtVaGetValues(landscape_button, XmNset, &test2, NULL);
+
+ fprintf(stderr, "+++++++ new state of portrait: %d, landscape: %d\n",
+ test1, test2);
+#endif /* 0 */
+
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ if (strncmp(resource.paper,
+ papersizes[i].resource_format,
+ strlen(papersizes[i].resource_format)) == 0
+ && get_widget_by_name(&sizes_button, sizes_menu, papersizes[i].format, True)) {
+
+ XtVaSetValues(sizes_cascade, XmNmenuHistory, sizes_button, NULL);
+ }
+ }
+ }
+}
+
+#if 0 /* currently unused */
+static void
+shrinkfactor_spinbox_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int val;
+/* static Boolean first_time = True; */
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNposition, &val, NULL);
+
+ /* return if value not changed yet; else the first invocation of the
+ window may actually reset the shrink factor to the default.
+ */
+/* if (val != resource.shrinkfactor) { */
+/* first_time = False; */
+/* } */
+
+ if (XtIsRealized(w)) {
+ /* don't set the resource.shrinkfactor here so that we can revert it from there if needed */
+ do_set_shrinkfactor(val, False);
+ store_preference(&(prefs->db), "shrinkFactor", "%d", val);
+ }
+}
+#endif /* currently unused */
+
+static void
+set_shrinkfactor_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ char *text;
+ int val;
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+#if USE_SPINBOX
+ XmTextPosition pos;
+ UNUSED(call_data);
+ text = XmTextFieldGetString(w);
+ val = strtol(text, (char **)NULL, 10);
+#else
+ Widget text_field;
+ UNUSED(call_data);
+ XtVaGetValues(w, XmNuserData, &text_field, NULL);
+ ASSERT(text_field != 0, "Expected text field in XmNuserData, set_shrinkfactor_cb()");
+ XtVaGetValues(text_field, XmNvalue, &text, NULL);
+ val = strtol(text, (char **)NULL, 10);
+/* fprintf(stderr, "spinbox value: |%s|\n", text); */
+#endif
+
+ if (!XtIsRealized(w))
+ return;
+
+ /* verify values in case of direct text input */
+ if (val > 100 || val <= 0) {
+ if (val > 100)
+ statusline_print(STATUS_MEDIUM, "Shrink factor larger than maximum 100");
+ else if (val <= 0)
+ statusline_print(STATUS_MEDIUM, "Shrink factor smaller than minimum 1");
+ return;
+ }
+#if USE_SPINBOX
+ /* synchronize internal spinbox value */
+ pos = XmTextFieldGetInsertionPosition(w);
+ XtVaSetValues(w, XmNposition, val, NULL);
+ XmTextFieldSetInsertionPosition(w, pos);
+#endif
+ /* don't set the resource.shrinkfactor here so that we can revert it from there if needed */
+ do_set_shrinkfactor(val, False);
+ store_preference(&(prefs->db), "shrinkFactor", "%d", val);
+
+ XtFree(text);
+}
+
+static Widget
+h_create_shrink_frame(Widget top, struct topic_info *info)
+{
+ Widget shrink_form, shrink_label;
+
+ UNUSED(info);
+
+ shrink_form = XmCreateForm(top, "shrink_form", NULL, 0);
+ XtVaSetValues(shrink_form,
+/* XmNverticalSpacing, 10, */
+/* XmNhorizontalSpacing, 10, */
+ NULL);
+
+
+ shrink_label = XmCreateLabelGadget(shrink_form, "Default Shrink Factor: ", NULL, 0);
+ XtVaSetValues(shrink_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ /* TODO XmNleftOffset, 10, */
+ NULL);
+ XtManageChild(shrink_label);
+ {
+ Widget shrink_text;
+#if USE_SPINBOX
+ Widget shrink_spinbox =
+ XtVaCreateManagedWidget(Xdvi_SHRINK_SPINBOX, xmSpinBoxWidgetClass, shrink_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, shrink_label,
+ XmNinitialDelay, 200,
+ XmNrepeatDelay, 50,
+ NULL);
+ shrink_text =
+ XtVaCreateManagedWidget(Xdvi_SHRINK_TEXT, xmTextFieldWidgetClass, shrink_spinbox,
+ XmNspinBoxChildType, XmNUMERIC,
+ XmNminimumValue, 1,
+ XmNmaximumValue, 100,
+ XmNeditable, True,
+ XmNcolumns, 3,
+ XmNincrementValue, 1,
+ XmNwrap, False, /* too confusing */
+ /* NOTE: use resource.shrinkfactor here, not current setting,
+ otherwise the current setting will sneak into ~/.xdvirc */
+ XmNposition, (int)(resource.shrinkfactor),
+ NULL);
+
+ XtAddCallback(shrink_text, XmNactivateCallback, set_shrinkfactor_cb, (XtPointer)info);
+ XtAddCallback(shrink_text, XmNvalueChangedCallback, set_shrinkfactor_cb, (XtPointer)info);
+
+ adjust_heights(shrink_spinbox, shrink_text, shrink_label, NULL);
+
+#else
+ char buf[LENGTH_OF_INT];
+ Widget shrink_button;
+ shrink_text = XmCreateTextField(shrink_form, Xdvi_SHRINK_TEXT, NULL, 0);
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", resource.shrinkfactor);
+ XtVaSetValues(shrink_text,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, shrink_label,
+ XmNcolumns, 4,
+ XmNvalue, buf,
+ XmNuserData, shrink_text,
+ NULL);
+ XtOverrideTranslations(shrink_text, XtParseTranslationTable("<Key>Return:activate()"));
+ XtAddCallback(shrink_text, XmNactivateCallback, set_shrinkfactor_cb, (XtPointer)info);
+
+ shrink_button = XmCreatePushButton(shrink_form, Xdvi_APPLY_STR, NULL, 0);
+ XtVaSetValues(shrink_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftOffset, 10,
+ XmNleftWidget, shrink_text,
+ XmNuserData, shrink_text,
+ NULL);
+ XtAddCallback(shrink_button, XmNactivateCallback, set_shrinkfactor_cb, (XtPointer)info);
+
+ adjust_heights(shrink_label, shrink_text, shrink_button, NULL);
+ XtManageChild(shrink_text);
+ XtManageChild(shrink_button);
+#endif
+ }
+
+/* XtManageChild(shrink_form); */
+
+ return shrink_form;
+}
+
+static void
+remember_windowsize_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ resource.remember_windowsize = !resource.remember_windowsize;
+
+ store_preference(&(prefs->db), "rememberWindowSize", "%s", resource.remember_windowsize ? "True" : "False");
+}
+
+
+
+static Widget
+h_create_papersize_form(Widget parent, struct topic_info *info)
+{
+ Widget form, menu, cascade, portrait_option, landscape_option;
+ XmString str;
+ Arg args[8];
+ int n;
+ size_t i;
+ Boolean landscape = False;
+
+ form = XmCreateForm(parent, "paper_form", NULL, 0);
+
+ menu = XmCreatePulldownMenu(form, Xdvi_PAPER_MENU, NULL, 0);
+
+ if (strcmp(resource.paper, "letter") != 0 && /* exceptions: these have no landscape format */
+ strcmp(resource.paper, "ledger") != 0 &&
+ strlen(resource.paper) > 0 &&
+ resource.paper[strlen(resource.paper) - 1] == 'r') { /* landscape format */
+ landscape = True;
+ }
+
+ str = XmStringCreateLocalized("Paper Size:");
+
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, menu); n++;
+ XtSetArg(args[n], XmNlabelString, str); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+
+ cascade = XmCreateOptionMenu(form, Xdvi_PAPER_CASCADE, args, n);
+ XmStringFree(str);
+
+ portrait_option = XmCreateToggleButtonGadget(form, Xdvi_PAPER_PORTRAIT_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(portrait_option, !landscape, False);
+ XtVaSetValues(portrait_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, cascade,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+
+ landscape_option = XmCreateToggleButtonGadget(form, Xdvi_PAPER_LANDSCAPE_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(landscape_option, landscape, False);
+ XtVaSetValues(landscape_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, portrait_option,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+/* adjust_heights(landscape_option, menu, cascade, NULL); */
+ XtAddCallback(portrait_option, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+ XtAddCallback(landscape_option, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+/* XtAddCallback(portrait_option, XmNarmCallback, test_cb, (XtPointer)info); */
+/* XtAddCallback(landscape_option, XmNarmCallback, test_cb, (XtPointer)info); */
+
+ XtManageChild(portrait_option);
+ XtManageChild(landscape_option);
+
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ Widget w = XtVaCreateManagedWidget(papersizes[i].format, xmPushButtonGadgetClass, menu,
+ XmNuserData, landscape_option,
+ NULL);
+/* fprintf(stderr, "Created button: %p for %s\n", w, papersizes[i].format); */
+
+ /* select default value */
+ if (strncmp(resource.paper,
+ papersizes[i].resource_format,
+ strlen(papersizes[i].resource_format)) == 0) {
+ XtVaSetValues(cascade, XmNmenuHistory, w, NULL);
+ }
+ XtAddCallback(w, XmNactivateCallback, select_cb, (XtPointer)info);
+ }
+ XtManageChild(cascade);
+
+ return form;
+}
+
+Widget
+prefs_paper(struct topic_info *info)
+{
+ Widget form;
+ Widget geometry_frame, geometry_label, geometry_rowcol, shrink_frame, geometry_button;
+ Widget paper_frame, paper_label;
+ Arg args[10];
+ int n = 0;
+ Widget rowcol;
+#if !defined(LESSTIF_VERSION)
+ Widget paper_text;
+#endif
+ Widget paper_size_form;
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ info->right_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ geometry_frame = XmCreateFrame(form, "geometry_frame", args, n);
+ h_attach_below(geometry_frame, NULL);
+
+ geometry_label = XmCreateLabelGadget(geometry_frame, "Window Size and Shrink Factor", &frame_title, 1);
+ XtManageChild(geometry_label);
+
+ geometry_rowcol = XmCreateRowColumn(geometry_frame, "geometry_rowcol", one_col, XtNumber(one_col));
+
+ geometry_button = XmCreateToggleButtonGadget(geometry_rowcol, Xdvi_REMEMBER_WINDOWSIZE_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(geometry_button, resource.remember_windowsize, False);
+ XtAddCallback(geometry_button, XmNvalueChangedCallback, remember_windowsize_cb, (XtPointer)info);
+ XtManageChild(geometry_button);
+
+ shrink_frame = h_create_shrink_frame(geometry_rowcol, info);
+ XtManageChild(shrink_frame);
+
+ XtManageChild(geometry_rowcol);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ XtSetArg(args[n], XmNtopOffset, 10); n++;
+ paper_frame = XmCreateFrame(form, "paper_frame", args, n);
+ h_attach_below(paper_frame, geometry_frame);
+
+ paper_label = XmCreateLabelGadget(paper_frame, "Default Paper Size", &frame_title, 1);
+ XtManageChild(paper_label);
+
+ rowcol = XmCreateRowColumn(paper_frame, "papersize_rowcol", NULL, 0);
+
+#if !defined(LESSTIF_VERSION) /* stupid LessTif doesn't wrap Labels at '\n' */
+ paper_text = XmCreateLabelGadget(rowcol,
+ "Used if the DVI file does not specify the paper size, e.g. via\n"
+ "\\usepackage[dvips]{geometry}. This setting will only take effect\n"
+ "after restarting xdvi.", NULL, 0);
+ XtVaSetValues(paper_text,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ XtManageChild(paper_text);
+#endif
+
+ paper_size_form = h_create_papersize_form(rowcol, info);
+ XtManageChild(paper_size_form);
+
+ XtManageChild(rowcol);
+
+ XtManageChild(geometry_frame);
+ XtManageChild(paper_frame);
+
+ XtManageChild(form);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_page.h b/Build/source/texk/xdvik/gui/xm_prefs_page.h
new file mode 100644
index 00000000000..e333f831507
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_page.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_PREFS_PAGE_
+#define XM_PREFS_PAGE_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_paper(struct topic_info *info);
+extern void update_preferences_windowsize(void);
+extern void restore_preferences_shrink(void);
+extern void update_preferences_shrink(void);
+extern void update_preferences_paper(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_PAGE_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_scroll.c b/Build/source/texk/xdvik/gui/xm_prefs_scroll.c
new file mode 100644
index 00000000000..fda08dd33dd
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_scroll.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Panel 5 (Scrolling behaviour) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "statusline.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_scroll.h"
+#include "my-snprintf.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <ctype.h>
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/CascadeBG.h>
+
+/*
+ * Handy defaults
+ */
+static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
+
+static void
+select_unit_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget pulldown = XtParent(w);
+ Widget form = XtParent(XtParent(pulldown));
+ Widget text_x, text_y;
+
+ const char *w_name = XtName(w);
+
+ UNUSED(call_data);
+
+ fprintf(stderr, "setting name: %s\n", w_name);
+ XtVaSetValues(pulldown, XmNuserData, (XtPointer)w_name, NULL);
+
+ if (get_widget_by_name(&text_x, form, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
+ && get_widget_by_name(&text_y, form, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)) {
+ const char *buf_x = XmTextFieldGetString(text_x);
+ const char *buf_y = XmTextFieldGetString(text_y);
+
+ int val_x = strtol(buf_x, (char **)NULL, 10);
+ int val_y = strtol(buf_y, (char **)NULL, 10);
+
+ static char x_off[LENGTH_OF_INT + 16];
+ static char y_off[LENGTH_OF_INT + 16];
+
+ SNPRINTF(x_off, LENGTH_OF_INT + 16, "%s%s", buf_x, w_name);
+ SNPRINTF(y_off, LENGTH_OF_INT + 16, "%s%s", buf_y, w_name);
+
+ resource.sidemargin = x_off;
+ resource.topmargin = y_off;
+
+ resource.sidemargin_int = val_x;
+ resource.topmargin_int = val_y;
+
+ store_preference(&(prefs->db), "sideMargin", "%s", x_off);
+ store_preference(&(prefs->db), "topMargin", "%s", y_off);
+
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+
+ XtFree((char *)buf_x);
+ XtFree((char *)buf_y);
+ }
+}
+
+static void
+set_offset_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget form = XtParent(w);
+ Widget pulldown;
+
+ UNUSED(call_data);
+
+ if (get_widget_by_name(&pulldown, form, Xdvi_HOME_POSITION_UNITS_PULLDOWN, True)) {
+ char *ptr = NULL;
+ const char *w_name = XtName(w);
+
+ XtVaGetValues(pulldown, XmNuserData, &ptr, NULL);
+
+ if (ptr == NULL) {
+ XDVI_WARNING((stderr, "XmNuserData for %s is NULL in set_offset_cb()\n",
+ Xdvi_HOME_POSITION_UNITS_PULLDOWN));
+ return;
+ }
+ fprintf(stderr, "UNIT: |%s|\n", ptr);
+
+ if (strcmp(w_name, Xdvi_HOME_POSITION_X_OFF_TEXT) == 0) {
+ static char x_off[LENGTH_OF_INT + 16];
+ const char *buf = XmTextFieldGetString(w);
+ int val = strtol(buf, (char **)NULL, 10);
+
+ SNPRINTF(x_off, LENGTH_OF_INT + 16, "%s%s", buf, ptr);
+
+ XtFree((char *)buf);
+
+ resource.sidemargin = x_off;
+ resource.sidemargin_int = val;
+ store_preference(&(prefs->db), "sideMargin", "%s", x_off);
+
+ goto_page(current_page, resource.keep_flag ? NULL : home, True);
+ }
+ else if (strcmp(w_name, Xdvi_HOME_POSITION_Y_OFF_TEXT) == 0) {
+ static char y_off[LENGTH_OF_INT + 16];
+ const char *buf = XmTextFieldGetString(w);
+ int val = strtol(buf, (char **)NULL, 10);
+
+ SNPRINTF(y_off, LENGTH_OF_INT + 16, "%s%s", buf, ptr);
+
+ XtFree((char *)buf);
+
+ resource.topmargin = y_off;
+ resource.topmargin_int = val;
+ store_preference(&(prefs->db), "topMargin", "%s", y_off);
+
+ goto_page(current_page, resource.keep_flag ? NULL : home, True);
+ }
+ else {
+ XDVI_WARNING((stderr, "unexpected widget name `%s' in set_offset_cb()", w_name));
+ }
+ }
+}
+
+static void
+home_position_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget parent = XtParent(XtParent(w));
+ Widget toggle_home, toggle_curr, label_x, label_y, text_x, text_y, units_menu;
+
+ UNUSED(call_data);
+
+ resource.use_current_offset = !resource.use_current_offset;
+
+ if (get_widget_by_name(&toggle_home, parent, Xdvi_HOME_POSITION_STR, True)
+ && get_widget_by_name(&toggle_curr, parent, Xdvi_SCROLL_CURRENT_STR, True)
+ && get_widget_by_name(&label_x, parent, Xdvi_HOME_POSITION_X_STR, True)
+ && get_widget_by_name(&label_y, parent, Xdvi_HOME_POSITION_Y_STR, True)
+ && get_widget_by_name(&text_x, parent, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
+ && get_widget_by_name(&text_y, parent, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)
+ && get_widget_by_name(&units_menu, parent, Xdvi_HOME_POSITION_UNITS_MENU, True)) {
+
+ XmToggleButtonGadgetSetState(toggle_home, !resource.use_current_offset, False);
+ XmToggleButtonGadgetSetState(toggle_curr, resource.use_current_offset, False);
+
+ XtSetSensitive(label_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(label_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(units_menu, !resource.keep_flag && !resource.use_current_offset);
+ }
+
+ store_preference(&(prefs->db), "useCurrentOffset", "%s", resource.use_current_offset ? "True" : "False");
+}
+
+static void
+keep_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget parent, keep, unkeep, toggle_home, toggle_curr, label_x, label_y, text_x, text_y, units_menu;
+
+ UNUSED(call_data);
+
+ resource.keep_flag = !resource.keep_flag;
+
+ parent = XtParent(w);
+
+ if (get_widget_by_name(&keep, parent, Xdvi_SCROLL_KEEP_STR, True)
+ && get_widget_by_name(&unkeep, parent, Xdvi_SCROLL_UNKEEP_STR, True)
+ && get_widget_by_name(&toggle_home, parent, Xdvi_HOME_POSITION_STR, True)
+ && get_widget_by_name(&toggle_curr, parent, Xdvi_SCROLL_CURRENT_STR, True)
+ && get_widget_by_name(&label_x, parent, Xdvi_HOME_POSITION_X_STR, True)
+ && get_widget_by_name(&label_y, parent, Xdvi_HOME_POSITION_Y_STR, True)
+ && get_widget_by_name(&text_x, parent, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
+ && get_widget_by_name(&text_y, parent, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)
+ && get_widget_by_name(&units_menu, parent, Xdvi_HOME_POSITION_UNITS_MENU, True)) {
+
+ XmToggleButtonGadgetSetState(keep, resource.keep_flag, False);
+ XmToggleButtonGadgetSetState(unkeep, !resource.keep_flag, False);
+
+ XtSetSensitive(label_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(label_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(units_menu, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(toggle_home, !resource.keep_flag);
+ XtSetSensitive(toggle_curr, !resource.keep_flag);
+ }
+
+ store_preference(&(prefs->db), "keepPosition", "%s", resource.keep_flag ? "True" : "False");
+
+}
+
+static Widget
+h_create_scrolling(Widget parent, struct topic_info *info)
+{
+ Widget form, form1, form2, size_option, curr_option;
+ Widget x_off_label, x_off_text;
+ Widget y_off_label, y_off_text;
+ Widget off_units_menu, cascade, entry1, entry2, entry3;
+
+ Widget scroll_keep, scroll_unkeep;
+
+ char x_buf[LENGTH_OF_INT + 16];
+ char y_buf[LENGTH_OF_INT + 16];
+ int n;
+ Arg args[8];
+
+ fprintf(stderr, "sidemargin: %s, topmargin: %s\n", resource.sidemargin, resource.topmargin);
+
+ if (resource.sidemargin != NULL) {
+ char *ptr;
+ strcpy(x_buf, resource.sidemargin);
+ ptr = x_buf;
+ if (*ptr == '-')
+ ptr++;
+ while (isdigit((int)*ptr))
+ ptr++;
+ *ptr = '\0';
+ }
+ else
+ strcpy(x_buf, "0");
+
+ if (resource.topmargin != NULL) {
+ char *ptr;
+ strcpy(y_buf, resource.topmargin);
+ ptr = y_buf;
+ if (*ptr == '-')
+ ptr++;
+ while (isdigit((int)*ptr))
+ ptr++;
+ *ptr = '\0';
+ }
+ else
+ strcpy(y_buf, "0");
+
+ form = XmCreateForm(parent, "offsets_form", NULL, 0);
+
+ scroll_keep = XmCreateToggleButtonGadget(form, Xdvi_SCROLL_KEEP_STR, &one_of_many, 1);
+ XtVaSetValues(scroll_keep,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ scroll_unkeep = XmCreateToggleButtonGadget(form, Xdvi_SCROLL_UNKEEP_STR, &one_of_many, 1);
+ XtVaSetValues(scroll_unkeep,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, scroll_keep,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+
+ XmToggleButtonGadgetSetState(scroll_keep, resource.keep_flag, False);
+ XmToggleButtonGadgetSetState(scroll_unkeep, !resource.keep_flag, False);
+
+ XtAddCallback(scroll_keep, XmNvalueChangedCallback, keep_cb, (XtPointer)info);
+ XtAddCallback(scroll_unkeep, XmNvalueChangedCallback, keep_cb, (XtPointer)info);
+
+ XtManageChild(scroll_keep);
+ XtManageChild(scroll_unkeep);
+
+ form1 = XmCreateForm(form, "offsets_form1", NULL, 0);
+ XtVaSetValues(form1,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, scroll_unkeep,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 20,
+ NULL);
+
+ size_option = XmCreateToggleButtonGadget(form1, Xdvi_HOME_POSITION_STR, &one_of_many, 1);
+ XtVaSetValues(size_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ x_off_label = XmCreateLabelGadget(form1, Xdvi_HOME_POSITION_X_STR, NULL, 0);
+ XtVaSetValues(x_off_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, size_option,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ x_off_text = XtVaCreateManagedWidget(Xdvi_HOME_POSITION_X_OFF_TEXT,
+ xmTextFieldWidgetClass, form1,
+ XmNcolumns, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, x_off_label,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNvalue, x_buf,
+/* XmNvalue, buf, */
+ NULL);
+ y_off_label = XmCreateLabelGadget(form1, Xdvi_HOME_POSITION_Y_STR, NULL, 0);
+ XtVaSetValues(y_off_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, x_off_text,
+ XmNleftOffset, 10,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ y_off_text = XtVaCreateManagedWidget(Xdvi_HOME_POSITION_Y_OFF_TEXT,
+ xmTextFieldWidgetClass, form1,
+ XmNcolumns, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, y_off_label,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNvalue, y_buf,
+ NULL);
+ n = 0;
+ XtSetArg(args[n], XmNuserData, (XtPointer)"in"); n++;
+ off_units_menu = XmCreatePulldownMenu(form1, Xdvi_HOME_POSITION_UNITS_PULLDOWN, args, n);
+
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, off_units_menu); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
+ XtSetArg(args[n], XmNleftWidget, y_off_text); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ cascade = XmCreateOptionMenu(form1, Xdvi_HOME_POSITION_UNITS_MENU, args, n);
+ entry1 = XtVaCreateManagedWidget("in", xmPushButtonGadgetClass, off_units_menu,
+ NULL);
+ XtAddCallback(entry1, XmNactivateCallback, select_unit_cb, info);
+ entry2 = XtVaCreateManagedWidget("cm", xmPushButtonGadgetClass, off_units_menu,
+ NULL);
+ XtAddCallback(entry2, XmNactivateCallback, select_unit_cb, info);
+ entry3 = XtVaCreateManagedWidget("Pixel", xmPushButtonGadgetClass, off_units_menu,
+ NULL);
+ XtAddCallback(entry3, XmNactivateCallback, select_unit_cb, info);
+
+ XtAddCallback(x_off_text, XmNvalueChangedCallback, set_offset_cb, (XtPointer)info);
+ XtAddCallback(y_off_text, XmNvalueChangedCallback, set_offset_cb, (XtPointer)info);
+
+ XtManageChild(size_option);
+ XtManageChild(x_off_label);
+ XtManageChild(x_off_text);
+ XtManageChild(y_off_label);
+ XtManageChild(y_off_text);
+ XtManageChild(cascade);
+
+ form2 = XmCreateForm(form, "offsets_form2", NULL, 0);
+ XtVaSetValues(form2,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, form1,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 20,
+ NULL);
+
+ curr_option = XmCreateToggleButtonGadget(form2, Xdvi_SCROLL_CURRENT_STR, &one_of_many, 1);
+ XtVaSetValues(curr_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XtManageChild(curr_option);
+
+ XtSetSensitive(x_off_label, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(x_off_text, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(y_off_label, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(y_off_text, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(cascade, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(size_option, !resource.keep_flag);
+ XtSetSensitive(curr_option, !resource.keep_flag);
+
+ XmToggleButtonGadgetSetState(size_option, !resource.use_current_offset, False);
+ XmToggleButtonGadgetSetState(curr_option, resource.use_current_offset, False);
+
+ XtAddCallback(size_option, XmNvalueChangedCallback, home_position_cb, (XtPointer)info);
+ XtAddCallback(curr_option, XmNvalueChangedCallback, home_position_cb, (XtPointer)info);
+
+ XtManageChild(form1);
+ XtManageChild(form2);
+
+ return form;
+}
+
+Widget
+prefs_scrolling(struct topic_info *info)
+{
+ Widget form;
+ Widget scrolling_form, scrolling_frame;
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ info->right_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ scrolling_frame = XmCreateFrame(form, "scrolling_frame", NULL, 0);
+ h_attach_below(scrolling_frame, NULL);
+
+ scrolling_form = h_create_scrolling(scrolling_frame, info);
+ XtVaSetValues(scrolling_form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, scrolling_frame,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtManageChild(scrolling_form);
+ XtManageChild(scrolling_frame);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_scroll.h b/Build/source/texk/xdvik/gui/xm_prefs_scroll.h
new file mode 100644
index 00000000000..838a55afdfd
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_scroll.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ *
+ */
+
+#ifndef XM_PREFS_SCROLL_
+#define XM_PREFS_SCROLL_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_scrolling(struct topic_info *info);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_SCROLL_ */
diff --git a/Build/source/texk/xdvik/gui/xm_toolbar.c b/Build/source/texk/xdvik/gui/xm_toolbar.c
new file mode 100644
index 00000000000..c1bc76286a1
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_toolbar.c
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Tool bar implementation for the Motif widget set.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "pagesel.h"
+#include "help-window.h"
+#include "message-window.h"
+#include "kpathsea/tex-file.h"
+#include "kpathsea/expand.h"
+#include "statusline.h"
+#include "dvi-init.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "xm_menu.h"
+#include "xm_toolbar.h"
+#include "util.h"
+#include "x_util.h"
+#include "Tip.h"
+
+#include <stdlib.h>
+
+#include "xdvi-config.h"
+#include "c-openmx.h"
+
+/* default toolbar pixmap file */
+#include "pixmaps/toolbar.xpm"
+
+#ifdef MOTIF
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Frame.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Separator.h>
+#include <Xm/CascadeB.h>
+#include <Xm/MainW.h>
+#include <Xm/DialogS.h>
+#include <Xm/MessageB.h>
+#include <Xm/Label.h>
+
+#if defined(HAVE_X11_XPM_H)
+# include <X11/xpm.h>
+#elif defined(HAVE_XPM_H)
+# include <xpm.h>
+#elif defined(HAVE_XM_XPMP_H)
+# include <Xm/XpmP.h>
+#endif
+
+#include <sys/stat.h>
+
+/*
+ * The following needs to be keept in sync with the actual pixmap sizes in
+ * tools.xpm. When editing the pixmaps, take care that the symbolic names
+ * are not messed up (e.g. it works with "pixmap" from ftp.x11.org, but
+ * not with xv).
+ */
+
+#define PIXMAP_WIDTH 18
+#define PIXMAP_HEIGHT 18
+/* #define PIXMAP_COUNT 13 */
+
+
+static Widget tool_bar_frame;
+
+#define SEP_CHAR ':' /* character separating entries in translations lines */
+
+void
+toggle_scrollbars(void)
+{
+ Widget x_bar = XtNameToWidget(globals.widgets.main_window, "HorScrollBar");
+ Widget y_bar = XtNameToWidget(globals.widgets.main_window, "VertScrollBar");
+
+ if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) == 0) {
+ XtUnmanageChild(x_bar);
+ XtUnmanageChild(y_bar);
+ }
+ else {
+ XtManageChild(x_bar);
+ XtManageChild(y_bar);
+ }
+
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+}
+
+void
+toggle_toolbar(void)
+{
+#if !HAVE_XPM
+ statusline_print(STATUS_LONG,
+ "Compiled without XPM support; no toolbar available.");
+#else
+ if (resource.toolbar_unusable) {
+ statusline_print(STATUS_LONG,
+ "Toolbar pixmap file not found; toolbar is disabled.");
+ return;
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ XtUnmanageChild(tool_bar_frame);
+ else
+ XtManageChild(tool_bar_frame);
+
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+
+#endif /* not HAVE_XPM */
+}
+
+typedef enum { TB_BUTTON, TB_SEPARATOR } toolbarButtonT;
+
+/* global array of button infos */
+static struct toolbar_button_info {
+ Widget button;
+ toolbarButtonT type;
+ char *tip;
+} *toolbar_buttons = NULL;
+
+#if HAVE_XPM /* remainder of file: toolbar is disabled without XPM support */
+
+/* to save current values to */
+static Pixel m_background = 0, m_top_shadow_color = 0, m_bottom_shadow_color = 0;
+
+/* to save resource value of XmNshadowThickness before overriding it if
+ toolbar_buttons_raised is false; it will be used to raise the button on enter:
+*/
+static int m_shadow_thickness;
+extern Boolean get_int_arg(String *param, Cardinal *num_params, int *res);
+
+/* indexes for named colors */
+enum {
+ BACKGROUND,
+ FOREGROUND,
+ BOTTOM_SHADOW,
+ TOP_SHADOW,
+ HIGHLIGHT
+};
+
+/* save info about buttons that need to change state */
+static struct state_buttons_info {
+ Widget back_button; /* insensitive when current page is last page */
+ Widget zoom_in_button; /* insensitive when shrinkfactor is 1 */
+ Widget forward_button; /* insensitive when current page is first page */
+ Widget hyperref_back_button; /* insensitive when at end of href history */
+ Widget hyperref_forward_button; /* insensitive when at begin of href history */
+} m_button_info;
+
+static XtCallbackRec command_call[] = {
+ { handle_command, NULL },
+ { NULL, NULL },
+};
+
+static void
+set_button_sensitivity(Widget w, Boolean sensitive)
+{
+ if (w == NULL) { /* if button hadn't been initialized properly */
+ return;
+ }
+ XtVaSetValues(w, XmNsensitive, sensitive, NULL);
+ /* also remove `raised' property on mouse over */
+ if (!sensitive && !resource.toolbar_buttons_raised) {
+ Dimension x, y, wd, ht;
+ Pixel foreground;
+ static GC backgroundGC = NULL;
+ if (!XtIsRealized(w))
+ return;
+ XtVaGetValues(w,
+ XmNx, &x,
+ XmNy, &y,
+ XmNwidth, &wd,
+ XmNheight, &ht,
+ NULL);
+ if (backgroundGC == NULL) {
+ XtVaGetValues(w, XmNforeground, &foreground, NULL);
+ backgroundGC = set_or_make_gc(NULL, GXcopy, m_background, foreground);
+ }
+ XtVaSetValues(w,
+ XmNtopShadowColor, m_background,
+ XmNbottomShadowColor, m_background,
+ NULL);
+#if 0
+ fprintf(stderr, "drawing on %d,%d\n", x, y);
+ XFillRectangle(XtDisplay(w), XtWindow(w), globals.gc.high, /* backgroundGC, */
+ x, y, wd, ht);
+#endif
+ }
+ XSync(DISP, False);
+}
+
+void
+tb_check_navigation_sensitivity(int pageno)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.forward_button, pageno == total_pages - 1 ? False : True);
+ set_button_sensitivity(m_button_info.back_button, pageno == 0 ? False : True);
+}
+
+void
+tb_set_htex_back_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+ set_button_sensitivity(m_button_info.hyperref_back_button, sensitive);
+}
+
+void
+tb_set_htex_forward_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.hyperref_forward_button, sensitive);
+}
+
+void
+tb_set_pagehist_back_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+ set_button_sensitivity(m_button_info.hyperref_back_button, sensitive);
+}
+
+void
+tb_set_pagehist_forward_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.hyperref_forward_button, sensitive);
+}
+
+void
+tb_set_zoom_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.zoom_in_button, sensitive);
+}
+
+#if 0
+static void
+search_callback(Widget w,
+ XtPointer client_data,
+ XmAnyCallbackStruct *call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL, "Sorry, not yet implemented");
+}
+#endif /* 0 */
+
+
+
+/*
+ * If successful, this extracts a square pixmap from resource.toolbar_pixmap_file
+ * and returns True.
+ * In this case, the pixmap `sen' will contain the actual
+ * pixmap and `insen' will contain a drawn pixmap for the insensitive state of
+ * the button. We are emulating a shaded state derived from the monochrome 'm'
+ * color attributes of the XPM.
+ *
+ * If unsuccessful, it returns False, and the Pixmap pointers are undefined.
+ */
+
+static Boolean
+create_pixmap(Widget parent, int iconidx, Pixmap *sen, Pixmap *insen)
+{
+ static Boolean first_time = True;
+ static Window rootWindow;
+ static XpmColorSymbol color[5] = {
+ {"none", "none", 0},
+ {"iconColor1", NULL, 0},
+ {"bottomShadowColor", NULL, 0},
+ {"topShadowColor", NULL, 0},
+ {"selectColor", NULL, 0}
+ };
+ static int screenNum;
+ static Pixmap tools_map;
+ static Pixmap tools_mask;
+ static Pixmap shade_map;
+ static Pixmap shade_mask;
+
+ int status = 0;
+ XpmAttributes attr;
+ Pixmap map;
+ Pixmap mask;
+ static String pixmap_file_path = NULL; /* note: never free()d */
+
+ ASSERT(iconidx >= 0, "index must be positive");
+
+ if (first_time) {
+ /* FIXME: We use a dummy window here to get the correct depth/visual for the
+ pixmap creation (cant use globals.widgets.top_level since it's not realized
+ yet and realizing it now would result in wrong dimensions) ... */
+ Widget dummy = XtVaAppCreateShell("xdvi", "Xdvi",
+ transientShellWidgetClass, DISP,
+ XtNdepth, G_depth,
+ XtNvisual, G_visual,
+ XtNcolormap, G_colormap,
+ XtNmappedWhenManaged, False,
+ NULL);
+ XtRealizeWidget(dummy); /* note: doesn't pop it up */
+ rootWindow = XtWindow(dummy);
+ screenNum = DefaultScreen(XtDisplay(globals.widgets.top_level));
+ ASSERT(rootWindow != 0, "");
+ XtVaGetValues(parent,
+ XmNbackground, &color[BACKGROUND].pixel,
+ XmNforeground, &color[FOREGROUND].pixel,
+ XmNbottomShadowColor, &color[BOTTOM_SHADOW].pixel,
+ XmNtopShadowColor, &color[TOP_SHADOW].pixel,
+ XmNhighlightColor, &color[HIGHLIGHT].pixel,
+ NULL);
+ /* try to locate the XPM file with the toolbar pixmaps */
+ pixmap_file_path = XtResolvePathname(DISP,
+ "pixmaps",
+ resource.toolbar_pixmap_file,
+ (String)NULL, /* suffix */
+ (String)NULL, /* use default path */
+ (Substitution)NULL, /* substitutions */
+ 0, /* number of substitutions */
+ (XtFilePredicate)NULL); /* return True iff file exists */
+
+ TRACE_GUI((stderr, "pixmap file search via XtResolvePathname: %s => %s",
+ resource.toolbar_pixmap_file, pixmap_file_path ? (char*)pixmap_file_path : "<NULL>"));
+ if (pixmap_file_path == NULL) {
+ pixmap_file_path = (String)kpse_find_file(resource.toolbar_pixmap_file,
+ kpse_program_text_format,
+ 0);
+ TRACE_GUI((stderr,
+ "pixmap file search via kpse_find_file: %s => %s",
+ resource.toolbar_pixmap_file,
+ pixmap_file_path ? (char*)pixmap_file_path : "<NULL>"));
+ if (pixmap_file_path == NULL) {
+ TRACE_GUI((stderr, "No installed toolbar pixmap found, using built-in pixmap."));
+ }
+ }
+ }
+
+ /* Setup the color subsititution table */
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColormap | XpmDepth | XpmVisual;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = XtNumber(color);
+ attr.visual = G_visual;
+ attr.colormap = G_colormap;
+ attr.depth = G_depth;
+
+ /* Create the "sensitive" pixmap */
+ if (!tools_map) {
+ if (pixmap_file_path != NULL) {
+ status = XpmReadFileToPixmap(XtDisplay(globals.widgets.top_level), rootWindow,
+ pixmap_file_path, &tools_map, &tools_mask, &attr);
+ }
+ else {
+ status = XpmCreatePixmapFromData(XtDisplay(globals.widgets.top_level), rootWindow,
+ (char **)toolbar_xpm, &tools_map, &tools_mask, &attr);
+ }
+ }
+ else
+ status = XpmSuccess;
+
+ map = tools_map;
+ mask = tools_mask;
+
+ if (status == XpmSuccess) {
+ static Pixmap tmp_mask;
+ static GC gc;
+
+ if (first_time) {
+ tmp_mask = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow, PIXMAP_WIDTH, PIXMAP_HEIGHT, 1);
+ gc = XCreateGC(XtDisplay(globals.widgets.top_level), tmp_mask, 0, NULL);
+ }
+ XCopyArea(XtDisplay(globals.widgets.top_level),
+ mask, tmp_mask, gc, iconidx * PIXMAP_WIDTH, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT, 0, 0);
+
+ mask = tmp_mask;
+ }
+ else { /* something went wrong */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Something's wrong with your XPM file - "
+ "try to load it into an image editor and fix the problem.",
+ "Xpm error: %s - switching toolbar off.",
+ XpmGetErrorString(status));
+ sen = insen = NULL;
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ return False;
+ }
+
+ XpmFreeAttributes(&attr);
+
+ if (map != 0) {
+ static GC back_gc, bots_gc;
+
+ if (first_time) {
+ XGCValues gcvalues;
+
+ gcvalues.foreground = color[BACKGROUND].pixel;
+ back_gc = XCreateGC(XtDisplay(globals.widgets.top_level), rootWindow, GCForeground, &gcvalues);
+
+ gcvalues.foreground = color[BOTTOM_SHADOW].pixel;
+ bots_gc = XCreateGC(XtDisplay(globals.widgets.top_level), rootWindow, GCForeground, &gcvalues);
+ }
+
+ /* Need to create new Pixmaps with the mask applied. */
+ XSetClipMask(XtDisplay(globals.widgets.top_level), bots_gc, mask);
+
+ /* Create the "sensitive" pixmap. */
+ *sen = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow, PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ G_depth);
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *sen, back_gc, 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
+ if (iconidx != -1)
+ XCopyArea(XtDisplay(globals.widgets.top_level), map, *sen, bots_gc,
+ iconidx * PIXMAP_WIDTH, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT, 0, 0);
+ else
+ XCopyArea(XtDisplay(globals.widgets.top_level), map, *sen, bots_gc,
+ 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT, 0, 0);
+
+ if (iconidx == -1)
+ XFreePixmap(XtDisplay(globals.widgets.top_level), map);
+
+ /* Create the "insensitive" pixmap. */
+ if (insen != NULL) {
+ Pixmap map;
+ Pixmap mask;
+
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColorKey | XpmColormap | XpmDepth | XpmVisual;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = XtNumber(color);
+ attr.color_key = XPM_MONO;
+ attr.visual = G_visual;
+ attr.colormap = G_colormap;
+ attr.depth = G_depth;
+
+
+ if (!shade_map) {
+ if (pixmap_file_path != NULL) {
+ status = XpmReadFileToPixmap(XtDisplay(globals.widgets.top_level), rootWindow,
+ pixmap_file_path, &shade_map, &shade_mask, &attr);
+ }
+ else {
+ status = XpmCreatePixmapFromData(XtDisplay(globals.widgets.top_level), rootWindow,
+ (char **)toolbar_xpm, &shade_map, &shade_mask, &attr);
+ }
+ }
+ else
+ status = XpmSuccess;
+
+ map = shade_map;
+ mask = shade_mask;
+
+ if (status == XpmSuccess) {
+ static Pixmap tmp_mask;
+ static GC gc;
+
+ if (first_time) {
+ tmp_mask = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow,
+ PIXMAP_WIDTH, PIXMAP_HEIGHT, 1);
+ gc = XCreateGC(XtDisplay(globals.widgets.top_level), tmp_mask, 0, NULL);
+ }
+
+ XCopyArea(XtDisplay(globals.widgets.top_level), mask, tmp_mask, gc,
+ iconidx * PIXMAP_WIDTH, 0,
+ PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ 0, 0);
+
+ mask = tmp_mask;
+ }
+ else { /* something went wrong */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Something's wrong with your XPM file - "
+ "try to load it into an image editor and fix the problem.",
+ "Xpm error: %s - switching toolbar off.",
+ XpmGetErrorString(status));
+ sen = insen = NULL;
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ return False;
+ }
+
+ if (mask != 0) {
+ static GC tops_gc;
+
+ if (first_time) {
+ XGCValues gcvalues;
+
+ gcvalues.foreground = color[TOP_SHADOW].pixel;
+ tops_gc = XCreateGC(XtDisplay(globals.widgets.top_level), rootWindow, GCForeground, &gcvalues);
+ }
+
+ /* Need to create new Pixmaps with the mask applied. */
+ XSetClipMask(XtDisplay(globals.widgets.top_level), bots_gc, mask);
+ XSetClipMask(XtDisplay(globals.widgets.top_level), tops_gc, mask);
+ XSetClipOrigin(XtDisplay(globals.widgets.top_level), tops_gc, 1, 1);
+
+ *insen = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow, PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ G_depth);
+
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *insen, back_gc, 0, 0,
+ PIXMAP_WIDTH, PIXMAP_HEIGHT);
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *insen, tops_gc, 1, 1,
+ PIXMAP_WIDTH - 1, PIXMAP_HEIGHT - 1);
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *insen, bots_gc, 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
+
+ if (iconidx == -1)
+ XFreePixmap(XtDisplay(globals.widgets.top_level), map);
+ }
+
+ XpmFreeAttributes(&attr);
+ }
+ }
+
+ first_time = False;
+ return True;
+}
+
+/*
+ * If successful, this returns True, and sets *button to a button with
+ * a square pixmap on it (which is cut out form `index' position in
+ * resource.toolbar_pixmap_file). If unsuccessful, it returns false,
+ * and *button is undefined.
+ */
+static Boolean
+create_toolbar_button(Widget parent, Widget *button,
+ const Pixmap *image_sens, const Pixmap *image_insens)
+{
+ Boolean sensitive = True; /* dummy */
+ *button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, parent,
+ XmNhighlightOnEnter, True,
+ XmNlabelPixmap, *image_sens,
+ XmNlabelInsensitivePixmap, *image_insens,
+ XmNsensitive, sensitive,
+ XmNlabelType, XmPIXMAP,
+ NULL);
+ XtVaGetValues(*button, XmNshadowThickness, &m_shadow_thickness, NULL);
+ if (!resource.toolbar_buttons_raised) {
+ if (m_background == 0) { /* initialize values */
+ XtVaGetValues(*button,
+ /* should we rather get background of parent widget? */
+ XmNbackground, &m_background,
+ XmNtopShadowColor, &m_top_shadow_color,
+ XmNbottomShadowColor, &m_bottom_shadow_color,
+ NULL);
+ }
+ /* remove shadows, setting them later when mouse enters button */
+ XtVaSetValues(*button,
+ XmNtopShadowColor, m_background,
+ XmNbottomShadowColor, m_background,
+ NULL);
+ }
+ return True;
+}
+
+static void
+create_toolbar_separator(Widget parent, Widget *separator, int width)
+{
+ *separator = XtVaCreateManagedWidget("toolbarSeparator",
+ xmSeparatorWidgetClass, parent,
+ XmNseparatorType, XmNO_LINE,
+ XmNminWidth, width,
+ XmNwidth, width,
+ XmNorientation, XmVERTICAL,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+}
+
+/* taken from shadow_trick in WlToolBar.c, mgv-3.1.5:
+ Get a raised behaviour for armed buttons, by explicitly setting
+ a shadow on entry and removing it on leave.
+*/
+static void
+enter_leave(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
+{
+ char *tooltip = (char *)closure;
+ XCrossingEvent *ev = (XCrossingEvent *)event;
+ static Boolean entered = False; /* to skip double leaves */
+
+ UNUSED(cont);
+
+ if (ev->type == EnterNotify) {
+ if (!resource.toolbar_buttons_raised) {
+ /* draw shadows */
+ XtVaSetValues(w,
+ XmNtopShadowColor, m_top_shadow_color,
+ XmNbottomShadowColor, m_bottom_shadow_color,
+ NULL);
+ }
+ entered = True;
+ if (resource.tooltips_in_statusline) {
+ statusline_print(STATUS_SHORT, tooltip);
+ }
+ }
+ else if (ev->type == LeaveNotify && !resource.toolbar_buttons_raised) {
+ /* remove shadows */
+ if (!entered)
+ return;
+
+ XtVaSetValues(w,
+ XmNtopShadowColor, m_background,
+ XmNbottomShadowColor, m_background,
+ NULL);
+ entered = False;
+ }
+}
+
+/*
+ save info about special buttons in m_button_info
+ (see definition of that for details)
+*/
+static void
+button_info_save(struct xdvi_action *action, Widget w)
+{
+ if (action->proc == Act_back_page && strcmp(action->param, "1") == 0) {
+ m_button_info.back_button = w;
+ }
+ else if (action->proc == Act_forward_page && strcmp(action->param, "1") == 0) {
+ m_button_info.forward_button = w;
+ }
+ else if (action->proc == Act_pagehistory_back) {
+ set_button_sensitivity(w, False);
+ m_button_info.hyperref_back_button = w;
+ }
+ else if (action->proc == Act_pagehistory_forward) {
+ set_button_sensitivity(w, False);
+ m_button_info.hyperref_forward_button = w;
+ }
+ else if (action->proc == Act_set_shrink_factor && action->param[0] == '+') {
+ m_button_info.zoom_in_button = w;
+ }
+}
+
+#endif /* HAVE_XPM */
+
+/*
+ * Create a toolbar with buttons, return toolbar widget.
+ */
+Widget
+create_toolbar(Widget parent, Widget menu_bar)
+{
+#if HAVE_XPM
+ size_t alloc_len = 0, n;
+ size_t alloc_step = 16;
+ const char *c_ptr, *e_ptr;
+#endif /* HAVE_XPM */
+ Widget tool_bar;
+ resource.toolbar_unusable = False;
+
+ tool_bar_frame = XtVaCreateWidget("toolBarFrame",
+ xmFrameWidgetClass, parent,
+ XmNshadowType, XmSHADOW_OUT,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menu_bar,
+ NULL);
+
+ tool_bar = XtVaCreateManagedWidget("toolBar",
+ xmRowColumnWidgetClass, tool_bar_frame,
+ XmNchildType, XmFRAME_WORKAREA_CHILD,
+ XmNrowColumnType, XmWORK_AREA,
+ XmNorientation, XmHORIZONTAL,
+ XmNtraversalOn, False,
+ XmNisHomogeneous, False,
+ XmNpacking, XmPACK_TIGHT,
+ XmNspacing, 0, /* override to use SEPARATOR(n) instead */
+ XmNadjustLast, True,
+ NULL);
+
+#if HAVE_XPM
+ /* parse toolbar_translations, create the widgets and assign the actions */
+ for (n = 0, c_ptr = resource.toolbar_translations;
+ c_ptr != NULL && *c_ptr != '\0';
+ c_ptr = e_ptr, n++) {
+ char **line_items = NULL;
+ int extra_space;
+ size_t len, curr, item_count = 0;
+
+ if ((e_ptr = strchr(c_ptr, '\n')) == NULL
+ /* ... and in case last line doesn't end with \n ... */
+ && (e_ptr = strchr(c_ptr, '\0')) == NULL) {
+ break;
+ }
+
+ if (e_ptr == c_ptr) {
+ XDVI_WARNING((stderr, "Skipping empty line in toolbarTranslations resource."));
+ e_ptr++;
+ continue;
+ }
+ len = e_ptr - c_ptr;
+ TRACE_GUI((stderr, "LEN %lu: |%.*s|", (unsigned long)len, (int)len, c_ptr));
+
+ line_items = split_line(c_ptr, SEP_CHAR, 0, len, &item_count);
+
+ if (globals.debug & DBG_GUI) {
+ int k;
+ for (k = 0; line_items[k] != NULL; k++) {
+ fprintf(stderr, "ITEM %d of %lu: |%s|\n", k, (unsigned long)item_count, line_items[k]);
+ }
+ }
+ while (alloc_len <= n + 1) {
+ alloc_len += alloc_step;
+ toolbar_buttons = xrealloc(toolbar_buttons, alloc_len * sizeof *toolbar_buttons);
+ }
+
+ if (item_count == 1 && sscanf(line_items[0], "SPACER(%d)", &extra_space) == 1) {
+ TRACE_GUI((stderr, "creating spacer of witdh %d at %lu", extra_space, (unsigned long)n));
+ create_toolbar_separator(tool_bar, &(toolbar_buttons[n].button), extra_space);
+ toolbar_buttons[n].type = TB_SEPARATOR;
+ }
+ else if (item_count == 4) {
+ Pixmap sens, insens;
+ int idx = strtoul(line_items[0], (char **)NULL, 10);
+ struct xdvi_action *action;
+
+ TRACE_GUI((stderr, "creating pixmap at %d", idx));
+ if (!create_pixmap(tool_bar, idx, &sens, &insens)) {
+ free(toolbar_buttons);
+ toolbar_buttons = NULL;
+ break;
+ }
+ TRACE_GUI((stderr, "creating button %ld", (unsigned long)n));
+ if (!create_toolbar_button(tool_bar, &(toolbar_buttons[n].button), &sens, &insens)) {
+ free(toolbar_buttons);
+ toolbar_buttons = NULL;
+ break;
+ }
+ toolbar_buttons[n].type = TB_BUTTON;
+
+ if ((action = compile_action(line_items[3])) != NULL) {
+ char *long_tooltip = xstrdup(line_items[1]);
+ toolbar_buttons[n].tip = xstrdup(line_items[2]);
+ /* char *short_tooltip = xstrdup(line_items[2]); */
+ command_call[0].closure = (XtPointer) action;
+
+ /*
+ eventually save this widget in list of `special' buttons
+ that need to toggle between sensitive/insensitive
+ */
+ button_info_save(action, toolbar_buttons[n].button);
+
+ XtVaSetValues(toolbar_buttons[n].button, XmNactivateCallback, (XtArgVal)command_call, NULL);
+ XtAddEventHandler(toolbar_buttons[n].button,
+ EnterWindowMask | LeaveWindowMask,
+ False,
+ enter_leave,
+ long_tooltip);
+ }
+ else {
+ XDVI_WARNING((stderr, "Invalid action \"%s\" in toolbarTranslations resource:\n\"%.*s\"",
+ line_items[3], (int)len, c_ptr));
+ }
+ }
+ else {
+ XDVI_WARNING((stderr, "Skipping malformed line \"%.*s\" in toolbarTranslations resource "
+ "(%lu instead of 4 items).",
+ (int)len, c_ptr, (unsigned long)item_count));
+ toolbar_buttons[n].button = 0;
+ }
+
+ for (curr = 0; curr < item_count; curr++) {
+ free(line_items[curr]);
+ }
+ free(line_items);
+ line_items = NULL;
+
+ if (*e_ptr != '\0')
+ e_ptr++;
+ }
+#else
+ if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) != 0) {
+ XDVI_WARNING((stderr, "This version has been compiled without XPM support. "
+ "Disabling the toolbar, which needs XPM."));
+ }
+#endif /* HAVE_XPM */
+
+ if (toolbar_buttons == NULL) {
+ resource.toolbar_unusable = True;
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ }
+ else {
+#if HAVE_XPM
+ toolbar_buttons[n].button = 0; /* terminate info */
+#endif
+ }
+ return tool_bar;
+}
+
+/*
+ * Add the tips to the toolbar. This has to be done after the toolbar has been
+ * realized.
+ */
+void
+create_tips(Widget toplevel)
+{
+#if HAVE_XPM
+ Widget tip_shell;
+
+ int i;
+
+ if (resource.toolbar_unusable) /* don't create tips in this case */
+ return;
+
+ tip_shell = XtVaCreatePopupShell("tipShell", tipWidgetClass,
+ toplevel, XtNwidth, 1, XtNheight, 1,
+ NULL);
+
+ for (i = 0; toolbar_buttons[i].button != 0; i++) {
+ if (toolbar_buttons[i].type == TB_BUTTON) {
+ TipAddWidget(tip_shell, toolbar_buttons[i].button, toolbar_buttons[i].tip);
+ }
+ }
+#else
+ UNUSED(toplevel);
+#endif /* HAVE_XPM */
+}
+
+
+#else /* MOTIF */
+/* silence "empty compilation unit" and "`toolbar_xpm' defined but not used" warnings */
+static void bar(void); static void foo() { UNUSED(toolbar_xpm); bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_toolbar.h b/Build/source/texk/xdvik/gui/xm_toolbar.h
new file mode 100644
index 00000000000..7afd1012d59
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_toolbar.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+
+ */
+
+#ifndef XM_TOOLBAR_H_
+#define XM_TOOLBAR_H_
+
+#ifdef MOTIF
+
+extern Widget create_toolbar(Widget parent, Widget menu_bar);
+
+extern Boolean toolbar_visible, scrollbars_visible, pagelist_visible;
+extern void create_tips(Widget parent);
+
+#if HAVE_XPM
+extern void tb_check_navigation_sensitivity(int pageno);
+extern void tb_check_navigation_sensitivity(int pageno);
+extern void tb_set_htex_forward_sensitivity(Boolean sensitive);
+extern void tb_set_htex_back_sensitivity(Boolean sensitive);
+extern void tb_set_pagehist_forward_sensitivity(Boolean sensitive);
+extern void tb_set_pagehist_back_sensitivity(Boolean sensitive);
+extern void tb_set_zoom_sensitivity(Boolean sensitive);
+#endif /* HAVE_XPM */
+
+extern void toggle_toolbar(void);
+extern void toggle_scrollbars(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_TOOLBAR_H_ */
diff --git a/Build/source/texk/xdvik/hypertex.c b/Build/source/texk/xdvik/hypertex.c
new file mode 100644
index 00000000000..7db7f69527f
--- /dev/null
+++ b/Build/source/texk/xdvik/hypertex.c
@@ -0,0 +1,2165 @@
+/*
+ * 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.
+*/
+
+/*
+ * Original copyright:
+ *
+ * Hypertex modifications to DVI previewer for X.
+ * This portion of xhdvi is completely in the public domain. The
+ * author renounces any copyright claims. It may be freely used for
+ * commercial or non-commercial purposes. The author makes no claims
+ * or guarantees - use this at your own risk.
+ *
+ * Arthur Smith, U. of Washington, 1994
+ *
+ * 5/1994 code written from scratch, probably inspired by (but
+ * incompatible with) the CERN WWW library.
+ *
+ * 3/1995 CERN WWW library called to do document fetching.
+ *
+ * 5/2002 SU: rewritten from scratch to make it work with the new
+ * event handling in xdvi >= 22.41: Anchors are now saved
+ * per page instead of per document, making it more robust
+ * wrt. interrupting the drawing and skipping to another page.
+ * Only drawback is that links breaking over pages are more
+ * difficult to handle (but they didn't work properly before either).
+ * Clicking on a link now performs a search for the
+ * corresponding anchor similiar to `forward search'.
+ *
+ * Removed libwww, since it has become too bloated
+ * and buggy, and had only rudimentary support for GUI
+ * interaction to begin with (e.g., interrupting a
+ * download). And since this is 2002, we might just as well
+ * use a web browser to fetch remote documents ;-)
+ */
+
+/* TODO:
+
+ - implement popup with list of visited links, as specified in
+ http://xdvi.sourceforge.net/gui.html#navigation-openLinks
+ (maybe this should be a simple menu list, not a popup window).
+ */
+
+#define COPY_TMP_FILE 0 /* see comments below */
+
+/* #define DEBUG */
+
+/* #define DEBUG_MEMORY_HANDLING */
+#include "alloc-debug.h"
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <string.h>
+
+#include <ctype.h>
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+#include <X11/StringDefs.h> /* for XtNwidth, XtNheight */
+
+#include "events.h"
+#include "dvi-init.h"
+#include "message-window.h"
+#include "util.h"
+#include "x_util.h"
+#include "mime.h"
+#include "mag.h"
+#include "dvi-draw.h"
+#include "statusline.h"
+#include "browser.h"
+#include "hypertex.h"
+#include "special.h"
+#include "string-utils.h"
+#include "xm_toolbar.h"
+#include "my-snprintf.h"
+#include "pagehist.h"
+
+/* globals */
+/* rgb specifications to translate resource.{visited_}link_color into */
+char *g_link_color_rgb = NULL;
+char *g_visited_link_color_rgb = NULL;
+char *g_anchor_pos = NULL;
+size_t g_anchor_len = 0;
+
+static const int DEFAULT_MARKER_X_OFFSET = 2; /* horizontal offset of anchor marker to edge of screen */
+static const int HTEX_ALLOC_STEP = 32;
+
+/* distance of underline from lower edge of character bbox */
+static const int ANCHOR_XTRA_V_BBOX = 6;
+
+/* info whether we're dealing with hypertex or hdvips type links */
+typedef enum { HYPERTEX_LINK, HDVIPS_LINK } hrefLinkT;
+static hrefLinkT m_href_type;
+
+typedef enum {
+ A_HREF = 0,
+ A_NAME,
+ A_HREF_FILE, /* hdvips file ref */
+ A_HREF_URL, /* hdvips URL ref */
+ A_HDVIPS_INTERNAL, /* internal ref */
+ A_HDVIPS_HREF, /* hdvips href */
+ A_HDVIPS_NAME, /* hdvips name */
+ A_OTHER,
+ A_END,
+ A_NONE,
+ A_MISMATCH
+} htexAnchorT;
+
+/****************************** helper routines ******************************/
+
+static Boolean
+htex_is_href(htexAnchorT type)
+{
+ return type == A_HREF
+ || type == A_HREF_FILE
+ || type == A_HREF_URL
+ || type == A_HDVIPS_HREF
+ || type == A_HDVIPS_INTERNAL;
+}
+
+static Boolean
+htex_is_name(htexAnchorT type)
+{
+ return type == A_NAME || type == A_HDVIPS_NAME;
+}
+
+static void
+parse_html_special(const char *special, size_t len, const char **beg, const char **end)
+{
+ *beg = special;
+ while (isspace((int)**beg) || **beg == '=') {
+ (*beg)++;
+ len--;
+ }
+ *end = *beg + len - 1;
+
+ while (isspace((int)**end) || **end == '>')
+ (*end)--;
+
+ /* remove quote pairs */
+ if (**beg == '"') {
+ (*beg)++;
+ if (**end == '"') {
+ (*end)--;
+ }
+ }
+ /* now end points to last anchor char, move behind that */
+ (*end)++;
+}
+
+/*
+ Anchor prescanning stuff: We make a pass through all pages in the document
+ before displaying them to collect information about mismatched anchors
+ (anchors where the opening tag is on some previous page).
+ The information is stored in the following struct:
+*/
+struct prescan_info {
+ int anchor_depth;
+ size_t anchor_num;
+ size_t anchor_list_size;
+ int *anchor_list;
+ /* pointers to either NULL, or to mismatched anchor strings
+ (the contents of '<a href="...">' on some previous page),
+ for each page */
+ size_t pagelist_len;
+ char **pagelist;
+};
+
+static struct prescan_info m_prescan_info = { 0, 0, 0, NULL, 0, NULL };
+static struct prescan_info m_save_prescan_info = { 0, 0, 0, NULL, 0, NULL };
+
+
+/*
+ Save prescan info from previous page, in case we only have a partial
+ scan of the current page and need to start all over.
+*/
+void
+htex_prescan_save(void)
+{
+ m_save_prescan_info.anchor_depth = m_prescan_info.anchor_depth;
+ m_save_prescan_info.anchor_num = m_prescan_info.anchor_num;
+ /* copy over anchor list */
+ while (m_save_prescan_info.anchor_depth >= (int)m_save_prescan_info.anchor_list_size) {
+ int i;
+ m_save_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
+ m_save_prescan_info.anchor_list = XREALLOC(m_save_prescan_info.anchor_list,
+ m_save_prescan_info.anchor_list_size
+ * sizeof *(m_save_prescan_info.anchor_list));
+ for (i = 0; i < m_save_prescan_info.anchor_depth; i++) {
+ m_save_prescan_info.anchor_list[i] = m_prescan_info.anchor_list[i];
+ }
+ }
+ /* the page list of anchor strings can only have had its current position modified;
+ we'll simply delete that position in htex_prescan_restore().
+ */
+}
+
+/*
+ Restore prescan info from m_save_prescan_info.
+*/
+void
+htex_prescan_restore(int pageno)
+{
+ m_prescan_info.anchor_depth = m_save_prescan_info.anchor_depth;
+ m_prescan_info.anchor_num = m_save_prescan_info.anchor_num;
+ /* copy back anchor list */
+ if (m_save_prescan_info.anchor_depth > 0) {
+ int i;
+ /* old list might have been free()d in htex_prescan_reset_firstpass */
+ while (m_save_prescan_info.anchor_depth >= (int)m_prescan_info.anchor_list_size) {
+ m_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
+ m_prescan_info.anchor_list = XREALLOC(m_prescan_info.anchor_list,
+ m_prescan_info.anchor_list_size
+ * sizeof *(m_prescan_info.anchor_list));
+ }
+ for (i = 0; i < m_save_prescan_info.anchor_depth; i++) {
+ m_prescan_info.anchor_list[i] = m_save_prescan_info.anchor_list[i];
+ }
+ }
+ /* reset anchor string info for this page */
+ if ((int)m_prescan_info.pagelist_len > pageno) {
+ ASSERT(m_prescan_info.pagelist != NULL, "m_prescan_info.pagelist not properly allocated");
+ FREE(m_prescan_info.pagelist[pageno]);
+ m_prescan_info.pagelist[pageno] = NULL;
+ }
+}
+
+/*
+ Reset prescan info for first pass (anchor numbers only) to its initial state,
+ freeing up allocated resources for anchor_list.
+
+*/
+void
+htex_prescan_reset_firstpass(void)
+{
+ MYTRACE((stderr, "resetting anchor_depth to 0!!!!!!!!!!!!"));
+ m_prescan_info.anchor_depth = 0;
+ m_prescan_info.anchor_num = 0;
+ m_prescan_info.anchor_list_size = 0;
+ FREE(m_prescan_info.anchor_list);
+ m_prescan_info.anchor_list = NULL;
+}
+
+/*
+ Reset the prescan info, freeing up all allocated memory.
+ Used when e.g. switching to a different file via Ctrl-F.
+*/
+static void
+htex_prescan_reset(void)
+{
+ size_t i;
+ m_prescan_info.anchor_depth = 0;
+ m_prescan_info.anchor_num = 0;
+ m_prescan_info.anchor_list_size = 0;
+
+ free(m_prescan_info.anchor_list);
+ m_prescan_info.anchor_list = NULL;
+
+ for (i = 0; i < m_prescan_info.pagelist_len; i++) {
+ free(m_prescan_info.pagelist[i]);
+ }
+ free(m_prescan_info.pagelist);
+ m_prescan_info.pagelist = NULL;
+ m_prescan_info.pagelist_len = 0;
+}
+
+/*
+ Initialize m_prescan_info for scanning a new page.
+*/
+void
+htex_prescan_initpage(void)
+{
+ m_prescan_info.anchor_num = 0;
+}
+
+
+Boolean
+htex_prescan_special(const char *cp, int cp_len, struct htex_prescan_data *data)
+{
+ UNUSED(cp_len);
+ ASSERT(data != NULL, "data argument to htex_prescan_special() mustn't be NULL");
+ if (data->pageno + 1 < (int)m_prescan_info.pagelist_len) { /* already scanned this page */
+ MYTRACE((stderr, "already scanned page %d", data->pageno+1));
+ return False;
+ }
+
+ /* resize pagelist */
+ while (data->pageno >= (int)m_prescan_info.pagelist_len) {
+ size_t old_len = m_prescan_info.pagelist_len;
+ size_t i;
+ MYTRACE((stderr, "============ resizing pagelist to %d", data->pageno + 1));
+ m_prescan_info.pagelist_len = data->pageno + 1;
+ m_prescan_info.pagelist = XREALLOC(m_prescan_info.pagelist,
+ m_prescan_info.pagelist_len * sizeof *m_prescan_info.pagelist);
+ /* initialize with NULL values */
+ for (i = old_len; i < m_prescan_info.pagelist_len; i++) {
+ MYTRACE((stderr, "============ initializing pagelist %d", i));
+ m_prescan_info.pagelist[i] = NULL;
+ }
+ }
+
+ if (data->scan_type == HTEX_ANCHOR_STRING) {
+ if ((int)m_prescan_info.anchor_num == data->anchor_num) {
+ char *anchor;
+ const char *beg, *end;
+ const char *cp1 = cp;
+ const char *ptr = NULL;
+ const char *pptr = NULL;
+
+ if (memicmp(cp1, "<a href", strlen("<a href")) == 0) {
+ cp1 += strlen("<a href");
+ parse_html_special(cp1, strlen(cp1), &beg, &end);
+ anchor = xmalloc(end - beg + 1);
+ memcpy(anchor, beg, end - beg);
+ anchor[end - beg] = '\0';
+ /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
+ m_prescan_info.pagelist[data->pageno] = anchor;
+ }
+ else if (memcmp(cp1, "/A", 2) == 0) {
+ if ((ptr = strstr(cp1 + 2, "/GoToR")) != NULL /* external file */
+ && (ptr = strchr(ptr, '(')) != NULL
+ && (pptr = strchr(ptr + 1, '(')) != NULL) {
+ anchor = xmalloc(pptr - ptr);
+ memcpy(anchor, ptr + 1, pptr - ptr - 1);
+ anchor[pptr - ptr - 1] = '\0';
+ /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
+ m_prescan_info.pagelist[data->pageno] = anchor;
+ }
+ else if ((ptr = strstr(cp1 + 2, "/URI")) != NULL /* external file */
+ && (ptr = strchr(ptr, '(')) != NULL
+ && (pptr = strchr(ptr + 1, '(')) != NULL) {
+ anchor = xmalloc(pptr - ptr);
+ memcpy(anchor, ptr + 1, pptr - ptr - 1);
+ anchor[pptr - ptr - 1] = '\0';
+ /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
+ m_prescan_info.pagelist[data->pageno] = anchor;
+ }
+ }
+ else if (memcmp(cp, "/L", 2) == 0) {
+ if ((ptr = strstr(cp1 + 2, "/Dest")) != NULL /* internal link */
+ && (ptr = strchr(ptr, '(')) != NULL
+ && (pptr = strchr(ptr + 1, '(')) != NULL) {
+ anchor = xmalloc(pptr - ptr);
+ memcpy(anchor, ptr + 1, pptr - ptr - 1);
+ anchor[pptr - ptr - 1] = '\0';
+ /* save the anchor string in m_prescan_info.pagelist[<current_page>] */
+ m_prescan_info.pagelist[data->pageno] = anchor;
+ }
+ }
+ }
+ }
+ if (memicmp(cp, "<a ", 3) == 0) {
+ while (m_prescan_info.anchor_depth >= (int)m_prescan_info.anchor_list_size) {
+ m_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
+ m_prescan_info.anchor_list = XREALLOC(m_prescan_info.anchor_list,
+ m_prescan_info.anchor_list_size
+ * sizeof *(m_prescan_info.anchor_list));
+ }
+ ASSERT(m_prescan_info.anchor_depth >= 0, "List should contain previous anchor info");
+ m_prescan_info.anchor_list[m_prescan_info.anchor_depth] = m_prescan_info.anchor_num;
+ m_prescan_info.anchor_depth++;
+ m_prescan_info.anchor_num++;
+ }
+ else if (memicmp(cp, "</a", 3) == 0) {
+ if (m_prescan_info.anchor_depth < 1) {
+ /* this can happen when stuff had been prescanned before */
+ return False;
+ }
+ m_prescan_info.anchor_depth--;
+ m_prescan_info.anchor_num++;
+ }
+ else if (memcmp(cp, "H.S end", strlen("H.S end")) == 0) { /* start of anchor */
+ while (m_prescan_info.anchor_depth >= (int)m_prescan_info.anchor_list_size) {
+ m_prescan_info.anchor_list_size += HTEX_ALLOC_STEP;
+ m_prescan_info.anchor_list = XREALLOC(m_prescan_info.anchor_list,
+ m_prescan_info.anchor_list_size
+ * sizeof *(m_prescan_info.anchor_list));
+ }
+ ASSERT(m_prescan_info.anchor_depth >= 0, "List should contain previous anchor info");
+ m_prescan_info.anchor_list[m_prescan_info.anchor_depth] = m_prescan_info.anchor_num;
+ m_prescan_info.anchor_depth++;
+ m_prescan_info.anchor_num++;
+
+ }
+ else if (memcmp(cp, "H.R end", strlen("H.R end")) == 0 /* end of rect */
+ || memcmp(cp, "H.A end", strlen("H.A end")) == 0 /* end of anchor */
+ || memcmp(cp, "H.L end", strlen("H.L end")) == 0 /* end of link */
+ ) {
+ if (m_prescan_info.anchor_depth < 1) {
+ /* this can happen when stuff had been prescanned before */
+ return False;
+ }
+ m_prescan_info.anchor_depth--;
+ m_prescan_info.anchor_num++;
+ }
+ return False;
+}
+
+int
+htex_prescan_get_depth(void)
+{
+ return m_prescan_info.anchor_depth;
+}
+
+/* copy over pagelist from old_page to new_page */
+void
+htex_prescan_carry_over(int old_page, int new_page)
+{
+ ASSERT(old_page >= 0, "old_page out of range");
+ ASSERT(old_page < (int)m_prescan_info.pagelist_len, "old_page out of range");
+
+ /* resize if needed */
+ if (new_page >= (int)m_prescan_info.pagelist_len) {
+ size_t old_len = m_prescan_info.pagelist_len;
+ size_t i;
+ m_prescan_info.pagelist_len = new_page + 1;
+ m_prescan_info.pagelist = XREALLOC(m_prescan_info.pagelist,
+ m_prescan_info.pagelist_len * sizeof *m_prescan_info.pagelist);
+ /* initialize with NULL values */
+ for (i = old_len; i < m_prescan_info.pagelist_len; i++) {
+ m_prescan_info.pagelist[i] = NULL;
+ }
+ }
+ free(m_prescan_info.pagelist[new_page]);
+ /* don't share pointers here */
+ m_prescan_info.pagelist[new_page] = xstrdup(m_prescan_info.pagelist[old_page]);
+}
+
+size_t
+htex_prescan_get_mismatched_anchor_num(size_t depth)
+{
+ ASSERT((int)depth <= m_prescan_info.anchor_depth, "depth too large");
+ ASSERT(depth <= m_prescan_info.anchor_list_size, "depth too large for lookup list");
+
+ return m_prescan_info.anchor_list[m_prescan_info.anchor_depth - 1];
+}
+
+/******************************* end of prescan stuff ******************************/
+
+struct anchor_marker {
+ int page; /* page on which marker is located */
+ char *filename; /* file in which the marker is located */
+ int y_pos; /* vertical position for marker */
+ int x_pos; /* horizontal position for marker */
+} g_anchormarker = { -1, NULL, -1, -1 };
+
+static XtIntervalId m_href_timeout_id = 0;
+
+
+struct history_info {
+ char *anchor; /* anchor name */
+ char *filename; /* name of file in which this anchor is located */
+ int page; /* pagenumber on which anchor is located */
+};
+
+struct anchor_info {
+ /* anchor contents as strings */
+ char *a_name;
+ char *a_href;
+ htexObjectT object_type;
+ /* bounding box info for this anchor */
+ int lrx, lry; /* lower-right corner */
+ int ulx, uly; /* upper-left corner */
+/* int refpage; /\* page in DVI file for stack of visited anchors *\/ */
+/* char *filename; /\* name of file in which this anchor is located, for visited anchors *\/ */
+ int prev_wrapped; /* index of prev elem, for wrapped hrefs, or -1 */
+ int next_wrapped; /* index of next elem, for wrapped hrefs, or -1 */
+};
+
+struct htex_page_info {
+ struct anchor_info *anchors; /* anchor info */
+ int tot_cnt; /* anchor info size */
+ int curr_cnt; /* current number of anchor on page */
+ int page; /* page in DVI file this anchor info refers to */
+ int have_wrapped; /* -1 if no wrapped anchor on beginning of page, or index of wrapped anchor */
+};
+
+/* file-scope globals ... */
+/* record x and y positions of current anchor, to recognize linebreaks in anchors */
+static int x_pos_bak = 0;
+static int y_pos_bak = 0;
+/* holds all anchors on current page */
+static struct htex_page_info htex_page_info = { NULL, 0, 0, -1, -1 };
+
+/*
+ double linked list with history of clicked links, for htex_forward/htex_back
+ */
+static struct dl_list *htex_history = NULL; /* current list insertion point */
+
+struct htex_anchor_stack_elem {
+ htexAnchorT type; /* type of anchor (href, anchor, ...) */
+ int anchor_num; /* number of this anchor on page (same as curr_cnt in struct htex_page_info) */
+};
+
+/*
+ * stack datatype and access functions; used for nested anchors
+ */
+struct htex_anchor_stack {
+ size_t size;
+ size_t depth;
+ struct htex_anchor_stack_elem *types;
+};
+
+struct visited_anchor {
+ int *list;
+ size_t list_size;
+};
+
+struct visited_anchors {
+ struct visited_anchor *anchors;
+ size_t size;
+};
+
+static struct visited_anchors visited_links = { NULL, 0 };
+
+static struct htex_anchor_stack stack = { 0, 0, NULL };
+
+
+
+/* the following list is from
+ http://www.iana.org/assignments/uri-schemes
+ re-sorted for likeliness. All protocols except for `file'
+ are considered remote.
+ (i.e. not accessible via the ordinary Unix file system)
+*/
+static char *const remote_URL_schemes[] = {
+ "http:", /* Hypertext Transfer Protocol [RFC2068] */
+ "ftp:", /* File Transfer Protocol [RFC1738] */
+ "https:", /* Hypertext Transfer Protocol Secure [RFC2818] */
+ "mailto:", /* Electronic mail address [RFC2368] */
+ "news:", /* USENET news [RFC1738] */
+ "nntp:", /* USENET news using NNTP access [RFC1738] */
+ "telnet:", /* Reference to interactive sessions [RFC1738] */
+ "nfs:", /* network file system protocol [RFC2224] */
+ "gopher:", /* The Gopher Protocol [RFC1738] */
+ "wais:", /* Wide Area Information Servers [RFC1738] */
+ /* the only exception: */
+ /* "file:", */ /* Host-specific file names [RFC1738] */
+ "prospero:", /* Prospero Directory Service [RFC1738] */
+ "z39.50s", /* Z39.50 Session [RFC2056] */
+ "z39.50r", /* Z39.50 Retrieval [RFC2056] */
+ "cid:", /* content identifier [RFC2392] */
+ "mid:", /* message identifier [RFC2392] */
+ "vemmi:", /* versatile multimedia interface [RFC2122] */
+ "service:", /* service location [RFC2609] */
+ "imap:", /* internet message access protocol [RFC2192] */
+ "acap:", /* application configuration access protocol [RFC2244] */
+ "rtsp:", /* real time streaming protocol [RFC2326] */
+ "tip:", /* Transaction Internet Protocol [RFC2371] */
+ "pop:", /* Post Office Protocol v3 [RFC2384] */
+ "data:", /* data [RFC2397] */
+ "dav:", /* dav [RFC2518] */
+ "opaquelocktoken:", /* opaquelocktoken [RFC2518] */
+ "sip:", /* session initiation protocol [RFC2543] */
+ "tel:", /* telephone [RFC2806] */
+ "fax:", /* fax [RFC2806] */
+ "modem:", /* modem [RFC2806] */
+ "ldap:", /* Lightweight Directory Access Protocol [RFC2255] */
+ "soap.beep:", /* soap.beep [RFCSOAP] */
+ "soap.beeps:", /* soap.beeps [RFCSOAP] */
+ /* Reserved URI Scheme Names: */
+ "afs:", /* Andrew File System global file names */
+ "tn3270:", /* Interactive 3270 emulation sessions */
+ "mailserver:", /* Access to data available from mail servers */
+ NULL
+};
+
+/* prototypes */
+static void htex_erase_anchormarker(XtPointer client_data, XtIntervalId *id);
+static void htex_draw_anchormarker(int y);
+
+
+static void
+resize_info_if_needed(struct htex_page_info *info)
+{
+ /* resize info if needed */
+ if (info->curr_cnt + 2 >= info->tot_cnt) {
+ int i;
+ while (info->curr_cnt + 2 >= info->tot_cnt) {
+ info->tot_cnt += HTEX_ALLOC_STEP;
+ }
+ info->anchors = XREALLOC(info->anchors, info->tot_cnt * sizeof *(info->anchors));
+ for (i = info->curr_cnt; i < info->tot_cnt; i++) {
+/* fprintf(stderr, "initializing info at index %d\n", i); */
+ info->anchors[i].a_href = NULL;
+ info->anchors[i].a_name = NULL;
+/* info->anchors[i].filename = NULL; */
+ info->anchors[i].ulx = INT_MAX;
+ info->anchors[i].uly = INT_MAX;
+ info->anchors[i].lrx = 0;
+ info->anchors[i].lry = 0;
+ info->anchors[i].object_type = HTEX_TEXT;
+ info->anchors[i].prev_wrapped = -1;
+ info->anchors[i].next_wrapped = -1;
+ }
+ }
+}
+
+static void
+init_visited_links(struct visited_anchors *links, int total_pages, Boolean new_dvi_file)
+{
+ size_t i, old_size = links->size;
+ if (new_dvi_file) {
+ /* free old list */
+ for (i = 0; i < old_size; i++) {
+ FREE(links->anchors[i].list);
+ links->anchors[i].list = NULL;
+ links->anchors[i].list_size = 0;
+ }
+ }
+ if (links->size <= (size_t)total_pages) {
+ MYTRACE((stderr, "resetting visited links (%d != %d)", links->size, total_pages));
+ links->size = total_pages + 1;
+ links->anchors = XREALLOC(links->anchors, (links->size + 1) * sizeof *(links->anchors));
+ for (i = old_size; i < links->size; i++) {
+ MYTRACE((stderr, "+++ initializing visited links for page %d", i));
+ links->anchors[i].list = NULL;
+ links->anchors[i].list_size = 0;
+ }
+ }
+}
+
+#if 0
+static void
+show_visited(struct visited_anchors *links, int pageno)
+{
+ size_t i;
+ fprintf(stderr, "visited links on page %d:\n", pageno);
+ for (i = 0; i < links->anchors[pageno].list_size; i++) {
+ fprintf(stderr, "%d ", links->anchors[pageno].list[i]);
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+static void
+save_in_list(struct visited_anchors *links, int pageno, int idx)
+{
+ links->anchors[pageno].list
+ = XREALLOC(links->anchors[pageno].list,
+ (links->anchors[pageno].list_size + 1)
+ * sizeof *(links->anchors[pageno].list));
+ links->anchors[pageno].list[links->anchors[pageno].list_size] = idx;
+ links->anchors[pageno].list_size++;
+}
+
+static void
+set_visited(struct visited_anchors *links, int pageno, int anchor_num)
+{
+ int i;
+ /* is it already present? */
+ for (i = 0; i < (int)links->anchors[pageno].list_size; i++) {
+ if (links->anchors[pageno].list[i] == anchor_num)
+ return;
+ }
+ save_in_list(links, pageno, anchor_num);
+ i = anchor_num;
+ /* also set previous/next of this anchor to visited */
+ while ((i = htex_page_info.anchors[i].prev_wrapped) != -1) {
+ TRACE_HTEX((stderr, "set_visited: setting prev_wrapped %d to visited too", i));
+ save_in_list(links, pageno, i);
+ }
+ i = anchor_num;
+ while ((i = htex_page_info.anchors[i].next_wrapped) != -1) {
+ TRACE_HTEX((stderr, "set_visited: setting next_wrapped %d to visited too", i));
+ save_in_list(links, pageno, i);
+ }
+#if 0
+ show_visited(links, pageno);
+#endif
+}
+
+static Boolean
+is_visited(struct visited_anchors *links, int pageno, int anchor_num)
+{
+ size_t i;
+
+ ASSERT((size_t)pageno < links->size, "too few elements in links structure");
+
+ for (i = 0; i < links->anchors[pageno].list_size; i++) {
+ if (links->anchors[pageno].list[i] == anchor_num) {
+ return True;
+ }
+ }
+ return False;
+}
+
+static void
+push_stack(struct htex_anchor_stack *stack, htexAnchorT type, int anchor_num)
+{
+ size_t i = 0;
+ if (stack->depth >= stack->size) {
+ stack->size += HTEX_ALLOC_STEP;
+ stack->types = XREALLOC(stack->types, stack->size * sizeof *(stack->types));
+ for (i = stack->depth; i < stack->size; i++) {
+ stack->types[i].type = A_NONE;
+ stack->types[i].anchor_num = -1;
+ }
+ }
+ stack->types[stack->depth].type = type;
+ stack->types[stack->depth].anchor_num = anchor_num;
+ stack->depth++;
+#if 0
+ {
+ fprintf(stderr, "PUSH - stack is now: \n");
+ for (i = 0; i < stack->depth; i++)
+ fprintf(stderr, "%d:%d ", i, stack->types[i]);
+ MYTRACE(stderr, "\n");
+ }
+#endif
+}
+
+static htexAnchorT
+pop_stack(struct htex_anchor_stack *stack, int *anchor_num)
+{
+ htexAnchorT ret;
+
+ if (stack->depth < 1) {
+ return A_MISMATCH;
+ }
+
+#if 0
+ {
+ int i;
+ MYTRACE((stderr, "POP - stack is now: "));
+ for (i = 0; i < stack->depth; i++)
+ MYTRACE((stderr, "%d:%d ", i, stack->types[i]));
+ MYTRACE((stderr, ""));
+ }
+#endif
+ stack->depth--;
+ ret = stack->types[stack->depth].type;
+ *anchor_num = stack->types[stack->depth].anchor_num;
+ stack->types[stack->depth].type = A_NONE;
+ stack->types[stack->depth].anchor_num = -1;
+ return ret;
+}
+
+
+/* return True if stack contains an A_HREF, False else */
+static Boolean
+get_href_depth(const struct htex_anchor_stack *stack)
+{
+ size_t i;
+ for (i = 0; i <= stack->depth; i++) {
+ ASSERT(stack->types != NULL, "types musn't be NULL!");
+ if (htex_is_href(stack->types[i].type))
+ return True;
+ }
+ return False;
+}
+
+static htexAnchorT
+peek_stack(struct htex_anchor_stack *stack, int *anchor_num)
+{
+ if (stack->depth < 1) {
+ MYTRACE((stderr, "Xdvi warning: wrong nesting of anchors on page %d", current_page));
+ *anchor_num = -1;
+ return A_NONE;
+ }
+
+ *anchor_num = stack->types[stack->depth - 1].anchor_num;
+ return stack->types[stack->depth - 1].type;
+}
+
+/* routines for coloring the anchors */
+static void
+push_colorspecial(void)
+{
+ int i;
+
+ i = htex_page_info.curr_cnt - 1;
+ /* apply color if needed */
+ if (resource.link_style > 1) { /* colored links are wanted */
+ Boolean visited = False;
+
+ ASSERT(i >= 0, "i mustn't be negative");
+ if (is_visited(&visited_links, current_page, i)) {/* || wrapped_anchor_is_visited(i)) { */
+ visited = True;
+ }
+
+ MYTRACE((stderr, "anchor %d, %s is %s\n",
+ htex_page_info.curr_cnt - 1, htex_page_info.anchors[htex_page_info.curr_cnt - 1].a_href,
+ visited ? "******* visited ****** " : "not visited"));
+ if ((visited && resource.visited_link_color != NULL)
+ || (! visited && resource.link_color != NULL)) {
+ color_special(visited ? g_visited_link_color_rgb : g_link_color_rgb);
+ }
+ }
+}
+
+static void
+pop_colorspecial(void)
+{
+ color_special("pop");
+}
+
+/* return filename if it's a local file, NULL else */
+const char *
+is_local_file(const char *filename)
+{
+ int i;
+ if (strchr(filename, ':') != NULL) {
+ if (memicmp(filename, "file:", strlen("file:")) == 0) {
+ TRACE_HTEX((stderr, "%s uses file scheme", filename));
+ filename += strlen("file:");
+ /*
+ skip over `//localhost' part, and skip first `/' iff the
+ absolute path starts with `//' (as required by RFC2396,
+ but in the past most browsers/applications didn't support
+ this).
+ */
+ if (memicmp(filename, "//localhost", strlen("//localhost")) == 0) {
+ filename += strlen("//localhost");
+ }
+ if (memicmp(filename, "//", 2) == 0) {
+ filename += 1;
+ }
+ return filename;
+ }
+
+ /* check remote schemes */
+ for (i = 0; remote_URL_schemes[i] != NULL; i++) {
+ if (memicmp(filename, remote_URL_schemes[i], strlen(remote_URL_schemes[i])) == 0) {
+ TRACE_HTEX((stderr, "%s is a remote scheme", filename));
+ return NULL;
+ }
+ }
+ }
+ /* in all other cases, treat it as an ordinary filename */
+ TRACE_HTEX((stderr, "%s is an ordinary filename", filename));
+ return filename;
+}
+
+
+static char *
+parse_anchortext(const char *input, int len)
+{
+ char *anchor = NULL;
+ const char *beg, *end;
+
+ parse_html_special(input, len, &beg, &end);
+
+ anchor = XMALLOC(anchor, end - beg + 1);
+ memcpy(anchor, beg, end - beg);
+ anchor[end - beg] = '\0';
+ return anchor;
+}
+
+static void
+add_anchor(struct htex_page_info *info, htexAnchorT type,
+ const char *str, size_t len,
+ int pageno, char *filename)
+{
+ UNUSED(pageno);
+ UNUSED(filename);
+
+ resize_info_if_needed(info);
+
+ ASSERT(htex_is_name(type) || htex_is_href(type), "This doesn't look like a valid anchor");
+ /* add an anchor or a href, depending on `type' */
+ if (type == A_HREF) {
+ if (info->anchors[info->curr_cnt].a_href == NULL) {
+ info->anchors[info->curr_cnt].a_href = parse_anchortext(str, len);
+ }
+ TRACE_HTEX((stderr, "adding HREF %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
+ }
+ else if (type == A_HREF_URL) {
+ if (info->anchors[info->curr_cnt].a_href == NULL) {
+ info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
+ strncpy(info->anchors[info->curr_cnt].a_href, str, len);
+ info->anchors[info->curr_cnt].a_href[len] = '\0';
+ }
+ TRACE_HTEX((stderr, "adding HREF_URL %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
+ }
+ else if (type == A_HDVIPS_INTERNAL) {
+ if (info->anchors[info->curr_cnt].a_href == NULL) {
+ /* dynamically add a `#' prefix */
+ if (str[0] != '#') {
+ info->anchors[info->curr_cnt].a_href = xmalloc(len + 2);
+ strcpy(info->anchors[info->curr_cnt].a_href, "#");
+ strncat(info->anchors[info->curr_cnt].a_href, str, len);
+ info->anchors[info->curr_cnt].a_href[len + 1] = '\0';
+ }
+ else {
+ info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
+ strncpy(info->anchors[info->curr_cnt].a_href, str, len);
+ info->anchors[info->curr_cnt].a_href[len] = '\0';
+ }
+ }
+ TRACE_HTEX((stderr, "adding HREF_URL %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
+ }
+ else if (type == A_HREF_FILE) {
+ if (info->anchors[info->curr_cnt].a_href == NULL) {
+ /* dynamically add a `file:' extension */
+ if (memcmp(str, "file:", strlen("file:")) == 0) {
+ info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
+ strncpy(info->anchors[info->curr_cnt].a_href, str, len);
+ info->anchors[info->curr_cnt].a_href[len] = '\0';
+ }
+ else {
+ info->anchors[info->curr_cnt].a_href = xmalloc(len + strlen("file:") + 1);
+ strcpy(info->anchors[info->curr_cnt].a_href, "file:");
+ strncat(info->anchors[info->curr_cnt].a_href, str, len);
+ info->anchors[info->curr_cnt].a_href[len + strlen("file:")] = '\0';
+ }
+ }
+ TRACE_HTEX((stderr, "adding HREF_FILE %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_href));
+ }
+ else if (type == A_NAME) {
+ if (info->anchors[info->curr_cnt].a_name == NULL) {
+ info->anchors[info->curr_cnt].a_name = parse_anchortext(str, len);
+ }
+ TRACE_HTEX((stderr, "adding NAME %d: %s", info->curr_cnt, info->anchors[info->curr_cnt].a_name));
+ }
+ else if (type == A_HDVIPS_HREF) {
+ if (info->anchors[info->curr_cnt].a_href == NULL) {
+ info->anchors[info->curr_cnt].a_href = xmalloc(len + 1);
+ strncpy(info->anchors[info->curr_cnt].a_href, str, len);
+ info->anchors[info->curr_cnt].a_href[len] = '\0';
+ }
+ TRACE_HTEX((stderr, "adding HDVIPS_HREF %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_name));
+ }
+ else if (type == A_HDVIPS_NAME) {
+ if (info->anchors[info->curr_cnt].a_name == NULL) {
+ info->anchors[info->curr_cnt].a_name = xmalloc(len + 1);
+ strncpy(info->anchors[info->curr_cnt].a_name, str, len);
+ info->anchors[info->curr_cnt].a_name[len] = '\0';
+ }
+ TRACE_HTEX((stderr, "adding HDVIPS_NAME %d: |%s|", info->curr_cnt, info->anchors[info->curr_cnt].a_name));
+ }
+}
+
+static void
+set_anchor_size(struct htex_page_info *info, int index,
+ int ulx, int uly, int lrx, int lry)
+{
+ struct anchor_info *anchor;
+
+ ASSERT(info->anchors != NULL, "info->anchors should have been allocated before");
+ ASSERT(index < info->curr_cnt, "info too small");
+
+ anchor = &(info->anchors[index]);
+
+ anchor->ulx = ulx;
+ anchor->uly = uly;
+ anchor->lrx = lrx;
+ anchor->lry = lry;
+}
+
+void
+htex_set_objecttype(htexObjectT type)
+{
+ htex_page_info.anchors[htex_page_info.curr_cnt - 1].object_type = type;
+}
+
+void
+htex_set_anchorsize(int ulx, int uly, int lrx, int lry)
+{
+ set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1,
+ ulx, uly, lrx, lry);
+}
+
+static void
+enlarge_anchor_size(struct htex_page_info *info, int index,
+ int ulx, int uly, int lrx, int lry)
+{
+ struct anchor_info *anchor;
+
+ ASSERT(info->anchors != NULL, "info->anchors should have been allocated before");
+ ASSERT(index < info->curr_cnt, "info too small");
+
+/* fprintf(stderr, "enlarging anchor at index %d; %s\n", index, info->anchors[index].a_href); */
+ anchor = &(info->anchors[index]);
+
+ if (ulx < anchor->ulx) {
+ anchor->ulx = ulx;
+ }
+ if (uly < anchor->uly) {
+ anchor->uly = uly;
+ }
+ if (lrx > anchor->lrx) {
+ anchor->lrx = lrx;
+ }
+ /* set lry only for first character, since this will be used
+ to position underline */
+/* if (lry > anchor->lry && anchor->lry == 0) { */
+ if (lry > anchor->lry) {
+ anchor->lry = lry;
+ }
+}
+
+static void
+reset_page_info(struct htex_page_info *info, int pageno, Boolean force_init)
+{
+ int i, dummy;
+
+ if (force_init || pageno != info->page) {
+#if 0
+ fprintf(stderr, "%d or %d != %d: resetting anchorinfo for page %d (%d anchors)\n",
+ force_init, pageno, info->page, current_page, info->curr_cnt);
+#endif
+ ASSERT(info->curr_cnt == 0 || info->anchors != NULL, "inconsistency in info structure");
+ /* re-initialize all values */
+ for (i = 0; i < info->curr_cnt; i++) {
+ TRACE_HTEX((stderr, "----- resetting info for anchor %d", i));
+ FREE(info->anchors[i].a_name);
+ FREE(info->anchors[i].a_href);
+ info->anchors[i].a_name = NULL;
+ info->anchors[i].a_href = NULL;
+ info->anchors[i].ulx = INT_MAX;
+ info->anchors[i].uly = INT_MAX;
+ info->anchors[i].lrx = 0;
+ info->anchors[i].lry = 0;
+ info->anchors[i].object_type = HTEX_TEXT;
+ info->anchors[i].prev_wrapped = -1;
+ info->anchors[i].next_wrapped = -1;
+ }
+ }
+ if (pageno != info->page) { /* reset info */
+ free(info->anchors);
+ info->anchors = NULL;
+ info->tot_cnt = 0;
+ }
+ TRACE_HTEX((stderr, "---------------- setting curr_cnt to 0, and emptying stack"));
+ info->page = pageno;
+ info->curr_cnt = 0;
+ info->have_wrapped = -1;
+ while (stack.depth > 0)
+ pop_stack(&stack, &dummy);
+}
+
+/*
+ * htex_initpage does what's neccessary at the beginning of a page:
+ * - re-initialize geometry info if file or page size has changed (according to size_changed),
+ * - re-initialize visited links info if file has changed (according to new_dvi_file),
+ * - take care of mismatched anchors at the beginning of the page.
+ */
+void
+htex_initpage(Boolean new_dvi_file, Boolean size_changed, int pageno)
+{
+ reset_page_info(&htex_page_info, pageno, size_changed | new_dvi_file);
+ init_visited_links(&visited_links, total_pages, new_dvi_file);
+
+#if 0
+ show_visited(&visited_links, pageno);
+#endif
+
+ if (pageno > 0
+ && (int)m_prescan_info.pagelist_len > pageno /* pagelist_len will be 0 for file with no hyperlinks */
+ && m_prescan_info.pagelist[pageno - 1] != NULL) {
+ add_anchor(&htex_page_info, A_HREF,
+ m_prescan_info.pagelist[pageno - 1],
+ strlen(m_prescan_info.pagelist[pageno - 1]),
+ pageno, NULL);
+ htex_page_info.curr_cnt++;
+ MYTRACE((stderr, "++++++++++ mismatched anchor text (at %d): |%s|",
+ htex_page_info.curr_cnt - 1, m_prescan_info.pagelist[pageno - 1]));
+ /* x_pos_bak = y_pos_bak = INT_MAX; */
+ x_pos_bak = y_pos_bak = INT_MAX;
+ set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1, 0, 0, 1, 1);
+ htex_page_info.have_wrapped = htex_page_info.curr_cnt - 1;
+ if (bg_current != NULL) { /* only if it has been initialized by redraw_page in events.c */
+ push_colorspecial();
+ }
+/* else { */
+/* fprintf(stderr, "----------------------- NOT pushing color, waiting ...\n"); */
+/* } */
+ push_stack(&stack, A_HREF, htex_page_info.curr_cnt - 1);
+ }
+}
+
+static void
+hdvips_add_anchor(struct htex_page_info *info, htexAnchorT type, const char *str)
+{
+ char *ptr;
+ if ((ptr = strchr(str, ')')) != NULL) {
+ int curr_cnt_bak = info->curr_cnt;
+ /* overwrite previously created dummy/wrapped anchors */
+ ASSERT(info->curr_cnt > 0, "hdvips_add_anchor must be called after add_anchor()!");
+
+ while (info->curr_cnt > 0
+ && info->anchors[info->curr_cnt - 1].a_href != NULL
+ && (strcmp(info->anchors[info->curr_cnt - 1].a_href, "__WRAPPED__") == 0
+ || strcmp(info->anchors[info->curr_cnt - 1].a_href, "__DUMMY__") == 0)) {
+ info->curr_cnt--;
+ free(info->anchors[info->curr_cnt].a_href);
+ free(info->anchors[info->curr_cnt].a_name);
+ info->anchors[info->curr_cnt].a_href = info->anchors[info->curr_cnt].a_name = NULL;
+ add_anchor(info, type, str, ptr - str, 0, NULL);
+ }
+ info->curr_cnt = curr_cnt_bak;
+ }
+ else {
+ MYTRACE((stderr, "Xdvi warning: skipping malformed hdvips link `%s'", str));
+ }
+}
+
+/*
+ * htex_reset_page: invoked when drawing was interrupted,
+ * assumes that htex_page_info is in an inconsistent state and resets it.
+ */
+void
+htex_reset_page(int pageno)
+{
+ reset_page_info(&htex_page_info, pageno, True);
+}
+
+/* returns True iff inside a href tag */
+Boolean
+htex_scan_anchor(const char *cp, size_t len)
+{
+ char *ptr;
+
+ if (memicmp(cp, "</a>", 4) == 0) { /* end tag */
+ /* struct anchor_info *anchor; */
+ int num;
+ htexAnchorT type = pop_stack(&stack, &num);
+ if (type == A_MISMATCH)
+ return False;
+
+ /* ASSERT(htex_page_info.curr_cnt - 1 >= 0, "Index out of range"); */
+ /* anchor = &(htex_page_info.anchors[htex_page_info.curr_cnt - 1]); */
+
+ /* reset color if needed */
+ if (resource.link_style > 1 && resource.link_color != NULL && htex_is_href(type))
+ pop_colorspecial();
+ }
+ else if (memicmp(cp, "<a ", 3) == 0) {
+ m_href_type = HYPERTEX_LINK;
+ cp += 3; /* skip over `<a ' part */
+ len -= 3;
+ TRACE_HTEX((stderr, "scan_anchor: |%s|", cp));
+ if (memicmp(cp, "name", 4) == 0) {
+ add_anchor(&htex_page_info, A_NAME, cp + 4, len - 4, 0, NULL);
+ htex_page_info.curr_cnt++;
+ push_stack(&stack, A_NAME, htex_page_info.curr_cnt);
+ }
+ else if (memicmp(cp, "href", 4) == 0) {
+ add_anchor(&htex_page_info, A_HREF, cp + 4, len - 4, 0, NULL);
+ htex_page_info.curr_cnt++;
+ push_stack(&stack, A_HREF, htex_page_info.curr_cnt);
+
+ /* MYTRACE((stderr, "NON-WRAPPED ANCHOR at %d,%d!", PXL_H, PXL_V)); */
+ push_colorspecial();
+ x_pos_bak = PXL_H;
+ y_pos_bak = PXL_V;
+/* set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1, PXL_H, PXL_V, PXL_H + 10, PXL_V + 10); */
+ }
+ else {
+ XDVI_WARNING((stderr, "Skipping unimplemented htex special `%s'", cp));
+ push_stack(&stack, A_OTHER, htex_page_info.curr_cnt);
+ }
+ }
+ else if (memcmp(cp, "H.S end", strlen("H.S end")) == 0) {
+ /* start of anchor, link or rect. We just assume that the link
+ target will have length 0, so when we see text between H.S
+ and H.R, assume that it's the link text.
+ */
+ m_href_type = HDVIPS_LINK;
+ /* add dummy */
+ add_anchor(&htex_page_info, A_HDVIPS_HREF, "__DUMMY__", strlen("__DUMMY__"), 0, NULL);
+ htex_page_info.curr_cnt++;
+ push_stack(&stack, A_HREF, htex_page_info.curr_cnt - 1);
+ push_colorspecial();
+ x_pos_bak = PXL_H;
+ y_pos_bak = PXL_V;
+ return True;
+ }
+ else if (memcmp(cp, "H.R end", strlen("H.R end")) == 0 /* end of rect */
+ || memcmp(cp, "H.A end", strlen("H.A end")) == 0 /* end of anchor */
+ || memcmp(cp, "H.L end", strlen("H.L end")) == 0 /* end of link */
+ ) {
+ int num;
+ htexAnchorT type = pop_stack(&stack, &num);
+ if (type == A_MISMATCH)
+ return False;
+ if (resource.link_style > 1 && resource.link_color != NULL)
+ pop_colorspecial();
+ return False;
+ }
+ /* add anchor texts for hdvips links */
+ else if (memcmp(cp, "/A", 2) == 0) { /* possibly an hdvips external link */
+/* fprintf(stderr, "+++++ EXT: |%s|\n", cp); */
+ if ((ptr = strstr(cp + 2, "/GoToR")) != NULL /* external file */
+ && (ptr = strchr(ptr, '(')) != NULL) {
+ hdvips_add_anchor(&htex_page_info, A_HREF_FILE, ptr + 1);
+ }
+ else if ((ptr = strstr(cp + 2, "/URI")) != NULL /* URL */
+ && (ptr = strchr(ptr, '(')) != NULL) {
+ hdvips_add_anchor(&htex_page_info, A_HREF_URL, ptr + 1);
+ }
+ return False;
+ }
+ else if (memcmp(cp, "/L", 2) == 0) { /* possibly an hdvips internal link */
+ if ((ptr = strstr(cp + 2, "/Dest")) != NULL
+ && (ptr = strchr(ptr, '(')) != NULL) {
+ hdvips_add_anchor(&htex_page_info, A_HDVIPS_INTERNAL, ptr + 1);
+ }
+ return False;
+ }
+ else if (memcmp(cp, "/V", 2) == 0) { /* possibly an hdvips anchor */
+ if ((ptr = strstr(cp + 2, "/Dest")) != NULL
+ && (ptr = strchr(ptr, '(')) != NULL) {
+ hdvips_add_anchor(&htex_page_info, A_HDVIPS_NAME, ptr + 1);
+ }
+ return False;
+ }
+ else { /* not a start tag */
+ MYTRACE((stderr, "Xdvi warning: skipping malformed hyperref special `%s'", cp));
+ }
+ return get_href_depth(&stack);
+}
+
+void
+htex_record_position(int ulx, int uly, int w, int h)
+{
+ int lrx, lry;
+ int y_delta, x_delta;
+
+ if (!INSIDE_MANE_WIN) /* this would give wrong values */
+ return;
+
+ lrx = ulx + w;
+ lry = uly + h;
+
+ y_delta = lry - uly;
+ x_delta = lrx - ulx;
+
+ /* heuristics for creating new bounding box at what might be linebreaks */
+ if (lrx < x_pos_bak /* ordinary linebreak */
+ || lry + y_delta < y_pos_bak) { /* column break (from bottom of 1st to top 2nd column) */
+ htexAnchorT type;
+ int idx, prev, curr;
+ /* get anchor index of topmost stack item, to find the matching open tag */
+ if ((type = peek_stack(&stack, &idx)) == A_NONE) {
+/* fprintf(stderr, "!!!!!!!!!!!! couldn't find opening tag for this wrapped link!"); */
+ return;
+ }
+ ASSERT(idx >= 0, "Index out of range");
+/* fprintf(stderr, "wrapped link: index %d, type %d\n", idx, type); */
+ /* get correct idx */
+ if (m_href_type == HYPERTEX_LINK) {
+ while (htex_page_info.anchors[idx].a_href == NULL && idx > 0) {
+ idx--;
+ }
+ if (htex_page_info.anchors[idx].a_href == NULL && idx == 0) {
+ XDVI_ERROR((stderr, "Couldn't find wrapped anchor for idx %d, page %d!", idx, current_page));
+ return;
+ }
+ add_anchor(&htex_page_info, A_HREF,
+ htex_page_info.anchors[idx].a_href,
+ strlen(htex_page_info.anchors[idx].a_href),
+ 0, NULL);
+ }
+ else {
+ add_anchor(&htex_page_info, A_HREF, "__WRAPPED__", strlen("__WRAPPED__"), 0, NULL);
+ }
+ htex_page_info.curr_cnt++;
+ /* add wrapping info */
+ if (htex_page_info.have_wrapped >= 0) {
+ /* this is the only case where some other material might have come between
+ this and the previous anchor */
+ prev = htex_page_info.have_wrapped;
+ htex_page_info.have_wrapped = -1;
+ }
+ else {
+ prev = htex_page_info.curr_cnt - 2;
+ }
+ curr = htex_page_info.curr_cnt - 1;
+ ASSERT(prev >= 0, "Index out of range");
+
+/* fprintf(stderr, "setting prev to %d, curr to %d\n", prev, curr); */
+ htex_page_info.anchors[prev].next_wrapped = curr;
+ htex_page_info.anchors[curr].prev_wrapped = prev;
+ /* initialize it to cover current character */
+ set_anchor_size(&htex_page_info, htex_page_info.curr_cnt - 1, ulx, uly, lrx, lry);
+ }
+ else {
+ int prev_idx = htex_page_info.curr_cnt - 1;
+
+ if (prev_idx >= 0) {
+ enlarge_anchor_size(&htex_page_info, prev_idx, ulx, uly, lrx, lry);
+ }
+ else {
+ MYTRACE((stderr, "!!!!!!!!!!!! Bug? prev_idx < 0"));
+ }
+ }
+ x_pos_bak = lrx;
+ y_pos_bak = uly;
+}
+
+#if 0
+static void
+show_history(void)
+{
+ struct dl_list *ptr = htex_history;
+ struct history_info *info = ptr->item;
+ int i;
+
+ fprintf(stderr, "**************** history: %s, %d, %s\n", info->filename, info->page, info->anchor);
+ for (; ptr->prev != NULL; ptr = ptr->prev) { ; }
+ for (i = 0; ptr != NULL; ptr = ptr->next, i++) {
+ info = ptr->item;
+ fprintf(stderr, "elem %d: %s, %d, %s\n", i, info->filename, info->page, info->anchor);
+ MYTRACE((stderr, "elem: %p, prev: %p, next: %p", (void *)ptr, (void *)ptr->prev, (void *)ptr->next));
+ }
+}
+#endif
+
+/* check for names like foo/bar.dvi#link, return copy of
+ link truncated at the `#' if found (NULL else), and
+ save `link' into resource.anchor_pos for later use.
+ */
+static char *
+check_relative_name(const char *link)
+{
+ char *ptr;
+ TRACE_HTEX((stderr, "check_relative_name: |%s|", link));
+ if ((ptr = strchr(link, '#')) != NULL
+ && ptr > link + 4
+ && (memicmp(ptr - 4, ".dvi", 4) == 0)) {
+ char *new_link = xstrdup(link);
+ new_link[ptr - link] = '\0'; /* truncate the copy */
+ free(g_anchor_pos);
+ g_anchor_pos = xstrdup(ptr + 1);
+ g_anchor_len = strlen(g_anchor_pos);
+
+ return new_link;
+ }
+ else { /* reset g_anchor_pos */
+ free(g_anchor_pos);
+ g_anchor_pos = NULL;
+ }
+ return NULL;
+}
+
+static void
+htex_update_toolbar_navigation(void)
+{
+#if 0
+ show_history();
+#endif
+#if defined(MOTIF) && HAVE_XPM
+ tb_set_htex_back_sensitivity(htex_history->prev != NULL);
+ tb_set_htex_forward_sensitivity(htex_history->next != NULL);
+#endif
+}
+
+void
+htex_back(void)
+{
+ struct history_info *info;
+
+ if (htex_history == NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Hyperref history is empty");
+ return;
+ }
+ info = htex_history->item;
+
+ if (htex_history->prev == NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "At begin of history");
+ htex_update_toolbar_navigation();
+ return;
+ }
+
+ if (strcmp(info->filename, globals.dvi_name) != 0) { /* new filename different */
+ Boolean tried_dvi_ext = False;
+ char *new_dvi_name = NULL;
+
+ if ((new_dvi_name = open_dvi_file_wrapper(info->filename, False, False,
+ &tried_dvi_ext, False))
+ == NULL) {
+
+ statusline_print(STATUS_MEDIUM, "Re-opening file \"%s\" failed!\n", info->filename);
+ return;
+ }
+ else {
+ set_dvi_name(new_dvi_name);
+ globals.ev.flags |= EV_NEWDOC;
+ globals.ev.flags |= EV_PAGEHIST_INSERT;
+/* statusline_print(STATUS_MEDIUM, "Back to file: \"%s\"", globals.dvi_name); */
+ }
+ }
+ else {
+ page_history_insert(info->page);
+ }
+ goto_page(info->page, resource.keep_flag ? NULL : home, False);
+
+ MYTRACE((stderr, "curr page now: %d", current_page));
+ htex_history = htex_history->prev;
+
+ info = htex_history->item;
+
+#if 0
+ MYTRACE((stderr, "------ before skipping: %d, %s", info->page, info->anchor));
+ show_history();
+ while (info->page == current_page && htex_history->prev != NULL) {
+ /* skip identical locations */
+ MYTRACE((stderr, "+++++++ skipping identical page %d, %s", current_page, info->anchor));
+ htex_history = htex_history->prev;
+ info = htex_history->item;
+ }
+ MYTRACE((stderr, "------ after skipping: %d, %s", info->page, info->anchor));
+#endif
+
+ htex_update_toolbar_navigation();
+}
+
+
+void
+htex_forward(void)
+{
+ struct history_info *info;
+ char *link;
+
+ if (htex_history == NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Hyperref history is empty");
+ return;
+ }
+ if (htex_history->next == NULL) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "At end of history");
+ return;
+ }
+
+ htex_history = htex_history->next;
+ info = htex_history->item;
+ link = info->anchor;
+ /* go there */
+ if (*link == '#') { /* it's a relative link */
+ MYTRACE((stderr, "XXXXXXXX %s:%d: setting anchor to |%s|+1", __FILE__, __LINE__, info->anchor));
+ free(g_anchor_pos);
+ g_anchor_pos = xstrdup(info->anchor + 1);
+ g_anchor_len = strlen(g_anchor_pos);
+ globals.ev.flags |= EV_ANCHOR;
+ }
+ else { /* it's an absolute link */
+ char *new_linkname = NULL;
+ char *new_dvi_name = NULL;
+ Boolean tried_dvi_ext = False;
+
+ if ((new_linkname = check_relative_name(link)) != NULL)
+ link = new_linkname;
+
+ if ((new_dvi_name = open_dvi_file_wrapper(link, False, False,
+ &tried_dvi_ext, False)) == NULL) {
+ statusline_print(STATUS_MEDIUM, "Re-opening file \"%s\" failed!\n", info->filename);
+ free(new_linkname);
+ return;
+ }
+ else {
+ set_dvi_name(new_dvi_name);
+
+ globals.ev.flags |= EV_NEWDOC;
+ goto_page(0, resource.keep_flag ? NULL : home, False);
+ globals.ev.flags |= EV_PAGEHIST_INSERT;
+
+ if (g_anchor_pos != NULL)
+ globals.ev.flags |= EV_ANCHOR;
+
+/* statusline_print(STATUS_MEDIUM, "Loaded file: \"%s\"", globals.dvi_name); */
+ free(new_linkname);
+ }
+ }
+
+ htex_update_toolbar_navigation();
+}
+
+/* save this anchor in jump_history, current location in goback_history,
+ and update Motif toolbar icons
+*/
+static void
+history_save_anchor(const char *anchor, int current_page, const char *dvi_name)
+{
+ struct history_info *item;
+
+ if (htex_history == NULL) {
+ /* Insert dummy start elem. We need this to prevent dropping
+ off from the begin of the list, since otherwise a 1-elem
+ list couldn't encode the information whether we can still go
+ back. This way it will point to the dummy elem when there's
+ no way to go back. */
+ struct history_info *start_marker = XMALLOC(start_marker, sizeof *start_marker);
+ start_marker->anchor = NULL;
+ start_marker->filename = NULL;
+ start_marker->page = -1;
+ htex_history = dl_list_insert(htex_history, start_marker);
+ }
+ item = XMALLOC(item, sizeof *item);
+ item->anchor = xstrdup(anchor);
+ item->filename = xstrdup(dvi_name);
+ item->page = current_page;
+ htex_history = dl_list_truncate(dl_list_insert(htex_history, item));
+
+#if 0
+ MYTRACE((stderr, "==================== after inserting "));
+ show_history();
+#endif
+
+ htex_update_toolbar_navigation();
+
+}
+
+/*
+ * Return anchor string at coordinates x, y, and anchor count in 3rd argument,
+ * or NULL if there's no anchor at these coordinates.
+*/
+static char *
+get_anchor_at_index(int x, int y, int *count)
+{
+ int i;
+
+ for (i = 0; i < htex_page_info.curr_cnt; i++) {
+ struct anchor_info anchor = htex_page_info.anchors[i];
+/* fprintf(stderr, "getting anchor at index %d; %s\n", i, anchor.a_href); */
+ if (anchor.a_href == NULL) {
+ continue;
+ }
+ if (anchor.lry + 2 > y && anchor.uly - 1 < y /* allow some vertical fuzz */
+ && anchor.lrx > x && anchor.ulx < x) {
+ *count = i;
+ return anchor.a_href;
+ }
+ }
+ *count = -1;
+ return NULL;
+}
+
+
+/*
+ generate exposure events for anchor at index idx, and all anchors wrapping to/from it,
+ so that they will be redrawn in `visited' color
+*/
+static void
+redraw_anchors(int idx)
+{
+ struct anchor_info anchor = htex_page_info.anchors[idx];
+ int other;
+ int i = idx;
+#define DO_EXPOSE(lx,ly,rx,ry) (clearexpose(&mane, lx - 20, ly - 3, rx - lx + 26, ry - ly + 6))
+
+ /* HACK ALERT: This is a workaround for a coloring problem with wrapped anchors
+ (see regression/href/002/url-wrap-test2.dvi):
+ We can't change the color on-the-fly for a wrapped anchor, since the special
+ is pushed only at the opening tag. So for wrapped anchors, the visited colour
+ wouldn't be set correctly. Redrawing the entire page ensures this (but it's ugly).
+ Currently this hack overrides the algorithm below for all anchors that have a
+ `prev_wrapped' pointer.
+ */
+ if (htex_page_info.anchors[i].prev_wrapped != -1) {
+ globals.ev.flags |= EV_NEWPAGE;
+ XSync(DISP, False);
+ return;
+ }
+
+ DO_EXPOSE(anchor.ulx, anchor.uly, anchor.lrx, anchor.lry);
+
+ /* previous parts of wrapped anchors: */
+ for (i = idx;
+ i >= 0 && (other = htex_page_info.anchors[i].prev_wrapped) != -1;
+ i--) {
+ DO_EXPOSE(htex_page_info.anchors[other].ulx, htex_page_info.anchors[other].uly,
+ htex_page_info.anchors[other].lrx, htex_page_info.anchors[other].lry);
+ }
+
+ /* later parts of wrapped anchors: */
+ for (i = idx;
+ i < htex_page_info.curr_cnt && (other = htex_page_info.anchors[i].next_wrapped) != -1;
+ i++) {
+ DO_EXPOSE(htex_page_info.anchors[other].ulx, htex_page_info.anchors[other].uly,
+ htex_page_info.anchors[other].lrx, htex_page_info.anchors[other].lry);
+ }
+#undef DO_EXPOSE
+}
+
+
+/*
+ * Invoked when clicking on a link.
+ * newwindow == True means open new window,
+ * newwindow == False means jump to link in current window.
+ * With newwindow == True, don't update the toolbar navigation icons, since there's nothing to go back.
+ */
+Boolean
+htex_handleref(int x, int y, Boolean newwindow)
+{
+ char *link;
+ int link_num;
+
+/* fprintf(stderr, "---------- htex_handleref!\n"); */
+ if (!(globals.cursor.flags & CURSOR_LINK))
+ /* When no link cursor is shown, clicking shouldn't jump to link */
+ return False;
+
+ if ((link = get_anchor_at_index(x, y, &link_num)) != NULL) {
+ set_visited(&visited_links, current_page, link_num);
+
+ if (*link == '#') { /* it's a relative link */
+ if (newwindow) {
+ launch_xdvi(globals.dvi_name, link + 1);
+ redraw_anchors(link_num);
+ return True;
+ }
+ else {
+ history_save_anchor(link, current_page, globals.dvi_name);
+ free(g_anchor_pos);
+ g_anchor_pos = xstrdup(link + 1);
+ g_anchor_len = strlen(g_anchor_pos);
+ globals.ev.flags |= EV_ANCHOR;
+ redraw_anchors(link_num);
+ return True;
+ }
+ }
+ else { /* it's an absolute link */
+ char *new_dvi_name = NULL;
+ int pageno_bak = current_page;
+ char *new_linkname = NULL;
+ char *orig_link = link;
+ Boolean tried_dvi_ext = False;
+
+ MYTRACE((stderr, "OLD FILE: |%s|", globals.dvi_name));
+
+ if ((new_linkname = check_relative_name(link)) != NULL)
+ link = new_linkname;
+
+ if ((new_dvi_name = open_dvi_file_wrapper(link, False, newwindow,
+ &tried_dvi_ext, False)) != NULL) {
+ /* only save link in history if opening succeeds */
+ history_save_anchor(orig_link, pageno_bak, globals.dvi_name);
+ set_dvi_name(new_dvi_name);
+ if (!newwindow) {
+ globals.ev.flags |= EV_NEWDOC;
+ goto_page(0, resource.keep_flag ? NULL : home, False);
+ globals.ev.flags |= EV_PAGEHIST_INSERT;
+
+ MYTRACE((stderr, "NEW FILE: |%s|", globals.dvi_name));
+ if (g_anchor_pos != NULL)
+ globals.ev.flags |= EV_ANCHOR;
+/* statusline_print(STATUS_MEDIUM, "Loaded file: \"%s\"", dvi_name); */
+ }
+ else {
+ redraw_anchors(link_num);
+ }
+ }
+ free(new_linkname);
+ redraw_anchors(link_num);
+ return True;
+ }
+ }
+ return False;
+}
+
+/* change cursor and display anchor text in statusline */
+void
+htex_displayanchor(int x, int y)
+{
+ static int id_bak = -1;
+ static int pageno_bak = -1;
+ int id_curr;
+ char *anchor_text;
+
+ anchor_text = get_anchor_at_index(x, y, &id_curr);
+
+ if (anchor_text != NULL) { /* found an anchor */
+ if (!(globals.cursor.flags & CURSOR_LINK) && !dragging_text_selection()) {
+ globals.cursor.flags |= CURSOR_LINK;
+ globals.ev.flags |= EV_CURSOR;
+ }
+ /* to prevent flicker, print only when it differs from previous one,
+ i.e. when it either has a different ID or is on a different page: */
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0
+ && (id_curr != id_bak || current_page != pageno_bak)) {
+ statusline_print(STATUS_FOREVER, "%s", anchor_text);
+ id_bak = id_curr;
+ pageno_bak = current_page;
+ }
+ }
+ else { /* not over anchor text, reset cursor and statusline */
+ if (globals.cursor.flags & CURSOR_LINK) {
+ globals.cursor.flags &= ~CURSOR_LINK;
+ globals.ev.flags |= EV_CURSOR;
+ }
+
+ if (id_bak != -1 && (resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) {
+ statusline_clear();
+ id_bak = -1;
+ }
+ }
+}
+
+/*
+ * Invoked from all commands that change the shrink factor;
+ * forces re-computation of the anchor markers.
+*/
+void
+htex_resize_page(void)
+{
+ htex_initpage(False, True, current_page);
+}
+
+/*
+ * Invoked from all commands that reread the DVI file;
+ * resets all link infos.
+ * Note: visited_links and anchor stack data
+ * are preserved over files, so we don't need to free() them.
+ */
+void
+htex_reinit(void)
+{
+ htex_prescan_reset();
+ htex_initpage(True, True, current_page);
+}
+
+/*
+ Underline/highlight anchors if the appropriate resource is set.
+ Since this is done after the entire page is parsed, we can't use
+ the checks for fg_current and do_color_change(), but need to
+ use a separate GC instead.
+ */
+void
+htex_draw_anchormarkers(void)
+{
+ int i;
+ int rule_height = (globals.page.h / 1000.0);
+ XRectangle rect = { -1, -1, 0, 0 };
+
+ if (rule_height == 0)
+ rule_height = 1;
+
+ if (current_page == g_anchormarker.page
+ && strcmp(globals.dvi_name, g_anchormarker.filename) == 0
+ && g_anchormarker.y_pos > 0) {
+ htex_draw_anchormarker(g_anchormarker.y_pos);
+ }
+
+ if (resource.link_style == 0 || resource.link_style == 2)
+ return;
+
+ for (i = 0; i < htex_page_info.curr_cnt; i++) {
+ struct anchor_info anchor = htex_page_info.anchors[i];
+
+ if (anchor.a_href != NULL) {
+ int offset;
+ Boolean visited = False;
+
+#if 0
+ XDrawRectangle(DISP, mane.win, globals.gc.high,
+ anchor.ulx, anchor.uly,
+ anchor.lrx - anchor.ulx, anchor.lry - anchor.uly);
+
+#endif
+
+ if (is_visited(&visited_links, current_page, i)) {/* || wrapped_anchor_is_visited(i)) { */
+ visited = True;
+ }
+ offset = ANCHOR_XTRA_V_BBOX / (double)currwin.shrinkfactor + 0.5;
+
+ TRACE_HTEX((stderr, "UNDERLINE: %d, %s is %s", i, anchor.a_href,
+ visited ? "******* visited ****** " : "not visited"));
+ anchor.ulx -= currwin.base_x;
+ anchor.lrx -= currwin.base_x;
+ anchor.lry -= currwin.base_y;
+ anchor.uly -= currwin.base_y;
+
+ /* BUG ALERT: Don't use put_rule here, since this will cause a segfault
+ * with the new color code when switching density (#616920)!
+ */
+ MYTRACE((stderr, "UNDERLINE: checking if %d is visited: %d!", i, visited));
+
+/* if (clip_region_to_rect(&rect)) { */
+ if (anchor.object_type == HTEX_IMG) {
+ rect.x = anchor.ulx - 1;
+ rect.y = anchor.uly - 1;
+ rect.width = anchor.lrx - anchor.ulx + 2;
+ rect.height = anchor.lry - anchor.uly + 2;
+ if (clip_region_to_rect(&rect)) {
+ XDrawRectangle(DISP, mane.win,
+ visited ? globals.gc.visited_linkcolor : globals.gc.linkcolor,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+ }
+ else {
+ rect.x = anchor.ulx - 1;
+ rect.y = anchor.lry + offset;
+ rect.width = anchor.lrx - anchor.ulx + 2;
+ rect.height = rule_height;
+ if (clip_region_to_rect(&rect)) {
+ XFillRectangle(DISP, mane.win,
+ visited ? globals.gc.visited_linkcolor : globals.gc.linkcolor,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+ }
+ }
+ }
+}
+
+void
+launch_xdvi(const char *filename, const char *anchor_name)
+{
+#define ARG_LEN 32
+ int i = 0;
+ char *argv[ARG_LEN];
+ char *shrink_arg = NULL;
+
+ ASSERT(filename != NULL, "filename argument to launch_xdvi() mustn't be NULL");
+
+ argv[i++] = program_invocation_name;
+ /* FIXME: there's something broken with this and invoking xdvi.bin.
+ To reproduce the problem, invoke from the shell:
+ xdvi.bin -geometry 829x1172 /usr/share/texmf/doc/programs/kpathsea.dvi
+ this will run at 300dpi, i.e. ignore an .Xdefaults setting as opposed to:
+ xdvi.bin /usr/share/texmf/doc/programs/kpathsea.dvi
+
+ Also, how about the other command-line switches that might have
+ been passed to the parent instance? How about things that have been changed
+ at run-time, like shrink factor - should they be converted to command-line
+ options?
+ */
+
+ argv[i++] = "-name";
+ argv[i++] = "xdvi";
+
+ /* start the new instance with the same debug flags as the current instance */
+ if (globals.debug != 0) {
+ char debug_flag[128];
+ SNPRINTF(debug_flag, 128, "%lu", globals.debug);
+ argv[i++] = "-debug";
+ argv[i++] = debug_flag;
+ }
+
+ if (anchor_name != NULL) {
+ argv[i++] = "-anchorposition";
+ argv[i++] = (char *)anchor_name;
+ }
+
+ argv[i++] = "-s";
+ shrink_arg = XMALLOC(shrink_arg, LENGTH_OF_INT + 1);
+ sprintf(shrink_arg, "%d", currwin.shrinkfactor);
+ argv[i++] = shrink_arg;
+
+ argv[i++] = (char *)filename; /* FIXME */
+
+ argv[i++] = NULL;
+ ASSERT(i <= ARG_LEN, "Too few elements in argv[]");
+
+ if (globals.debug & DBG_HTEX) {
+ fprintf(stderr, "Invoking:\n");
+ for (i = 0; argv[i]; i++) {
+ fprintf(stderr, "%s\n", argv[i]);
+ }
+ }
+
+ /*
+ FIXME: using fork_process here hangs the new xdvi process when it tries
+ printing to stderr, so we use plain fork/exec (see comments in util.c)
+ */
+#if 0
+ fork_process(argv[0], False, NULL, NULL, NULL, argv);
+#else
+ {
+ int pid;
+ switch (pid = fork()) {
+ case -1:
+ perror("fork");
+ case 0:
+ execvp(argv[0], argv);
+ MYTRACE((stderr, "%s: Execution of %s failed.", globals.program_name, argv[0]));
+ _exit(EXIT_FAILURE);
+ default:
+ FREE(shrink_arg);
+ }
+ }
+#endif
+#undef ARG_LEN
+}
+
+#if COPY_TMP_FILE
+/* callback to remove temporary file after helper application has terminated.
+ Currently unused. Note the possible danger of a temp race if the application
+ does an fclose() on the file before ...
+*/
+static void
+remove_temp_file(int status, struct xchild *this)
+{
+ char *pathname = (char *)this->data;
+ if (WEXITSTATUS(status) == 0) {
+ unlink(pathname);
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN, NULL,
+ "Warning: Calling `%s' on `%s' terminated with non-zero status (%d)"
+ "\n(Not removing `%s')",
+ this->name, pathname, status, pathname);
+ }
+ free(pathname);
+}
+#endif
+
+void
+launch_program(const char *filename)
+{
+ const char *format_string = NULL;
+ char *content_type = NULL;
+ char *viewer = NULL;
+ char *argv[4];
+ struct stat statbuf;
+ const char *local_filename_sans_prefix;
+ char *path, *syscmd, *tmp;
+#if COPY_TMP_FILE
+ int tmp_fd;
+#endif
+ const char *ptr;
+ char *fullpath = NULL;
+ char canonical_path[MAXPATHLEN + 1];
+ Boolean needs_terminal;
+
+ TRACE_HTEX((stderr, "launch_program called with |%s|", filename));
+
+ /* is it a local file? */
+ local_filename_sans_prefix = is_local_file(filename);
+ if (local_filename_sans_prefix == NULL) { /* not local */
+ launch_browser(filename);
+ return;
+ }
+
+ /* expand the filename if it contains a relative path */
+ path = find_file(local_filename_sans_prefix, &statbuf, kpse_program_text_format);
+ if (path != NULL) {
+ /* fully canonicalize path before passing it to helper applications */
+ fullpath = REALPATH(path, canonical_path);
+ if (fullpath == NULL) {
+ XDVI_WARNING((stderr, "Couldn't canonicalize %s to full path - returning unexpanded.",
+ path));
+ fullpath = path;
+ }
+ else
+ FREE(path);
+ }
+ else {
+ XDVI_WARNING((stderr, "Couldn't find file %s; passing to application unchanged.",
+ local_filename_sans_prefix));
+ /* if it doesn't exist, maybe the user has encoded some magic in the
+ filename; in that case, pass it to the application unchanged. */
+ fullpath = (char *)local_filename_sans_prefix;
+ }
+
+ TRACE_HTEX((stderr, "fullpath: |%s|", fullpath));
+ content_type = figure_mime_type(fullpath);
+ ASSERT(content_type != NULL, "figure_mime_type() should have returned a valid type (eventually a fallback)");
+
+ /* make it safe to pass the argument to system() or `sh -c',
+ by escaping all `dangerous' characters: */
+ tmp = shell_escape_string(fullpath);
+ fullpath = tmp;
+
+ if ((viewer = figure_viewer(content_type, &format_string, &needs_terminal, fullpath)) == NULL) {
+ /* warn user if no application has been found. Help text needs to be constructed at
+ run-time, since we want the correct content-type in it. */
+#if 0
+ char *errmsg = NULL;
+#else
+ char *errmsg = xstrdup("Please assign an application to the MIME type `");
+ errmsg = xstrcat(errmsg, content_type);
+ errmsg = xstrcat(errmsg, "' in your ~/.mailcap file. "
+ "E.g. if you want to view the file with netscape, add the following line to your ~/.mailcap:\n");
+ errmsg = xstrcat(errmsg, content_type);
+ errmsg = xstrcat(errmsg, "; netscape -raise -remote 'openURL(%%s,new-window)'\n\n");
+#endif
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ errmsg,
+ "Could not determine an application for the file %s, MIME type `%s'.",
+ fullpath, content_type);
+ /* FIXME: something's wrong with the memory allocation scheme here -
+ can't free errmsg, it's already free'd inside popup_message() ?? */
+ /* free(errmsg); */
+ free(fullpath);
+ return;
+ }
+
+#if COPY_TMP_FILE
+ /* copy the file to a temporary location before passing it to the
+ viewer. This is e.g. how Acroread does it. This should fix the
+ problem with xdvizilla without -no-rm for DVI files (see comment
+ in figure_viewer(), mime.c).
+ SU 2003/10/02: currently I can't reproduce the xdvizilla problem
+ any more - it seems that for xdvi files, argv[0] will be invoked
+ anyway? Also, copying the files to tmp may break figure locations
+ and relative links for DVI files. Suspended this for the time being.
+ */
+ tmp = NULL;
+ if ((tmp_fd = xdvi_temp_fd(&tmp)) == -1) {
+ XDVI_ERROR((stderr, "couldn't create temporary file; not calling helper application."));
+ return;
+ }
+ TRACE_HTEX((stderr, "copying to temporary location: |%s->%s|", fullpath, tmp));
+ if (!copy_file(fullpath, tmp)) {
+ XDVI_ERROR((stderr, "couldn't copy %s to temporary file %s; not invoking helper application.",
+ fullpath, tmp));
+ return;
+ }
+ free(fullpath);
+ fullpath = tmp;
+#endif
+
+ if (strlen(format_string) > 0) {
+ ptr = find_format_str(viewer, format_string);
+ }
+ else { /* countrary to RFC 1343, we don't pass stuff via pipes (too bothersome) */
+ ptr = strchr(viewer, '\0');
+ }
+
+ if (needs_terminal) {
+ size_t offset = strlen("xterm -e ");
+ syscmd = xmalloc(offset + strlen(viewer) + strlen(fullpath) + 1);
+ strcpy(syscmd, "xterm -e ");
+ memcpy(syscmd + offset, viewer, ptr - viewer);
+ strcpy(syscmd + offset + (ptr - viewer), fullpath);
+ strcpy(syscmd + offset + (ptr - viewer) + strlen(fullpath), ptr + strlen(format_string));
+
+ }
+ else {
+ syscmd = xmalloc(strlen(viewer) + strlen(fullpath) + 1);
+ memcpy(syscmd, viewer, ptr - viewer);
+ strcpy(syscmd + (ptr - viewer), fullpath);
+ strcpy(syscmd + (ptr - viewer) + strlen(fullpath), ptr + strlen(format_string));
+ }
+
+ /*
+ mailcap(4) says that the mailcap command shall be passed to system(),
+ so we musn't use fork_process() directly here. Instead, we pass the command
+ to `/bin/sh -c', but via fork_process so that
+
+ - xdvi doesn't hang if the process doesn't return;
+ - we can still catch the return value if `sh -c' exits with an error
+ (e.g. if the viewer command is not found).
+
+ Note however that this doesn't mimick most of POSIX's system() semantics.
+ */
+ TRACE_HTEX((stderr, "execv(\"/bin/sh -c %s\")", syscmd));
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = syscmd;
+ argv[3] = NULL;
+#if COPY_TMP_FILE
+ fork_process("/bin/sh", False, globals.dvi_file.dirname, remove_temp_file, fullpath, argv);
+#else
+ fork_process("/bin/sh", False, globals.dvi_file.dirname, NULL, NULL, argv);
+#endif
+
+ FREE(viewer);
+#if COPY_TMP_FILE
+#else
+ FREE(fullpath);
+#endif
+ FREE(syscmd);
+}
+
+void
+htex_set_anchormarker(int y)
+{
+ Position drawing_x;
+
+ /* erase old marker if it's on the same page as the new marker, after
+ cancelling the old timeout so that it won't affect the new marker */
+ if (m_href_timeout_id)
+ XtRemoveTimeOut(m_href_timeout_id);
+ htex_erase_anchormarker(NULL, NULL);
+ XFlush(DISP);
+
+ XtVaGetValues(globals.widgets.draw_widget, XtNx, &drawing_x, NULL);
+ g_anchormarker.page = current_page;
+ free(g_anchormarker.filename);
+ g_anchormarker.filename = xstrdup(globals.dvi_name);
+ g_anchormarker.y_pos = y;
+ g_anchormarker.x_pos = DEFAULT_MARKER_X_OFFSET + -drawing_x;
+ m_href_timeout_id = XtAppAddTimeOut(app, STATUS_SHORT * 1000, htex_erase_anchormarker, (XtPointer)NULL);
+}
+
+static void
+htex_draw_anchormarker(int y)
+{
+ int x;
+ XPoint points[3];
+
+ Position drawing_x, clip_w;
+
+ XtVaGetValues(globals.widgets.clip_widget, XtNwidth, &clip_w, NULL);
+ XtVaGetValues(globals.widgets.draw_widget, XtNx, &drawing_x, NULL);
+
+ /* compute offset to draw into visible region */
+ x = DEFAULT_MARKER_X_OFFSET + -drawing_x;
+
+ /* Eventually erase old marker, to avoid `smearing' on horizontal scrolls. */
+ if (x != g_anchormarker.x_pos) {
+ clearexpose(&mane, g_anchormarker.x_pos - 1, y - 3, 20, 10);
+ }
+ g_anchormarker.x_pos = x;
+
+ points[0].x = x + 10;
+ points[1].x = x + 19;
+ points[2].x = x + 10;
+ points[0].y = y - 3;
+ points[1].y = y + 2;
+ points[2].y = y + 7;
+
+ XFillRectangle(DISP, mane.win, globals.gc.visited_linkcolor, x, y, 10, 4);
+ XFillPolygon(DISP, mane.win, globals.gc.visited_linkcolor, points, 3, Convex, CoordModeOrigin);
+ /* -1 indicates that no horizontal scrolling is wanted, since the
+ anchormarker will always be horizontally positioned inside the
+ visible area.
+ */
+ scroll_page_if_needed(-1, -1, y + 3, y - 3);
+}
+
+
+static void
+htex_erase_anchormarker(XtPointer client_data, XtIntervalId *id)
+{
+ Position clip_w;
+
+ UNUSED(client_data);
+ UNUSED(id);
+
+ if (globals.debug & DBG_EVENT) {
+ fprintf(stderr, "htex_erase_anchormarker called!\n");
+ }
+
+ if (m_href_timeout_id == (XtIntervalId)0) { /* timeout was removed but callback happened anyway */
+ return;
+ }
+
+ m_href_timeout_id = (XtIntervalId)0;
+ /* clear the mark if we're in the same file and on the same page as the mark */
+ if (g_anchormarker.filename != NULL
+ && strcmp(globals.dvi_name, g_anchormarker.filename) == 0
+ && g_anchormarker.page == current_page) {
+ XtVaGetValues(globals.widgets.clip_widget, XtNwidth, &clip_w, NULL);
+ clearexpose(&mane, 0, g_anchormarker.y_pos - 3, clip_w, 10);
+ }
+ g_anchormarker.y_pos = -1;
+}
+
diff --git a/Build/source/texk/xdvik/hypertex.h b/Build/source/texk/xdvik/hypertex.h
new file mode 100644
index 00000000000..f103b45ef4e
--- /dev/null
+++ b/Build/source/texk/xdvik/hypertex.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef HYPERTEX_H_
+#define HTEXTEX_H_
+
+/* fallbacks if parsing user-specified colors fails */
+#define LINK_COLOR_FALLBACK "BLUE2"
+#define VISITED_LINK_COLOR_FALLBACK "Purple4"
+
+extern const char *is_local_file(const char *filename);
+extern void launch_program(const char *filename);
+extern void launch_xdvi(const char *filename, const char *anchor_name);
+extern Boolean htex_handleref(int x, int y, Boolean newwindow);
+extern void htex_reinit(void);
+extern void htex_resize_page(void);
+extern void htex_draw_anchormarkers(void);
+extern void htex_record_position(int, int, int, int);
+
+extern void htex_initpage(Boolean dvi_file_changed, Boolean size_changed, int pageno);
+
+typedef enum { HTEX_ANCHOR_NUM, HTEX_ANCHOR_STRING } htexPrescanTypeT;
+
+struct htex_prescan_data {
+ int pageno;
+ int anchor_num;
+ htexPrescanTypeT scan_type;
+};
+
+typedef enum { HTEX_TEXT, HTEX_IMG } htexObjectT;
+
+/* prescanning stuff */
+extern Boolean htex_prescan_special(const char *str, int str_len, struct htex_prescan_data *data);
+extern int htex_prescan_get_depth(void);
+extern size_t htex_prescan_get_mismatched_anchor_num(size_t depth);
+extern void htex_prescan_save(void);
+extern void htex_prescan_reset_firstpass(void);
+extern void htex_prescan_restore(int pageno);
+extern void htex_prescan_initpage(void);
+extern void htex_prescan_carry_over(int old_page, int new_page);
+extern void htex_set_anchorsize(int x, int y, int w, int h);
+extern void htex_set_objecttype(htexObjectT type);
+
+extern void htex_reset_page(int pageno);
+extern void htex_displayanchor(int, int);
+extern void htex_set_anchormarker(int y);
+extern void htex_back(void);
+extern void htex_forward(void);
+
+extern Boolean htex_scan_anchor(const char *special, size_t len);
+
+#endif /* HTEXTEX_H_ */
diff --git a/Build/source/texk/xdvik/image-magick.c b/Build/source/texk/xdvik/image-magick.c
new file mode 100644
index 00000000000..50bf201956a
--- /dev/null
+++ b/Build/source/texk/xdvik/image-magick.c
@@ -0,0 +1,1422 @@
+/*
+ Imagemagick support for xdvik, written by Zhang Linbo <zlb@lsec.cc.ac.cn>
+
+ 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.
+*/
+
+/*
+ TODO:
+
+ 1. Specials other than 'psfile=' and 'em:graph' which include
+ image files.
+
+ [ NOTE SU: I consider this more or less done now with the backtick
+ parsing ;-) ]
+
+ 2. Use an XtWorkProc or similar to do some background pre-processing
+ of image files before they are displayed.
+
+ 3. Replace popen() by fork and explicit pipes, and make the
+ use of xdvi_temp_fd safer.
+
+ 4. PS figs are always clipped to the bbox defined in the special
+ string, which is not what we want when clip=false.
+ The problem can be partly solved by increasing the value of
+ the PSBW macro, or we may get the correct bbox by reading the
+ '%%BoundingBox' or '%%HiresBoundingBox' lines in the PS file
+ and set the image geometry accordingly.
+
+ 5. The code only(?) works with true color displays.
+
+ 6. There's also work to do to respond to window events in
+ load_image() and display_image() functions.
+*/
+#include <ctype.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "dvi-init.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "util.h"
+#include "special.h"
+#include "image-magick.h"
+
+#ifdef MAGICK /* entire file */
+
+#include "magick/api.h"
+#if MAGICK_VER_MAJOR > 5 || MAGICK_VER_MINOR >= 4
+# include "magick/xwindow.h" /* IM >= 5.4 */
+#else
+# include "magick/xwindows.h" /* IM <= 5.3 */
+#endif
+
+#if MAGICK_VER_MAJOR > 5 || MAGICK_VER_MINOR >= 4 /* >= 5.4 */
+# define CATCH_EXCEPTION(e) do { \
+ if (e.severity != UndefinedException) CatchException(&e); } while (0)
+#elif MAGICK_VER_MINOR >= 3 /* 5.3 */
+# define CATCH_EXCEPTION(e) if (image == NULL) \
+ MagickWarning(e.severity, e.reason, e.description);
+#else /* <= 5.2 (no check) */
+# define CATCH_EXCEPTION(e) if (image == NULL) \
+ MagickWarning(e.severity, e.message, e.qualifier);
+#endif
+
+#if 0
+#define CATCH_EXCEPTION(e) /* do nothing */
+#endif
+
+#ifndef False
+# define False 0
+#endif
+
+#ifndef True
+# define True 1
+#endif
+
+#define TWOPI (2*3.141592653589793)
+
+static double ROUND_tmp;
+#define ROUND(x) ( (ROUND_tmp=(x)) >= 0 ? (long)(ROUND_tmp + 0.5) : \
+ - (long)(- ROUND_tmp + 0.5) )
+
+static void
+showtime(const char *msg)
+{
+ if (globals.debug & DBG_PS) {
+ static double time0 = -1;
+ double time;
+ struct timeval tv;
+
+ gettimeofday(&tv, (struct timezone *) 0);
+ time = tv.tv_sec + (double) tv.tv_usec * 1e-6;
+ if (time0 < 0)
+ time0 = time;
+ fprintf(stderr, " %-40s %0.4f\n", msg, time - time0);
+ }
+}
+
+#define DPI ( resource.pixels_per_inch*0.001*magnification/mane.shrinkfactor )
+
+typedef struct XDviImageInfo {
+ Boolean clip;
+ int rwi, rhi, angle;
+ double llx, lly, urx, ury;
+ char filename[MaxTextExtent];
+} XDviImageInfo;
+
+typedef struct {
+ XDviImageInfo info;
+ XImage *ximage; /* ximage */
+ unsigned long bgpixel; /* background pixel */
+ int xoff, yoff; /* offsets in pixels */
+} XDviImage;
+
+static size_t cache_size = 0;
+/* default value for cache_limit (16MB), it can be specified with the
+ * "-magick_cache size" option */
+static size_t cache_limit = 16 * 1024 * 1024;
+static int ncached = 0;
+static XDviImage *cache = NULL;
+
+static char *magick_tmp;
+static double current_dpi = -1;
+
+/* Input image types */
+enum {
+ TYPE_UNKNOWN, /* unknown */
+ TYPE_CONVERT, /* `convert ... */
+};
+static int image_type; /* type of current input image */
+
+static void
+cleanup(void)
+{
+ if (magick_tmp != NULL)
+ unlink(magick_tmp);
+}
+
+static void
+free_ximage(XImage * ximage)
+{
+ if (ximage == NULL)
+ return;
+ if (ximage->data != NULL) {
+ free(ximage->data);
+ ximage->data = NULL;
+ }
+ XDestroyImage(ximage);
+}
+
+static void
+clear_cache()
+{
+ XDviImage *c;
+ if (!ncached)
+ return;
+ for (c = cache; c < cache + ncached; c++)
+ free_ximage(c->ximage);
+ free(cache);
+ ncached = 0;
+ cache = NULL;
+ cache_size = 0;
+}
+
+static void
+parse_backtick(char *fn)
+{
+ char *p, *q, *r, c;
+
+ if (fn[0] != '`')
+ return;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: parsing backtick command |%s|\n", fn);
+
+#ifdef __GNUC__
+#warning FIXME: add code to execute the cmd then load the output file, \
+ if '-allowshell' is effective and the user requests it \
+ somehow (slow but reliable).
+#endif
+
+ fn[0] = '\0';
+ p = fn + 1;
+ /* Skip 'env' and 'VAR=value' */
+ do {
+ while (isspace((int)*p))
+ ++p;
+ q = p;
+ while (*q != '\0' && !isspace((int)*q))
+ ++q;
+ if (*q == '\0' || q <= p)
+ return;
+ if (((r = strchr(p, '=')) == NULL || r >= q) &&
+ (!isspace((int)*q) || strncmp(p, "env", 3)))
+ break;
+ p = q;
+ } while (1);
+
+ /* Now [p ... q-1] is the command name */
+ if (q - p == 7 && !memcmp(p, "convert", 7))
+ image_type = TYPE_CONVERT;
+ else
+ image_type = TYPE_UNKNOWN;
+ p = q;
+ do {
+ while (isspace((int)*p))
+ ++p;
+ q = p;
+ if (*q == '`' || *q == '\'' || *q == '"') {
+ c = *p;
+ ++q;
+ while (*q != '\0' && *q != c)
+ q++;
+ if (*q != '\0')
+ q++;
+ }
+ else {
+ while (*q != '\0' && !isspace((int)*q))
+ q++;
+ }
+#ifdef __GNUC__
+#warning FIXME: check for some cmdline options
+ break;
+#endif
+ } while (1);
+ *q = '\0';
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: filename=|%s|\n", p);
+
+ /* check for the case `kpsewhich -n ... #1` */
+ if (*p == '`') {
+#if 0
+ /* WARNING: unsafe! */
+ FILE *pipe;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: executing %s\n", p);
+ if (*(--q) == '`')
+ *q = '\0';
+ if ((pipe = popen(p + 1, "r")) == NULL)
+ return;
+ fscanf(pipe, "%s", fn);
+ pclose(pipe);
+ return;
+#else
+ if (memcmp(++p, "kpsewhich", sizeof("kpsewhich") - 1))
+ return;
+#ifdef __GNUC__
+#warning FIXME: better make KPSE library call here.
+#endif
+ if (*(--q) == '`')
+ --q;
+ while (q >= p && isspace((int)*q))
+ --q;
+ if (q < p)
+ return;
+ *(q + 1) = '\0';
+ while (q >= p && !isspace((int)*q))
+ --q;
+ p = q + 1;
+#endif
+ }
+
+ strcpy(fn, p);
+}
+
+static Boolean
+imagick_eps_to_jpeg(const char *fullpath,
+ unsigned long *columns, unsigned long *rows,
+ XDviImage *img, PixelPacket *bgcolor,
+ double xdpi, double ydpi)
+{
+ size_t size;
+#ifdef __GNUC__
+#warning FIXME: security (check 'allowshell'?), backticks, pathname canonicalization,
+ /* note SU: better use fork()/exec() here, popen() is too unsafe. */
+#endif
+ static char *cmdline = NULL;
+ static size_t cmdline_size = 0;
+ static char *fmt = "%s -q -dBATCH -dMaxBitmap=300000000 "
+ "-dNOPAUSE -dNOSAFER -sDEVICE=jpeg "
+ "-dTextAlphaBits=4 -dGraphicsAlphaBits=4 "
+ "-g%ldx%ld -r%0.4fx%0.4f -sOutputFile=%s - -c quit";
+ static const char strsafe[] =
+ "{ << /PermitFileReading [ (*) ] /PermitFileWriting [ ] /PermitFileControl [ ] "
+ ">> setuserparams .locksafe "
+ "} stopped pop\n";
+ FILE *pipe;
+
+ showtime("PS/EPS -> JPEG:");
+ /* Add a border to the drawing box (PSBW=border width in bp) */
+#define PSBW 1
+ *columns += ROUND(2 * PSBW / 72.0 * xdpi);
+ *rows += ROUND(2 * PSBW / 72.0 * ydpi);
+ img->xoff = ROUND(PSBW / 72.0 * xdpi);
+ img->yoff = -ROUND(PSBW / 72.0 * ydpi);
+
+ size = strlen(fmt) + 25 * 2 + 10 * 2 + strlen(magick_tmp) + strlen(resource.gs_path) + 1;
+ if (size > cmdline_size) {
+ cmdline_size = size;
+ cmdline = xrealloc(cmdline, cmdline_size);
+ }
+ unlink(magick_tmp);
+ sprintf(cmdline, fmt, resource.gs_path, *columns, *rows, xdpi, ydpi,
+ magick_tmp);
+ if ((pipe = popen(cmdline, "w")) == NULL) {
+ fprintf(stderr, "%s: Cannot execute %s, ignoring image %s.\n",
+ globals.program_name, resource.gs_path, fullpath);
+ return False;
+ }
+
+#define ColorToPixelPacket(c) ((c*((1L<<(QuantumDepth))-1L)+32768L)/65535L)
+#define UnifiedColorValue(c) ((c)/(double)((1L<<(QuantumDepth))-1L))
+#ifdef __GNUC__
+#warning FIXME: how to control roundoff error which may produce a \
+ different backgroung pixel in the output image?
+#endif
+#if COLOR
+ bgcolor->red = ColorToPixelPacket(bg_current->color.r);
+ bgcolor->green = ColorToPixelPacket(bg_current->color.g);
+ bgcolor->blue = ColorToPixelPacket(bg_current->color.b);
+#else
+ bgcolor->red = bgcolor->green = bgcolor->blue = ColorToPixelPacket(65535);
+#endif
+ bgcolor->opacity = (1L << QuantumDepth) - 1L;
+
+#ifdef __GNUC__
+#warning FIXME: how to set bg color within gs (instead of filling the bbox) ?
+#endif
+ if (resource.gs_safer) {
+ fprintf(pipe, strsafe);
+ }
+ /* fill PS paper with background color */
+ fprintf(pipe,
+ "newpath -5 -5 moveto %f 0 rlineto "
+ "0 %f rlineto %f 0 rlineto 0 %f rlineto "
+ "closepath %f %f %f setrgbcolor fill\n",
+ img->info.urx - img->info.llx + 2 * (PSBW + 5),
+ img->info.ury - img->info.lly + 2 * (PSBW + 5),
+ -(img->info.urx - img->info.llx + 2 * (PSBW + 5)),
+ -(img->info.ury - img->info.lly + 2 * (PSBW + 5)),
+ UnifiedColorValue(bgcolor->red),
+ UnifiedColorValue(bgcolor->green),
+ UnifiedColorValue(bgcolor->blue));
+
+ /* shift PS coordinates */
+ fprintf(pipe, "%f %f translate\n", -img->info.llx + PSBW, -img->info.lly + PSBW);
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " clip=%s\n", img->info.clip ? "yes" : "no");
+ if (img->info.clip) {
+ fprintf(pipe, "newpath %f %f moveto %f 0 rlineto 0 %f rlineto "
+ "%f 0 rlineto 0 %f rlineto closepath clip\n",
+ img->info.llx, img->info.lly, img->info.urx - img->info.llx,
+ img->info.ury - img->info.lly, -(img->info.urx - img->info.llx),
+ -(img->info.ury - img->info.lly));
+ }
+ fprintf(pipe, "%f %f moveto\n", img->info.llx, img->info.lly);
+ fprintf(pipe, "(%s) run showpage\n", fullpath);
+ pclose(pipe);
+ return True;
+}
+
+
+static Image *
+rotate_image(XDviImage *img, Image *image, ExceptionInfo exception)
+{
+ Image *tmp_image;
+ unsigned long w = image->columns, h = image->rows;
+ double sin_a = sin(img->info.angle * (TWOPI / 360));
+ double cos_a = cos(img->info.angle * (TWOPI / 360));
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "\t rotating image by %d degrees\n",
+ img->info.angle);
+
+ /* adjust xoff, yoff, assuming (0,0) the origin of rotation */
+ if (img->xoff || img->yoff) {
+ double a, b;
+ a = img->xoff * cos_a + img->yoff * sin_a;
+ b = -img->xoff * sin_a + img->yoff * cos_a;
+ img->xoff = ROUND(a);
+ img->yoff = ROUND(b);
+ }
+
+ showtime("RotateImage:");
+ tmp_image = RotateImage(image, -(double)img->info.angle, &exception);
+ DestroyImage(image);
+ image = tmp_image;
+ CATCH_EXCEPTION(exception);
+ if (image == NULL)
+ return NULL;
+ /*
+ * _______________________________________
+ * | * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * |* *|
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | * * |
+ * | O (origin) |
+ * O--------------------------------------
+ * (lower-left corner of image box after rotation)
+ */
+ if (img->info.angle <= 90) {
+ img->xoff += ROUND(h * sin_a);
+ }
+ else if (img->info.angle <= 180) {
+ img->xoff += ROUND(h * sin_a - w * cos_a);
+ img->yoff += ROUND(h * cos_a);
+ }
+ else if (img->info.angle <= 270) {
+ img->xoff -= ROUND(w * cos_a);
+ img->yoff += ROUND(w * sin_a + h * cos_a);
+ }
+ else {
+ img->yoff += ROUND(w * sin_a);
+ }
+ return image;
+}
+
+static Image *
+crop_shift_image(XDviImage *img, Image *image,
+ unsigned long *columns, unsigned long *rows,
+ double xscale, double yscale,
+ ExceptionInfo exception)
+{
+ /* ZLB: the code below works for the case where the BoundingBox
+ * of the PS figure generated by the shell command is (0 0 w h),
+ * where w and h are the pixel width and height of the input image.
+ * (this is true for the program 'convert' without options).
+ * The image should then be cropped or/and shifted depending
+ * on the value of 'clip' */
+ int w = image->columns, h = image->rows;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: type of input image = CONVERT\n");
+
+ if (!img->info.clip) {
+ /* We only need to shift the image */
+ img->xoff = +ROUND(xscale * DPI * img->info.llx / 72.0);
+ img->yoff = -ROUND(yscale * DPI * img->info.lly / 72.0);
+ *columns = ROUND(xscale * DPI * w / 72.0);
+ *rows = ROUND(yscale * DPI * h / 72.0);
+ }
+ else {
+ int llx = ROUND(img->info.llx);
+ int lly = ROUND(img->info.lly);
+ int urx = ROUND(img->info.urx);
+ int ury = ROUND(img->info.ury);
+
+ if (llx < 0) {
+ img->xoff = +ROUND(xscale * DPI * llx / 72.0);
+ llx = 0;
+ }
+ if (lly < 0) {
+ img->yoff = -ROUND(yscale * DPI * lly / 72.0);
+ lly = 0;
+ }
+ if (urx > w)
+ urx = w;
+ if (ury > h)
+ ury = h;
+
+ if ((urx - llx) < 1 || (urx - llx) < 1) {
+ DestroyImage(image);
+ return NULL;
+ }
+
+ if (llx != 0 || lly != 0 || urx != w || ury != h) {
+ /* Crop the image */
+ Image *tmp_image;
+ RectangleInfo geo;
+ geo.width = urx - llx;
+ geo.height = ury - lly;
+ geo.x = llx;
+ geo.y = h - ury;
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "\t cropping image (%d %d %d %d)\n",
+ llx, lly, urx, ury);
+ showtime("CropImage:");
+ tmp_image = CropImage(image, &geo, &exception);
+ DestroyImage(image);
+ image = tmp_image;
+ CATCH_EXCEPTION(exception);
+ if (image == NULL)
+ return NULL; /* error cropping image */
+ }
+ *columns = ROUND(xscale * DPI * (urx - llx) / 72.0);
+ *rows = ROUND(yscale * DPI * (ury - lly) / 72.0);
+ }
+ return image;
+}
+
+
+/* parse and return the `magick_cache' resource size_str */
+static long
+parse_cache_setting(const char *size_str)
+{
+ char *p;
+ long size = strtol(size_str, &p, 0);
+ switch (*p) {
+ case 'g':
+ case 'G':
+ size *= 1024;
+ /* fall through */
+ case 'm':
+ case 'M':
+ size *= 1024;
+ /* fall through */
+ case 'k':
+ case 'K':
+ size *= 1024;
+ break;
+ default:
+ if (*p != '\0') {
+ fprintf(stderr, "Magick: invalid suffix (%c) in "
+ "magick_cache option\n", *p);
+ }
+ }
+ return size;
+}
+
+static XDviImage *
+load_image(XDviImageInfo *info)
+{
+ static ExceptionInfo exception;
+ static ImageInfo *image_info;
+ static XResourceInfo resource_info;
+ static XVisualInfo visual_info;
+ static XStandardColormap map_info;
+ static XPixelInfo pixel_info;
+ static XWindowInfo window_info;
+ static Boolean initialized = False;
+ static Boolean disabled = False;
+
+ static XDviImage img = { {False, 0, 0, 0, 0, 0, 0, 0, ""}, NULL, 0, 0, 0 };
+
+ Image *image, *tmp_image;
+ double xscale, yscale, xdpi, ydpi;
+ int n;
+ unsigned long columns, rows;
+ char density[40];
+ size_t size;
+ char *fn = info->filename;
+ XDviImage *c;
+ PixelPacket bgcolor;
+
+ struct stat statbuf;
+ char *path, *fullpath;
+ char canonical_path[MAXPATHLEN + 1];
+
+ if (disabled)
+ return NULL;
+
+ parse_backtick(info->filename);
+ if (info->filename[0] == '\0') {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: skipping malformed backtick command.\n");
+ return NULL;
+ }
+ else {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: filename=|%s|\n", info->filename);
+ }
+
+ img.info = *info;
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: load_image: fn=%s\n", fn);
+
+ /* check for changes in mag/shrink/resolution */
+ if (fabs(current_dpi - DPI) > 1e-4) {
+ current_dpi = DPI;
+ clear_cache();
+ }
+
+ /* look it up in the cache */
+ if (ncached) {
+ for (c = cache; c < cache + ncached; c++) {
+ if (memcmp(&c->info, info, sizeof *info))
+ continue;
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " Image found in cache.\n");
+ return c;
+ }
+ }
+
+ if (!initialized) {
+ magick_tmp = NULL;
+ if ((n = xdvi_temp_fd(&magick_tmp)) == -1) {
+ fprintf(stderr, "Magick: cannot create tmp filename, disabled.\n");
+ disabled = True;
+ return NULL;
+ }
+ /* FIXME: mustn't close filedescriptor returned by xdvi_temp_fd(),
+ else we have a race condition again; see e.g.
+ http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/avoid-race.html
+ */
+ close(n);
+ unlink(magick_tmp);
+ atexit(cleanup); /* remove magick_tmp at exit. */
+
+ showtime("Initializing load_image:");
+ InitializeMagick("xdvi.bin");
+ GetExceptionInfo(&exception);
+ image_info = CloneImageInfo((ImageInfo *) NULL);
+
+ XGetResourceInfo(XrmGetStringDatabase(""), "xdvi", &resource_info);
+ /* resource_info.debug = 1; */
+ if (!XMatchVisualInfo(DISP, XScreenNumberOfScreen(SCRN),
+ G_depth, G_visual->class, &visual_info)) {
+ fprintf(stderr, "Magick: can't get visual info, image disabled.\n");
+ disabled = True;
+ return NULL;
+ }
+ XGetMapInfo(&visual_info, G_colormap, &map_info);
+ XGetWindowInfo(DISP, &visual_info, &map_info, &pixel_info,
+ (XFontStruct *) NULL, &resource_info, &window_info);
+
+ if (resource.magick_cache != NULL) {
+ cache_limit = parse_cache_setting(resource.magick_cache);
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " Setting magick_cache to %lu\n",
+ (unsigned long)cache_limit);
+ }
+ initialized = True;
+ }
+
+ xscale = info->rwi / (double) ((int) (10 * (info->urx - info->llx) + .5));
+ yscale = info->rhi / (double) ((int) (10 * (info->ury - info->lly) + .5));
+ xdpi = xscale * DPI;
+ ydpi = yscale * DPI;
+ /* Compute scaled size of the image */
+ columns = ROUND(DPI * info->rwi * 0.1 / 72);
+ rows = ROUND(DPI * info->rhi * 0.1 / 72);
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "\tscale=%0.2fx%0.2f, dpi=%0.2fx%0.2f, size=%ldx%ld\n",
+ xscale, yscale, xdpi, ydpi, columns, rows);
+
+ /* expand and canonicalize path name */
+ path = find_file(fn, &statbuf, kpse_pict_format);
+ if (path != NULL) {
+ fullpath = REALPATH(path, canonical_path);
+ if (fullpath == NULL) {
+ XDVI_WARNING((stderr, "Couldn't canonicalize %s to full path - returning unexpanded.",
+ path));
+ fullpath = path;
+ }
+ else {
+ free(path);
+ }
+ }
+ else {
+ fprintf(stderr, "%s: %s:%d: Can't find image file %s!\n",
+ globals.program_name, __FILE__, __LINE__, fn);
+ return NULL;
+ }
+
+ /* If the file is PS/EPS transform it to JPEG first (faster) */
+ n = strlen(fullpath);
+ if ((n >= 3 && !memicmp(fullpath + n - 3, ".ps", 3)) ||
+ (n >= 4 && !memicmp(fullpath + n - 4, ".eps", 4))) {
+ if (!imagick_eps_to_jpeg(fullpath, &columns, &rows, &img, &bgcolor, xdpi, ydpi)) {
+ return NULL;
+ }
+ /* Should we append the 'JPEG:' prefix to the filename to help
+ * ImageMagick to identify the file format? */
+ fullpath = magick_tmp;
+ }
+ else {
+ img.xoff = img.yoff = 0;
+ }
+
+ strcpy(image_info->filename, fullpath);
+ showtime("ReadImage:");
+ if (fullpath == magick_tmp) {
+ /* seems 'density' only affects image size of PS/EPS files */
+ sprintf(density, "%0.2fx%0.2f", xdpi, ydpi);
+ image_info->density = density;
+ image_info->units = PixelsPerInchResolution;
+ }
+ image = ReadImage(image_info, &exception);
+ CATCH_EXCEPTION(exception);
+ unlink(magick_tmp);
+ if (image == NULL) /* error loading image */
+ return NULL;
+
+ /* Set background color for PS/EPS fig */
+ if (fullpath == magick_tmp) /* input is PS */
+ image->background_color = bgcolor;
+
+ if (globals.debug & DBG_PS) {
+ int i = image->units;
+ fprintf(stderr, "\t image size = %ldx%ld\n",
+ image->columns, image->rows);
+ fprintf(stderr, "\t image resolution = %0.2fx%0.2f (units=%s)\n",
+ image->x_resolution, image->y_resolution,
+ i == UndefinedResolution ? "???" :
+ i == PixelsPerInchResolution ? "PPI" : "PPCM");
+ }
+
+ if (fullpath != magick_tmp) { /* non PS image */
+ /* Note: (info->llx info->lly info->urx info->ury) should be
+ * regarded as the viewport */
+ if (image_type == TYPE_CONVERT) {
+ image = crop_shift_image(&img, image, &columns, &rows, xscale, yscale, exception);
+ }
+ else {
+ /* Do nothing. The image will be scaled to the size of the bbox.
+ * ZLB: the output will be identical to dvips iff the bbox of
+ * the PS figure generated by the shell command is equal to
+ * (info->llx info->lly info->urx info->ury).
+ * (this is true if the bbox set via 'bb', 'viewport', etc.,
+ * is equal to the real bbox of the PS figure) */
+ }
+
+ if (columns != image->columns || rows != image->rows) {
+ /* Scale image */
+ if (globals.debug & DBG_PS) {
+ fprintf(stderr, "\t scaling image %ldx%ld -> %ldx%ld\n",
+ image->columns, image->rows, columns, rows);
+ }
+ showtime("ScaleImage:");
+ tmp_image = ScaleImage(image, columns, rows, &exception);
+ DestroyImage(image);
+ image = tmp_image;
+ CATCH_EXCEPTION(exception);
+ if (image == NULL)
+ return NULL; /* error resizing image */
+ }
+ }
+
+ /* rotate image */
+ if (info->angle) {
+ image = rotate_image(&img, image, exception);
+ }
+
+#if 0
+ DescribeImage(image, stdout, 1 /* verbosity */ );
+ DisplayImages(image_info, image);
+#endif
+
+#define XStandardPixel(map,color,dx) (unsigned long) (map.base_pixel + \
+ (((color).red * map.red_max + (1L << (dx - 1L))) / ((1L << dx) - 1L)) * map.red_mult + \
+ (((color).green * map.green_max + (1L << (dx - 1L))) / ((1L << dx) - 1L)) * map.green_mult + \
+ (((color).blue * map.blue_max + (1L << (dx - 1L))) / ((1L << dx) - 1L)) * map.blue_mult)
+
+ img.bgpixel = XStandardPixel(map_info, image->background_color, 16);
+ if (img.ximage != NULL) {
+ free_ximage(img.ximage);
+ img.ximage = NULL;
+ }
+#undef XStandardPixel
+
+ /* Transform to XImage */
+ window_info.id = mane.win;
+ window_info.annotate_context = globals.gc.copy;
+ /*
+ FIXME: If this isn't set to false, running on a remote display may
+ lead to `Badaccess (no permission to access private resource)' X
+ errors (only with ImageMagick >= 5.4 - zlb has emailed the
+ developers about this).
+ Setting it to false always might slightly hurt performance - how
+ to check for remoteness? Parse the DISPLAY variable?
+ */
+ window_info.shared_memory = False;
+ showtime("XMakeImage:");
+ XGetPixelPacket(DISP, &visual_info, &map_info,
+ &resource_info, image, &pixel_info);
+ n = XMakeImage(DISP, &resource_info, &window_info, image,
+ image->columns, image->rows);
+
+ /* Since XDestroyImage doesn't know how to free window_info.ximage->data,
+ * we simply copy window_info.ximage. The next call of XMakeImage
+ * will free both window_info.ximage->data and window_info.ximage.
+ */
+ DestroyImage(image);
+ if (!n)
+ return NULL;
+ img.ximage = XCreateImage(DISP, G_visual, G_depth, ZPixmap, 0, NULL,
+ window_info.ximage->width,
+ window_info.ximage->height, BMBITS, 0);
+ if (img.ximage == NULL)
+ return NULL;
+ *img.ximage = *(window_info.ximage);
+ size = img.ximage->bytes_per_line * img.ximage->height;
+ img.ximage->data = malloc(size ? size : 1); /* NOTE: no xmalloc! */
+ if (img.ximage->data == NULL) {
+ fprintf(stderr, "Magick: cannot allocate memory for ximage data.\n");
+ XDestroyImage(img.ximage);
+ img.ximage = NULL;
+ return NULL;
+ }
+ if (size)
+ memcpy(img.ximage->data, window_info.ximage->data, size);
+
+ size += sizeof(XDviImage) + sizeof(XImage);
+ if (cache_size + size > cache_limit) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " image not cached (cache limit).\n");
+ return &img;
+ }
+
+ c = realloc(cache, sizeof(XDviImage) * (ncached + 1)); /* NOTE: no xrealloc! */
+ if (c == NULL) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " image not cached (cache alloc).\n");
+ return &img;
+ }
+ cache_size += size;
+ cache = c;
+ c = cache + (ncached++);
+ *c = img;
+ img.ximage = NULL; /* so next call won't delete this ximage */
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " image cached (cache_size=%uKB, limit=%uKB).\n",
+ cache_size / 1024, cache_limit / 1024);
+#if 0
+ DestroyImageInfo(image_info);
+ DestroyExceptionInfo(&exception);
+ DestroyMagick();
+#endif
+
+ return c;
+}
+
+static void
+display_image(XDviImage * img, int xul, int yul,
+ const struct window_expose_info *expose,
+ const GC gc)
+{
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, " display_image: pos=%d, %d\n", xul, yul);
+
+ xul -= img->xoff;
+ yul -= img->yoff;
+
+#if 0
+ XPutImage(DISP, mane.win, globals.gc.copy, img->ximage, 0, 0,
+ xul, yul - img->ximage.height + 1,
+ img->ximage.width, img->ximage.height);
+#else
+ /* Try to make background pixels transparent */
+ {
+ XImage *scr;
+ int x0 = xul;
+ int y0 = yul - img->ximage->height + 1;
+ int w = img->ximage->width;
+ int h = img->ximage->height;
+ int xoff = 0;
+ int yoff = 0;
+ int x, y;
+
+ if (x0 + w <= expose->min_x || x0 >= expose->max_x ||
+ y0 + h <= expose->min_y || y0 >= expose->max_y)
+ return;
+ if (x0 < expose->min_x) {
+ xoff = expose->min_x - x0;
+ x0 = expose->min_x;
+ w -= xoff;
+ }
+ if (x0 + w > expose->max_x)
+ w = expose->max_x - x0 + 0;
+ if (y0 < expose->min_y) {
+ yoff = expose->min_y - y0;
+ y0 = expose->min_y;
+ h -= yoff;
+ }
+ if (y0 + h > expose->max_y)
+ h = expose->max_y - y0 + 0;
+
+ {
+ /* Need to double check the bounds here, because redraw_page() in
+ * events.c may set larger bounding box (expose->min_x, expose->min_y, etc.)
+ * than actual viewport causing 'BadMatch' error in XGetImage().
+ *
+ * Here we clip the rectangle w*h+x0+y0 with the root window. */
+ XWindowAttributes a;
+ Status status;
+ Window child;
+
+ status = XGetWindowAttributes(DISP, mane.win, &a);
+ if (!status || a.map_state != IsViewable)
+ return;
+ XTranslateCoordinates(DISP, mane.win, a.root, x0, y0, &x, &y,
+ &child);
+ XGetWindowAttributes(DISP, a.root, &a);
+ if (x + w <= a.x || x >= a.x + a.width || y + h <= a.y
+ || y >= a.y + a.height) return;
+ if (x < a.x) {
+ x0 += a.x - x;
+ xoff += a.x - x;
+ w -= a.x - x;
+ x = a.x;
+ }
+ if (x + w > a.x + a.width)
+ w = a.x + a.width - x;
+ if (y < a.y) {
+ y0 += a.y - y;
+ yoff += a.y - y;
+ h -= a.y - y;
+ y = a.y;
+ }
+ if (y + h > a.y + a.height)
+ h = a.y + a.height - y;
+#if 0
+ XDrawLine(DISP, mane.win, gc, x0, y0, x0 + w - 1, y0);
+ XDrawLine(DISP, mane.win, gc, x0 + w - 1, y0, x0 + w - 1, y0 + h - 1);
+ XDrawLine(DISP, mane.win, gc, x0 + w - 1, y0 + h - 1, x0, y0 + h - 1);
+ XDrawLine(DISP, mane.win, gc, x0, y0 + h - 1, x0, y0);
+ XDrawLine(DISP, mane.win, gc, x0, y0, x0 + w - 1, y0 + h - 1);
+ XDrawLine(DISP, mane.win, gc, x0 + w - 1, y0, x0, y0 + h - 1);
+
+ XDrawLine(DISP, mane.win, gc, expose->min_x,
+ expose->min_y, expose->max_x, expose->min_y);
+ XDrawLine(DISP, mane.win, gc, expose->max_x,
+ expose->min_y, expose->max_x, expose->max_y);
+ XDrawLine(DISP, mane.win, gc, expose->max_x,
+ expose->max_y, expose->min_x, expose->max_y);
+ XDrawLine(DISP, mane.win, gc, expose->min_x,
+ expose->max_y, expose->min_x, expose->min_y);
+ XDrawLine(DISP, mane.win, gc, expose->max_x,
+ expose->max_y, expose->min_x, expose->min_y);
+ XDrawLine(DISP, mane.win, gc, expose->min_x,
+ expose->max_y, expose->max_x, expose->min_y);
+#endif
+ }
+
+#ifdef __GNUC__
+#warning FIXME: GetImage may still produce 'BadMatch' when dragging \
+ the window around (toward outside of the desktop).
+#endif
+ scr = XGetImage(DISP, mane.win, x0, y0, w, h, AllPlanes, ZPixmap);
+
+#warning FIXME: the loops are only a quick hack and are slow.
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++) {
+ unsigned long pixel = 0;
+ pixel = XGetPixel(img->ximage, x + xoff, y + yoff);
+ if (pixel == img->bgpixel)
+ continue;
+ XPutPixel(scr, x, y, pixel);
+ }
+ XPutImage(DISP, mane.win, globals.gc.copy, scr, 0, 0, x0, y0, w, h);
+ XDestroyImage(scr);
+ }
+#endif
+ showtime(" Done.");
+}
+
+static void
+render_image_file(XDviImageInfo *info, int x, int y)
+{
+ XDviImage *im = NULL;
+ int w, h;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: render_image_file: pos=(%d,%d)\n", x, y);
+
+#ifdef __GNUC__
+#warning FIXME: immediate return if image not exposed.
+#endif
+
+ if (!INSIDE_MANE_WIN)
+ return;
+
+ info->angle = bbox_angle >= 0 ? bbox_angle % 360 : 360 - (-bbox_angle) % 360;
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: render_image_file: angle=%d\n", info->angle);
+
+ if (resource.postscript && (im = load_image(info)) != NULL)
+ display_image(im, x, y, &globals.win_expose, globals.gc.rule);
+
+ if (im != NULL && resource.postscript == 1)
+ return;
+
+ /* Draw bbox of the image */
+ w = ROUND(DPI * info->rwi / 720.0);
+ h = ROUND(DPI * info->rhi / 720.0);
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: render_image_file: box=%dx%d+%d+%d\n",
+ w, h, x, y - h + 1);
+
+ if (!info->angle) {
+ XDrawRectangle(DISP, currwin.win, globals.gc.high, x, y - h + 1, w, h);
+ }
+ else
+ {
+#if 1
+ bbox_valid = True;
+ bbox_width = w;
+ bbox_height = bbox_voffset = h;
+ save_bbox();
+ bbox_valid = False;
+#else
+ /* code borrowed from special.c:draw_bbox() */
+ double sin_a = sin(info->angle * (TWOPI / 360));
+ double cos_a = cos(info->angle * (TWOPI / 360));
+ double a, b, c, d;
+
+ a = cos_a * (w-1);
+ b = -sin_a * (w-1);
+ c = -sin_a * (h-1);
+ d = -cos_a * (h-1);
+
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ x, y, x + ROUND(a), y + ROUND(b));
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ x + ROUND(a), y + ROUND(b),
+ x + ROUND(a + c), y + ROUND(b + d));
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ x + ROUND(a + c), y + ROUND(b + d),
+ x + ROUND(c), y + ROUND(d));
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ x + ROUND(c), y + ROUND(d), x, y);
+#endif
+ }
+}
+
+/* Process EPSF specials */
+
+static Boolean
+epsf_special(char *cp)
+{
+ char *filename;
+ unsigned filename_len;
+ char *p;
+ int n;
+ unsigned long flags = 0, u;
+ double rwi, rhi;
+ enum { LLX, LLY,
+ URX, URY,
+ RWI, RHI,
+ HSIZE, VSIZE,
+ HOFFSET, VOFFSET,
+ HSCALE, VSCALE,
+ ANGLE
+ };
+ XDviImageInfo info;
+
+ struct {
+ double val;
+ const char *key;
+ long mask;
+ } key_info[] = {
+ { 0, "llx", 0x0001 },
+ { 0, "lly", 0x0002 },
+ { 0, "urx", 0x0004 },
+ { 0, "ury", 0x0008 },
+ { 0, "rwi", 0x0010 },
+ { 0, "rhi", 0x0020 },
+ { 0, "hsize", 0x0040 },
+ { 0, "vsize", 0x0080 },
+ { 0, "hoffset", 0x0100 },
+ { 0, "voffset", 0x0200 },
+ { 0, "hscale", 0x0400 },
+ { 0, "vscale", 0x0800 },
+ { 0, "angle", 0x1000 },
+ };
+
+ memset(&info, 0, sizeof info); /* for validating memcmp(&info, ... */
+
+ filename = cp;
+ if (*cp == '\'' || *cp == '"') {
+ do
+ ++cp;
+ while (*cp != '\0' && *cp != *filename);
+ filename_len = cp - filename - 1;
+ if (*cp == *filename)
+ ++cp;
+ ++filename;
+ }
+ else {
+ while (*cp != '\0' && !isspace((int)*cp))
+ ++cp;
+ filename_len = cp - filename;
+ }
+
+ if (filename_len + 1 > MaxTextExtent) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: filename too long, passing to psgs.c\n");
+ return False;
+ }
+
+ memcpy(info.filename, filename, filename_len); /* no need to terminate because of memset(...) above */
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: epsf_special: filename = '%s'\n",
+ info.filename);
+
+ /* Scan for EPSF keywords */
+ while (*cp != '\0') {
+ while (isspace((int)*cp))
+ ++cp;
+ p = cp;
+ while (*p != '=' && !isspace((int)*p) && *p != '\0')
+ p++;
+ n = p - cp;
+ if (!n)
+ break;
+ if (*p == '=')
+ ++p;
+ while (isspace((int)*p))
+ ++p;
+
+ if (!memcmp(cp, "clip", n)) {
+ /* this is the only key without value */
+ info.clip = True;
+ }
+ else {
+ size_t i;
+ Boolean found = False;
+ for (i = 0; !found && i < XtNumber(key_info); i++) {
+ if (memicmp(cp, key_info[i].key, n) == 0) {
+ if (sscanf(p, "%lf", &(key_info[i].val)) == 1) {
+ flags |= key_info[i].mask;
+ while (!isspace((int)*p) && *p != '\0')
+ ++p;
+ found = True;
+ }
+ else {
+ fprintf(stderr, "Magick: invalid value for %s\n", key_info[i].key);
+ return False;
+ }
+ }
+ }
+
+ if (!found) {
+ i = *(cp + n);
+ *(cp + n) = '\0';
+ fprintf(stderr,"Magick: ignoring unknown EPSF key \"%s\".\n", cp);
+ *(cp + n) = i;
+ /* skip '=...' */
+ while (*p != '\0' && !isspace((int)*p))
+ ++p;
+ }
+ }
+ cp = p;
+ }
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: epsf_special: flags = 0x%lx\n", flags);
+
+ /* only accept the special when llx, lly, urx, ury are properly defined */
+ u = key_info[LLX].mask | key_info[LLY].mask |
+ key_info[URX].mask | key_info[URY].mask;
+ if ((flags & u) != u)
+ return False;
+
+#ifdef __GNUC__
+#warning keywords to handle: [hv]size, [hv]offset, [hv]scale, angle \
+ (ZLB: not used by the graphicx/graphics packages)
+#endif
+ if (flags & (key_info[HSIZE].mask | key_info[VSIZE].mask |
+ key_info[HOFFSET].mask | key_info[VOFFSET].mask |
+ key_info[HSCALE].mask | key_info[VSCALE].mask |
+ key_info[ANGLE].mask))
+ fprintf(stderr, "Magick: warning: EPSF keywords '[hv]size', "
+ "'[hv]offset', '[hv]scale', and 'angle' are not "
+ "implemented.\n");
+
+ info.urx = key_info[URX].val;
+ info.ury = key_info[URY].val;
+ info.llx = key_info[LLX].val;
+ info.lly = key_info[LLY].val;
+ rwi = key_info[RWI].val;
+ rhi = key_info[RHI].val;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: epsf_special: llx=%0.2f, lly=%0.2f, "
+ "urx=%0.2f, ury=%0.2f\n",
+ info.llx, info.lly, info.urx, info.ury);
+
+ if (info.urx - info.llx < 1 || info.ury - info.lly < 1)
+ return False;
+ if (info.urx - info.llx > 1e+4 || info.ury - info.lly > 1e+4)
+ return False;
+ if (fabs(info.llx) > 1e+10 || fabs(info.lly) > 1e+10)
+ return False;
+
+ if (!(flags & (key_info[RWI].mask | key_info[RHI].mask))) {
+ /* both rwi and rhi undefined */
+ rwi = 10 * (info.urx - info.llx);
+ rhi = 10 * (info.ury - info.lly);
+ }
+ else if (!(flags & key_info[RWI].mask)) {
+ /* rwi undefined, rhi defined */
+ rwi = rhi * (info.urx - info.llx) / (info.ury - info.lly);
+ }
+ else if (!(flags & key_info[RHI].mask)) {
+ /* rhi undefined, rwi defined */
+ rhi = rwi * (info.ury - info.lly) / (info.urx - info.llx);
+ }
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: epsf_special: rwi=%f, rhi=%f\n", rwi, rhi);
+
+ if (rwi < 1 || rhi < 1)
+ return False;
+
+ /* We don't want IM to process large images (>16MB) */
+ if (DPI * rwi / 720 * DPI * rhi / 720 * G_depth / 8 / 1024 / 1024 > 16) {
+ p = filename + (n = filename_len);
+ if ((n >= 3 && !memicmp(p - 3, ".ps", 3)) ||
+ (n >= 4 && !memicmp(p - 4, ".eps", 4))) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: image too large, passing to psgs.c\n");
+ return False;
+ }
+ else {
+ /* don't pass non-PS files to psgs.c */
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: image too large, ignored.\n");
+ return True;
+ }
+ }
+
+ info.rwi = ROUND(rwi);
+ info.rhi = ROUND(rhi);
+
+ render_image_file(&info, PXL_H - currwin.base_x, PXL_V - currwin.base_y);
+
+ return True;
+}
+
+static char *
+emgraph_get_dimen(char *cp, double *v)
+{
+ char *p;
+ typedef struct {
+ int name_len;
+ char *name;
+ double factor;
+ } Unit;
+ Unit *u;
+ /* table for converting an arbitrary unit to bp */
+#define UNIT(u) sizeof(u)-1, u
+ static Unit units[] = {
+ { UNIT("bp"), 1.0 },
+ { UNIT("in"), 72.0 },
+ { UNIT("cm"), 72.0 / 2.54 },
+ { UNIT("mm"), 72.0 / 2.54 * 0.1 },
+ { UNIT("pt"), 72.0 / 72.27 },
+ { UNIT("sp"), 72.0 / 72.27 / 65536.0 },
+ { UNIT("pc"), 12.0 * 72.0 / 72.27 },
+ { UNIT("dd"), 1238.0 / 1157.0 * 72.0 / 72.27 },
+ { UNIT("cc"), 12.0 * 1238.0 / 1157.0 * 72.0 / 72.27 }
+ };
+
+ *v = strtod(cp, &p);
+ if (p == NULL) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: can't get dimension, image ignored.\n");
+ return NULL;
+ }
+
+ while (isspace((int)*p))
+ ++p;
+ for (u = units; u < units + XtNumber(units); u++)
+ if (!memicmp(p, u->name, u->name_len))
+ break;
+ if (u >= units + XtNumber(units)) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: unknown unit, image ignored.\n");
+ return NULL;
+ }
+ *v *= u->factor;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: unit=%s, len=%d, factor=%0.4f, value=%0.4f\n",
+ u->name, u->name_len, u->factor, *v);
+
+ if (*v < 0.01 || *v > 10000) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: invalid dimension, image ignored.\n");
+ return NULL;
+ }
+
+ return p + u->name_len;
+}
+
+static Boolean
+emgraph_special(char *cp)
+{
+ char *p;
+ double w, h;
+ XDviImageInfo info;
+
+ memset(&info, 0, sizeof info);
+
+ /* get filename */
+ while (isspace((int)*cp))
+ ++cp;
+ p = cp;
+ while (!isspace((int)*p) && *p != '\0' && *p != ',')
+ ++p;
+ if ((unsigned)(p - cp) >= sizeof info.filename) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: filename too long, image ignored.\n");
+ return False;
+ }
+ if (p <= cp) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: empty filename, image ignored.\n");
+ return False;
+ }
+ memcpy(info.filename, cp, p - cp); /* no need to terminate because of memset(...) above */
+
+ cp = p;
+
+ /* get width */
+ if ((cp = strchr(cp, ',')) == NULL) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: width undefined, image ignored.\n");
+ return False;
+ }
+ if ((cp = emgraph_get_dimen(++cp, &w)) == NULL)
+ return False;
+
+ /* get height */
+ if ((cp = strchr(cp, ',')) == NULL) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: height undefined, image ignored.\n");
+ return False;
+ }
+ if ((cp = emgraph_get_dimen(++cp, &h)) == NULL)
+ return False;
+
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: filename=\"%s\", width=%0.2f, height=%0.2f\n",
+ info.filename, w, h);
+
+ info.llx = info.lly = 0;
+ info.urx = w;
+ info.ury = h;
+ info.rwi = ROUND(10 * w);
+ info.rhi = ROUND(10 * h);
+
+ if (info.rwi < 1 || info.rhi < 1)
+ return False;
+
+ render_image_file(&info, PXL_H - currwin.base_x,
+ PXL_V - currwin.base_y + ROUND(h / 72 * DPI) - 1);
+
+ return True;
+}
+
+/* Filter specials. Returns True if the special has been processed
+ * by ImageMagick, False otherwise. */
+Boolean
+Magick_parse_special(char *cp)
+{
+ switch (*cp) {
+ case 'p':
+ case 'P':
+ if (!memicmp(cp, "psfile", 6)) {
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: parsing string |%s|\n", cp);
+ cp += 6;
+ while (isspace((int)*cp))
+ ++cp;
+ if (*cp != '=')
+ return False;
+ do
+ ++cp;
+ while (isspace((int)*cp));
+ return epsf_special(cp);
+ }
+ break;
+ case 'e':
+ case 'E':
+ if (!memicmp(cp, "em:", 3)) {
+ cp += 3;
+ while (isspace((int)*cp))
+ ++cp;
+ if (memicmp(cp, "graph", 5))
+ return False;
+ cp += 5;
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "Magick: parsing string |em:graph %s|\n", cp);
+ return emgraph_special(cp);
+ }
+ break;
+ }
+
+ return False;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MAGICK */
diff --git a/Build/source/texk/xdvik/image-magick.h b/Build/source/texk/xdvik/image-magick.h
new file mode 100644
index 00000000000..dee730a5b70
--- /dev/null
+++ b/Build/source/texk/xdvik/image-magick.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef IMAGE_MAGICK_H_
+#define IMAGE_MAGICK_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#ifdef MAGICK
+extern Boolean Magick_parse_special(char *cp);
+#endif /* MAGICK */
+
+#endif /* IMAGE_MAGICK_H_ */
+
diff --git a/Build/source/texk/xdvik/mime.c b/Build/source/texk/xdvik/mime.c
new file mode 100644
index 00000000000..1f1e13ee282
--- /dev/null
+++ b/Build/source/texk/xdvik/mime.c
@@ -0,0 +1,653 @@
+/* Copyright (c) 1994-1999 All rights reserved. */
+/* Written from scratch July 30, 1994, by A. P. Smith. */
+
+/* Copyright (c) 2003-2004 the xdvik development team */
+
+/*
+ Read mime.types and mailcap entries to check what
+ viewers to invoke on a new file.
+
+ Patch by Allin Cottrell (cottrell@ricardo.ecn.wfu.edu) to
+ invokeviewer applied 30/11/98.
+
+ Patched further in january 1999 by Nicolai Langfeldt
+ (janl@math.uio.no) to allow saner mime typing.
+
+ Rewritten by Stefan Ulrich <stefanulrich@users.sourceforge.net>
+ on 2003/03/25 for better RFC 1343 conformance.
+
+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.
+
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "hypertex.h"
+#include "xdvi-debug.h"
+#include "util.h"
+#include "string-utils.h"
+#include "mime.h"
+#include "browser.h"
+#include "message-window.h"
+
+#include <ctype.h>
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/variable.h"
+#include "kpathsea/c-pathmx.h"
+
+/* default settings if $EXTENSIONMAPS and $MAILCAPS is not set */
+
+static const char *const DEFAULT_EXTENSIONMAPS =
+ "$HOME/.mime.types:/etc/mime.types:/usr/etc/mime.types:/usr/local/etc/mimetypes";
+
+static const char *const DEFAULT_MAILCAPS =
+ "$HOME/.mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap";
+
+struct mime_map {
+ char *content_type;
+ char *extensions;
+};
+
+static struct mime_map default_mimemap[] = {
+ {"application/postscript", "ai eps epsf ps",},
+ {"application/octet-stream", "bin",},
+ {"application/oda", "oda",},
+ {"application/pdf", "pdf",},
+ {"application/rtf", "rtf",},
+ {"application/x-mif", "mif",},
+ {"application/x-csh", "csh",},
+ {"application/x-dvi", "dvi Dvi DVI",},
+ {"application/x-hdf", "hdf",},
+ {"application/x-latex", "latex",},
+ {"application/x-netcdf", "nc cdf",},
+ {"application/x-sh", "sh",},
+ {"application/x-tcl", "tcl",},
+ {"application/x-tex", "tex",},
+ {"application/x-texinfo", "texinfo texi",},
+ {"application/x-troff", "t tr roff",},
+ {"application/x-troff-man", "man",},
+ {"application/x-troff-me", "me",},
+ {"application/x-troff-ms", "ms",},
+ {"application/x-wais-source", "src",},
+ {"application/zip", "zip",},
+ {"application/x-bcpio", "bcpio",},
+ {"application/x-cpio", "cpio",},
+ {"application/x-gtar", "gtar",},
+ {"application/x-shar", "shar",},
+ {"application/x-sv4cpio", "sv4cpio",},
+ {"application/x-sv4crc", "sv4crc",},
+ {"application/x-tar", "tar",},
+ {"application/x-ustar", "ustar",},
+ {"audio/basic", "au snd",},
+ {"audio/x-aiff", "aif aiff aifc",},
+ {"audio/x-wav", "wav",},
+ {"image/gif", "gif",},
+ {"image/ief", "ief",},
+ {"image/jpeg", "jpeg jpg jpe",},
+ {"image/tiff", "tiff tif",},
+ {"image/x-cmu-raster", "ras",},
+ {"image/x-portable-anymap", "pnm",},
+ {"image/x-portable-bitmap", "pbm",},
+ {"image/x-portable-graymap", "pgm",},
+ {"image/x-portable-pixmap", "ppm",},
+ {"image/x-rgb", "rgb",},
+ {"image/x-xbitmap", "xbm",},
+ {"image/x-xpixmap", "xpm",},
+ {"image/x-xwindowdump", "xwd",},
+ {"text/html", "html htm sht shtml",},
+ {"text/plain", "txt",},
+ {"text/richtext", "rtx",},
+ {"text/tab-separated-values", "tsv",},
+ {"text/x-setext", "etx",},
+ {"video/mpeg", "mpeg mpg mpe",},
+ {"video/quicktime", "qt mov",},
+ {"video/x-msvideo", "avi",},
+ {"video/x-sgi-movie", "movie",},
+ {"application/gzip", "gz",},
+ {"application/compress", "Z",},
+ {"application/bzip", "bz",},
+ {"application/bzip2", "bz2",},
+};
+
+
+struct mailcap_map {
+ char *content_type;
+ char *command; /* command string */
+ char *testcmd; /* value of the `test=' field, or NULL if no test field present */
+ Boolean needsterminal; /* whether the `needsterminal' flag has been specified for this entry */
+ const char *format_string; /* format specifier ("%s" or "%u" or "") */
+};
+
+static struct mailcap_map default_mailcap[] = {
+ {"audio/*", "showaudio %s", NULL, False, False},
+ {"image/*", "xv %s", NULL, False, False},
+ {"video/mpeg", "mpeg_play %s", NULL, False, False},
+ {"application/pdf", "acroread %s", NULL, False, False},
+ {"text/html", "netscape-raise -remote 'openURL(%s,new-window)'", NULL, False, False},
+ {"application/postscript", "ghostview %s", NULL, False, False},
+ {"application/x-dvi", "xdvi %s", NULL, False, False},
+};
+
+static struct mime_map *m_mimemap = NULL;
+static int m_mimemap_currlen = 0;
+static int m_mimemap_size = 0;
+
+static struct mailcap_map *m_mailcap = NULL;
+static int m_mailcap_currlen, m_mailcap_size = 0;
+
+static const size_t MIME_ALLOC_STEP = 64;
+
+/* Utility function:
+ Read a line from a config file, dealing with continued lines
+ (ending with '\[ \t]*').
+ The *linebuf argument is re-alloced as needed from its initial size alloc_len.
+ The length of the read line is returned as ret_len.
+ The lineno int is by the number of lines read.
+ Trailing whitespace and newline is removed, and either the line,
+ or NULL for EOF is returned.
+*/
+static char *
+read_config_line(const char *filename, FILE *fp, char **linebuf,
+ size_t alloc_len, size_t *ret_len,
+ int *lineno)
+{
+ Boolean read_complete_line = False;
+ *ret_len = 0;
+ while (!read_complete_line) {
+ if ((fgets((*linebuf) + *ret_len, alloc_len - *ret_len, fp)) == NULL) {
+ if (*ret_len == 0) /* at EOF */
+ return NULL;
+ else /* nothing read, but we have a result from previous loop iteration */
+ return *linebuf;
+ }
+ (*lineno)++;
+ *ret_len = strlen(*linebuf);
+ if (*ret_len > 0 && (*linebuf)[*ret_len - 1] != '\n') {
+ /* catch the special case of missing NL at EOF */
+ if (*ret_len < alloc_len - 1) {
+ XDVI_WARNING((stderr, "%s, line %d: missing newline at end of file.", filename, *lineno));
+ return *linebuf;
+ }
+ /* buffer too short, need to re-allocate */
+ alloc_len *= 2;
+ *linebuf = xrealloc(*linebuf, alloc_len);
+ }
+ else if (*ret_len > 2
+ && (*linebuf)[*ret_len - 1] == '\n'
+ && ((*linebuf)[*ret_len - 2] == '\\'
+ || isspace((int)(*linebuf)[*ret_len - 2]))) {
+ /* we may have a continued line */
+ /* chop off trailing whitespace */
+ while (*ret_len > 1 && isspace((int)(*linebuf)[*ret_len - 2]))
+ (*ret_len)--;
+ if (*ret_len > 1 && (*linebuf)[*ret_len - 2] != '\\') { /* no continued line */
+ read_complete_line = True;
+ }
+ else /* overwrite backslash and newline at next read */
+ *ret_len -= 2;
+ }
+ else
+ read_complete_line = True;
+ }
+ /* chop off trailing NL */
+ (*linebuf)[--(*ret_len)] = '\0';
+ return *linebuf;
+}
+
+static void
+read_mime_file(FILE *fp, const char *filename, int *mime_line)
+{
+ int i;
+ const size_t line_len = 1024;
+ size_t ret_len = 0;
+ char *linebuf = xmalloc(line_len);
+ char *cp, *cp2;
+
+ int dummy = 0;
+ TRACE_HTEX((stderr, "reading mime file \"%s\"", filename));
+ while ((read_config_line(filename, fp, &linebuf, line_len, &ret_len, &dummy)) != NULL) {
+ if (linebuf[ret_len] == '\n')
+ linebuf[ret_len] = '\0';
+
+ cp = linebuf;
+ while (isspace((int)*cp))
+ cp++;
+ if (*cp == '#')
+ continue;
+
+ /* split either on tab or on whitespace */
+ if ((cp2 = strchr(cp, '\t')) == NULL && (cp2 = strchr(cp, ' ')) == NULL)
+ continue;
+ *cp2 = '\0'; /* Terminate cp string */
+ cp2++;
+ while (isspace((int)*cp2))
+ cp2++;
+ if (*cp2 == '\0')
+ continue; /* No extensions list */
+ if (*mime_line >= m_mimemap_size) {
+ m_mimemap_size += MIME_ALLOC_STEP;
+ m_mimemap = xrealloc(m_mimemap, m_mimemap_size * sizeof *m_mimemap);
+ for (i = *mime_line; i < m_mimemap_size; i++) {
+ m_mimemap[i].content_type = m_mimemap[i].extensions = NULL;
+ }
+ }
+#if 0
+ fprintf(stderr, "========== type %d: |%s| extension: |%s|\n", *mime_line, cp, cp2);
+#endif
+ free(m_mimemap[*mime_line].content_type);
+ m_mimemap[*mime_line].content_type = xstrdup(cp);
+ free(m_mimemap[*mime_line].extensions);
+ m_mimemap[*mime_line].extensions = xstrdup(cp2);
+
+ (*mime_line)++;
+ }
+ free(linebuf);
+}
+
+static char *
+maybe_expand_homedir(const char *path)
+{
+ char *newpath = NULL;
+ TRACE_HTEX((stderr, "maybe_expand_homedir: |%s|", path));
+ if (memcmp(path, "$HOME", strlen("$HOME")) == 0) {
+ newpath = xstrdup(getenv("HOME"));
+ newpath = xstrcat(newpath, path + strlen("$HOME"));
+ }
+ else if (path[0] == '~') {
+ newpath = expand_homedir(path);
+ if (newpath == NULL) {
+ XDVI_WARNING((stderr, "Couldn't expand path `%s'", path));
+ }
+ }
+ TRACE_HTEX((stderr, "maybe_expand_homedir: after expansion: |%s|", newpath ? newpath : "<NULL>"));
+ return newpath;
+}
+
+
+static void
+read_mailcap(FILE *fp, const char *filename, int *mailcap_line)
+{
+ size_t alloc_len = 1024;
+ size_t ret_len = 0;
+ char *linebuf = xmalloc(alloc_len);
+ int lineno = 0;
+
+ TRACE_HTEX((stderr, "reading mailcap file \"%s\"", filename));
+
+ while ((read_config_line(filename, fp, &linebuf, alloc_len, &ret_len, &lineno)) != NULL) {
+ Boolean error = False;
+ int i;
+ size_t n, num_items;
+ char **items;
+ char *ptr = linebuf;
+
+ while (isspace((int)*ptr)) {
+ ptr++;
+ ret_len--;
+ }
+ if (*ptr == '#' || *ptr == '\0') /* comments or empty lines */
+ continue;
+
+ /* split line into fields */
+ items = split_line(ptr, ';', 0, ret_len, &num_items);
+
+ if (num_items == 0) {
+ XDVI_WARNING((stderr, "%s, line %d: skipping malformed line \"%s\" (no command specified)",
+ filename, lineno, linebuf));
+ error = True;
+ }
+ else if (num_items == 1 || (num_items >= 2 && strlen(items[1]) == 0)) {
+ XDVI_WARNING((stderr, "%s, line %d: skipping malformed line \"%s\" (empty command)",
+ filename, lineno, linebuf));
+ error = True;
+ }
+
+ if (error) {
+ for (n = 0; n < num_items; n++)
+ free(items[n]);
+ free(items);
+ continue;
+ }
+
+ /* resize m_mailcap */
+ while (*mailcap_line >= m_mailcap_size) {
+ m_mailcap_size += MIME_ALLOC_STEP;
+ m_mailcap = xrealloc(m_mailcap, m_mailcap_size * sizeof *m_mailcap);
+ for (i = *mailcap_line; i < m_mailcap_size; i++) {
+ m_mailcap[i].content_type = NULL;
+ m_mailcap[i].command = NULL;
+ m_mailcap[i].needsterminal = False;
+ m_mailcap[i].testcmd = NULL;
+ }
+ }
+
+ for (n = 0; n < num_items; n++) {
+ if (n == 0) { /* first field: content-type */
+ m_mailcap[*mailcap_line].content_type = items[n];
+ /*
+ * add \/\* to content-type if it only consists of one field
+ * (it's not clear to me from RFC 1343 how this should be handled)
+ */
+ if (strchr(m_mailcap[*mailcap_line].content_type, '/') == NULL) {
+ m_mailcap[*mailcap_line].content_type = xstrcat(m_mailcap[*mailcap_line].content_type, "/*");
+ }
+ }
+ else if (memcmp(items[n], "test=", strlen("test=")) == 0) {
+ m_mailcap[*mailcap_line].testcmd = xstrdup(items[n] + strlen("test="));
+ free(items[n]);
+ }
+ else if (memcmp(items[n], "needsterminal", strlen("needsterminal")) == 0) { /* set flag */
+ m_mailcap[*mailcap_line].needsterminal = True;
+ free(items[n]);
+ }
+ else if (memcmp(items[n], "copiousoutput", strlen("copiousoutput")) == 0
+ || memcmp(items[n], "compose=", strlen("compose=")) == 0
+ || memcmp(items[n], "composetyped=", strlen("composetyped=")) == 0
+ || memcmp(items[n], "print=", strlen("print=")) == 0
+ || memcmp(items[n], "edit=", strlen("edit=")) == 0
+ || memcmp(items[n], "x11-bitmap=", strlen("x11-bitmap=")) == 0
+ || memcmp(items[n], "description=", strlen("description=")) == 0) {
+ free(items[n]);
+ continue;
+ }
+ else { /* command field */
+ m_mailcap[*mailcap_line].command = items[n];
+
+ if (find_format_str(m_mailcap[*mailcap_line].command, "%s") != NULL)
+ m_mailcap[*mailcap_line].format_string = "%s";
+ else if (find_format_str(m_mailcap[*mailcap_line].command, "%u") != NULL)
+ m_mailcap[*mailcap_line].format_string = "%u";
+ else
+ m_mailcap[*mailcap_line].format_string = "";
+ }
+ }
+ free(items);
+
+ (*mailcap_line)++;
+ }
+ free(linebuf);
+}
+
+/* parse mime or mailcap file, return true if successful. */
+static Boolean
+parse_mime_mailcap(const char *env_var,
+ const char *default_var_value,
+ int *lines,
+ void(*parse_func)(FILE *fp, const char *filename, int *mime_line))
+{
+ const char *path = NULL;
+ char **path_elems;
+ size_t elem_cnt, i;
+ FILE *fp;
+ Boolean success = False;
+
+ if ((path = getenv(env_var)) == NULL) {
+ path = default_var_value;
+ }
+
+ path_elems = split_line(path, ':', 0, strlen(path), &elem_cnt);
+ for (i = 0; i < elem_cnt; i++) {
+ char *newpath;
+ /* expand paths */
+ if ((newpath = maybe_expand_homedir(path_elems[i])) != NULL) {
+ free(path_elems[i]);
+ path_elems[i] = newpath;
+ }
+
+ if ((fp = XFOPEN(path_elems[i], FOPEN_R_MODE)) != NULL) {
+ parse_func(fp, path_elems[i], lines);
+ success = True;
+ }
+ free(path_elems[i]);
+ }
+ free(path_elems);
+ return success;
+}
+
+static void
+parsemimes(void)
+{
+ static Boolean already_called = False;
+
+ if (already_called)
+ return;
+ already_called = True;
+
+ m_mimemap_currlen = 0;
+
+ if (!parse_mime_mailcap("EXTENSIONMAPS", DEFAULT_EXTENSIONMAPS, &m_mimemap_currlen, read_mime_file)) {
+ m_mimemap_currlen = XtNumber(default_mimemap);
+ m_mimemap = default_mimemap;
+ }
+}
+
+
+/*
+ Partial parsing of mailcap file.
+
+ Currently not implemented:
+ - specifiers %t, %{xyz}, %n, %F
+ - realplayer's %u is treated as %s (couldn't find any documentation on %u)
+ */
+static void
+parsemailcap(void)
+{
+ static Boolean already_called = False;
+
+ if (already_called)
+ return;
+
+ already_called = True;
+
+ m_mailcap_currlen = 0;
+
+ if (!parse_mime_mailcap("MAILCAPS", DEFAULT_MAILCAPS, &m_mailcap_currlen, read_mailcap)) {
+ m_mailcap_currlen = XtNumber(default_mailcap);
+ m_mailcap = default_mailcap;
+ }
+}
+
+
+/*
+ Try to match test against a content type definition pattern.
+ The strings have one of the following formats (ignore spaces around `/'
+ - these are just to avoid breaking the C comment syntax):
+ * / *
+ text / *
+ * / plain
+ text / plain
+ where * matches everything.
+*/
+static Boolean
+match_content_type(const char *pattern, const char *test)
+{
+ /* chop both strings into parts at the '/' */
+ char *subtype_pattern, *subtype_test;
+ if ((subtype_pattern = strchr(pattern, '/')) == NULL) { /* malformed string? */
+ XDVI_WARNING((stderr, "Malformed content-type \"%s\" (should be \"type/subtype\")", pattern));
+ return False;
+ }
+ subtype_pattern++;
+ if ((subtype_test = strchr(test, '/')) == NULL) { /* malformed string? */
+ XDVI_WARNING((stderr, "Malformed content-type \"%s\" (should be \"type/subtype\")", test));
+ return False;
+ }
+ subtype_test++;
+ /* check whether it either matches the strings or a wildcard */
+ if ((*pattern == '*' && *subtype_pattern == '*') ||
+ (*pattern == '*' && strcmp(subtype_pattern, subtype_test) == 0) ||
+ (*subtype_pattern == '*' && memcmp(pattern, test, subtype_test - test) == 0) ||
+ (strcmp(subtype_pattern, subtype_test) == 0 && memcmp(pattern, test, subtype_test - test) == 0)) {
+ return True;
+ }
+ return False;
+}
+
+static Boolean
+run_test_command(const char *cmd, const char *arg)
+{
+ int retval;
+ const char *ptr;
+ size_t len;
+ char *syscmd = NULL;
+
+ UNUSED(arg); /* FIXME */
+ if (cmd == NULL)
+ return True;
+
+ syscmd = xmalloc(strlen(cmd) + strlen(arg) + 1);
+ if ((ptr = find_format_str(cmd, "%s")) != NULL) {
+ len = 2;
+ }
+ else if ((ptr = find_format_str(cmd, "%u")) != NULL) {
+ len = 2;
+ }
+ else {
+ len = 0;
+ ptr = strchr(cmd, '\0');
+ }
+ /* build system command */
+ memcpy(syscmd, cmd, ptr - cmd);
+ if (len > 0) { /* append argument */
+ strcpy(syscmd + (ptr - cmd), arg);
+ strcpy(syscmd + (ptr - cmd) + strlen(arg), ptr + len);
+ }
+ else {
+ syscmd[ptr - cmd] = '\0';
+ }
+
+ retval = system(syscmd);
+ TRACE_HTEX((stderr, "Execution of test command `%s' returned value %d", syscmd, retval));
+ free(syscmd);
+ return retval == 0;
+}
+
+char *
+figure_viewer(const char *content_type, const char **format_string, Boolean *needs_terminal, const char *arg)
+{
+ int i;
+
+ /* special case so that xdvizilla isn't used, which would be
+ too dangerous since xdvizilla tries to unlink the DVI file by default.
+ FIXME: A better way would be to always copy the original file, like
+ e.g. Acroread does it; see comment in launch_program(), hypertex.c.
+ */
+ if (strcmp(content_type, "application/x-dvi") == 0) {
+ *format_string = "%s";
+ *needs_terminal = False;
+ return xstrdup("xdvi %s");
+ }
+ /* try each command from our mailcap list */
+ for (i = 0; i < m_mailcap_currlen; i++) {
+ if (globals.debug & DBG_HTEX) {
+ fprintf(stderr, "type |%s| viewer |%s| needsterminal=%s testcmd |%s|\n",
+ m_mailcap[i].content_type, m_mailcap[i].command,
+ m_mailcap[i].needsterminal ? "yes" : "no",
+ m_mailcap[i].testcmd ? m_mailcap[i].testcmd : "None");
+ }
+ if (match_content_type(m_mailcap[i].content_type, content_type)
+ && run_test_command(m_mailcap[i].testcmd, arg)) {
+ *format_string = m_mailcap[i].format_string;
+ *needs_terminal = m_mailcap[i].needsterminal;
+ return xstrdup(m_mailcap[i].command);
+ }
+ }
+ /* failure */
+ return NULL;
+}
+
+
+/* return the mime type for filename, or default types
+ for non-recognized extensions/no extensions */
+char *
+figure_mime_type(const char *filename)
+{
+ int i;
+ char *extension, *cp;
+ char *content_type = NULL;
+
+ /* First check for the mailcap and mime files */
+ parsemimes();
+ parsemailcap();
+
+ if (globals.debug & DBG_HTEX)
+ fprintf(stderr, "figure_mime_type: Called to find type of %s\n",
+ filename);
+
+ /* See if this is a directory */
+ if (filename[strlen(filename) - 1] == '/') {
+ if (globals.debug & DBG_HTEX)
+ fprintf(stderr, "It's a directory, returning unknownExtensionMimeType: %s\n",
+ resource.unknown_mime_suffix);
+ return resource.unknown_mime_suffix;
+ }
+
+ /* See if filename extension is on the mime list: */
+ extension = strrchr(filename, '.');
+
+ if (extension == NULL) {
+ TRACE_HTEX((stderr,
+ "No extension, defaulting to noExtensionMimeType: %s\n",
+ resource.no_mime_suffix));
+ return resource.no_mime_suffix;
+ }
+ extension++;
+ /*
+ * corrupt URLs might have empty extensions; we need to catch this,
+ * since the while loop below would not terminate in that case:
+ */
+ if (strcmp(extension, "") == 0) {
+ XDVI_WARNING((stderr, "Empty extension for file name or URL `%s'\n", filename));
+ return resource.no_mime_suffix;
+ }
+
+ for (i = 0; i < m_mimemap_currlen; i++) {
+ /*
+ * find extension in m_mimemap[i].extensions, a space-separated list
+ * of extension strings.
+ */
+ cp = m_mimemap[i].extensions;
+ while ((cp = strstr(cp, extension)) != NULL) {
+ if ((cp - m_mimemap[i].extensions > 0) && (cp[-1] != ' ')) {
+ cp++;
+ continue;
+ }
+ cp += strlen(extension);
+ if ((*cp != ' ') && (*cp != '\0'))
+ continue;
+ content_type = m_mimemap[i].content_type;
+ break;
+ }
+ if (content_type != NULL)
+ break;
+ }
+
+ if (content_type == NULL) {
+ content_type = xstrdup(resource.unknown_mime_suffix);
+ TRACE_HTEX((stderr,
+ "Unknown extension, defaulting to unknownExtensionMimeType: %s",
+ content_type));
+ }
+ else {
+ TRACE_HTEX((stderr, "Found mime type: %s", content_type));
+ }
+
+ return content_type;
+}
+
diff --git a/Build/source/texk/xdvik/mime.h b/Build/source/texk/xdvik/mime.h
new file mode 100644
index 00000000000..a637e2bd87f
--- /dev/null
+++ b/Build/source/texk/xdvik/mime.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef MIME_H_
+#define MIME_H_
+
+extern char *figure_mime_type(const char *filename);
+extern char *figure_viewer(const char *mime_type, const char **format_string, Boolean *needs_terminal, const char *arg);
+
+#endif /* MIME_H_ */
diff --git a/Build/source/texk/xdvik/mksedscript b/Build/source/texk/xdvik/mksedscript
new file mode 100755
index 00000000000..706ba4467b5
--- /dev/null
+++ b/Build/source/texk/xdvik/mksedscript
@@ -0,0 +1,114 @@
+#! /bin/sh
+
+srcdir=$1
+
+# Values from c-auto.h
+
+mk_GREY=
+mk_PS_GS=
+mk_GS_PATH='gs'
+mk_PS_DPS=
+mk_PS_NEWS=
+mk_A4=
+mk_MOTIF=
+mk_COLOR=
+
+# T1 is always true
+mk_T1=1
+
+# Kpathsea defaults, they are #if'ed in the source but there is no
+# config option to disable them.
+mk_KPATHSEA=1
+
+# Optional values from CFLAGS
+
+mk_MFMODE='unspecified'
+mk_BDPI=600
+mk_DEFAULT_FONT_SIZES='m0:m0.5:m1:m2:m3:m4:m5'
+mk_SHRINK=8
+
+# Get arguments from CFLAGS
+
+for mk_arg
+do
+ case "$mk_arg" in
+ -D*=*)
+ eval "`echo \"$mk_arg\" | sed 's/^-D/mk_/'`"
+ ;;
+ -D*)
+ eval "`echo \"$mk_arg\" | sed 's/^-D/mk_/'`=1"
+ ;;
+ esac
+done
+
+# Get arguments from c-auto.h
+
+eval "`awk '/^#define/ { print "mk_"$2"="$3 }' c-auto.h`"
+
+# eval "`cat c-auto.h \
+# | grep '^[ ]*#[ ]*define[ ]' \
+# | sed 's/^[ ]*#[ ]*define[ ][ ]*/mk_/' \
+# | sed 's/[ ][ ]*/=/'`"
+
+# Process simple boolean arguments. Their values are empty or nonempty
+
+if test -z "$mk_COLOR"; then echo '/^#ifcolor/,/^#/d'; fi
+if test -z "$mk_GREY"; then echo '/^#ifgrey/,/^#/d'; fi
+if test -z "$mk_PS_DPS"; then echo '/^#ifdps/,/^#/d'; fi
+if test -z "$mk_PS_NEWS"; then echo '/^#ifnews/,/^#/d'; fi
+if test -z "$mk_T1"; then echo '/^#ift1/,/^#/d'; fi
+if test -z "$mk_MOTIF"; then echo '/^#ifmotif/,/^#/d';
+ else echo '/^#ifxaw/,/^#/d'; fi
+
+if test -z "$mk_KPATHSEA"; then echo '/^#ifkpathsea/,/^#/d';
+ else echo '/^#ifnokpathsea/,/^#/d'; fi
+
+# Process remaining PostScript emulation arguments
+
+if test -z "$mk_PS_GS"; then
+ echo '/^#ifghost/,/^#/d'
+else
+ echo "s^@GS_PATH@^$mk_GS_PATH^"
+fi
+
+if test -n "$mk_PS_GS" || test -n "$mk_PS_DPS" || test -n "$mk_PS_NEWS"; then
+ mk_PS=y
+ echo '/^#ifnops/,/^#/d'
+else
+ mk_PS=
+ echo '/^#ifps/,/^#/d'
+fi
+
+# get version info and release date from CHANGES file
+
+spacetab=' '
+XDVI_VERSION_INFO=`egrep "^[$spacetab]+\*" $srcdir/CHANGES | sed 1q | awk '{print $2 " " $3}'`
+XDVI_VERSION=`echo $XDVI_VERSION_INFO | awk '{print $1}'`
+XDVI_DATE=`echo $XDVI_VERSION_INFO | awk '{print $2}' | sed 's/[():]//g'`
+
+# Miscellaneous args
+
+if test -n "$mk_A4"; then
+ echo 's/@DEFAULT_PAGE_SIZE@/21 x 29.7 cm (A4 size)/'
+ echo 's/@DEFAULT_UNIT@/cm " (centimeters)"/'
+else
+ echo 's/@DEFAULT_PAGE_SIZE@/8.5 x 11 inches/'
+ echo 's/@DEFAULT_UNIT@/in " (inches)"/'
+fi
+
+echo "s^@MFMODE@^$mk_MFMODE^"
+echo "s/@BDPI@/$mk_BDPI/"
+echo "s/@SHRINK@/$mk_SHRINK/"
+echo "s/@XDVI_VERSION@/$XDVI_VERSION/"
+echo "s^@XDVI_DATE@^$XDVI_DATE^"
+
+echo "s/@DEFAULT_FONT_SIZES@/$mk_DEFAULT_FONT_SIZES/" | sed -e "s/:/ :\\\\\\
+/g"
+
+# Remove all remaining '#' lines
+
+echo '/^#/d'
+
+# Done
+
+exit 0
diff --git a/Build/source/texk/xdvik/my-snprintf.c b/Build/source/texk/xdvik/my-snprintf.c
new file mode 100644
index 00000000000..be70b4b8ef1
--- /dev/null
+++ b/Build/source/texk/xdvik/my-snprintf.c
@@ -0,0 +1,59 @@
+/*------------------------------------------------------------
+
+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.
+------------------------------------------------------------*/
+
+#include <string.h>
+#include <stdio.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "my-vsnprintf.h"
+#include "my-snprintf.h"
+
+#ifndef HAVE_SNPRINTF
+/*------------------------------------------------------------
+ * my_snprintf - emulation of glibc2.1 snprintf, use if
+ * snprintf is not available
+ *
+ * Arguments:
+ * char *str - buffer to print <format> string into
+ * int size - print only len characters of <format>
+ * char *format - variable format list
+ *
+ * Returns:
+ * int size - number of characters that would have been
+ * written if enough space had been available
+ *
+ * Purpose:
+ * Implementation of snprintf function, using my_vsnprintf
+ * (which see).
+ *------------------------------------------------------------*/
+int my_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list args;
+ int retVal;
+
+ va_start(args, format);
+ retVal = VSNPRINTF(str, size, format, args);
+ va_end(args);
+
+ return retVal;
+}
+#endif
diff --git a/Build/source/texk/xdvik/my-snprintf.h b/Build/source/texk/xdvik/my-snprintf.h
new file mode 100644
index 00000000000..5a5bbe6f275
--- /dev/null
+++ b/Build/source/texk/xdvik/my-snprintf.h
@@ -0,0 +1,36 @@
+/*------------------------------------------------------------
+
+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.
+------------------------------------------------------------*/
+
+#ifndef MY_SNPRINTF_H_
+#define MY_SNPRINTF_H_
+
+#ifdef HAVE_SNPRINTF
+
+#define SNPRINTF snprintf
+
+#else
+
+#define SNPRINTF my_snprintf
+int SNPRINTF(char *str, size_t size, const char *format, ...);
+
+#endif /* HAVE_SNPRINTF */
+#endif /* MY_VSNPRINTF_H_ */
+
diff --git a/Build/source/texk/xdvik/my-vsnprintf.c b/Build/source/texk/xdvik/my-vsnprintf.c
new file mode 100644
index 00000000000..dc2b9b7603c
--- /dev/null
+++ b/Build/source/texk/xdvik/my-vsnprintf.c
@@ -0,0 +1,92 @@
+/*------------------------------------------------------------
+
+written by Stefan Ulrich <stefanulrich@users.sourceforge.net> 2001/02/25
+
+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.
+------------------------------------------------------------*/
+
+#include <string.h>
+#include <stdio.h>
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "my-vsnprintf.h"
+
+#if !HAVE_VSNPRINTF || !HAVE_GOOD_VSNPRINTF
+/*------------------------------------------------------------
+ * my_vsnprintf - emulation of glibc2.1 vsnprintf, use if
+ * vsnprintf is not available
+ *
+ * Arguments:
+ * char *buf - buffer to print <format> string into
+ * int len - print only len characters of <format>
+ * char *format - format string
+ * va_list argp - variable argument list
+ *
+ * Returns:
+ * int size - number of characters that would have been
+ * written if enough space had been available
+ *
+ * Purpose:
+ * Implementation of GNU's vsnprintf using POSIX pipes (less
+ * portable and much slower than the original, but also much
+ * easier to implement ;-):
+ * Print the formatted string to a pipe and read back
+ * at most len-1 characters, appending a '\0' at the end.
+ *------------------------------------------------------------*/
+
+int
+my_vsnprintf(char *buf, int len, const char *format, va_list argp)
+{
+ int pipe_fd[2];
+ FILE *fd;
+ int size;
+#ifdef DEBUG
+ printf("=============my_vsnprintf called!\n");
+#endif
+ len--; /* for the trailing '\0' */
+
+ /* create a pipe for reading/writing */
+ if (xpipe(pipe_fd) == -1) {
+ perror("my_vsnprintf: pipe");
+ xdvi_exit(EXIT_FAILURE);
+ }
+ if ((fd = try_fdopen(pipe_fd[1], "w")) == NULL) {
+ perror("my_vsnprintf: fdopen");
+ xdvi_exit(EXIT_FAILURE);
+ }
+ /* instead of setting fd to non-buffering, flush it explicitly: */
+ /* setvbuf(fd, NULL, _IONBF, BUFSIZ); */
+ size = vfprintf(fd, format, argp);
+ fflush(fd);
+
+ /* wrote less characters than len -> adjust len for the subsequent read */
+ if (size < len) {
+ len = size;
+ }
+ read(pipe_fd[0], buf, len);
+ buf[len] = '\0'; /* always null-terminate */
+
+ fclose(fd);
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+
+ return size;
+}
+
+#endif /* !HAVE_VSNPRINTF || !HAVE_GOOD_VSNPRINTF */
diff --git a/Build/source/texk/xdvik/my-vsnprintf.h b/Build/source/texk/xdvik/my-vsnprintf.h
new file mode 100644
index 00000000000..a68ce8a9746
--- /dev/null
+++ b/Build/source/texk/xdvik/my-vsnprintf.h
@@ -0,0 +1,45 @@
+/*------------------------------------------------------------
+
+written by S. Ulrich (ulrich@cis.uni-muenchen.de) 2001/02/25
+
+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.
+------------------------------------------------------------*/
+
+#ifndef MY_VSNPRINTF_H__
+#define MY_VSNPRINTF_H__
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#if HAVE_VSNPRINTF && HAVE_GOOD_VSNPRINTF
+
+#include <stdio.h>
+#include <stdarg.h>
+#define VSNPRINTF(buf, len, format, args) vsnprintf(buf, len, format, args)
+
+#else /* HAVE_VSNPRINTF && HAVE_GOOD_VSNPRINTF */
+
+#include <unistd.h> /* for pipe() */
+#include "util.h" /* for xpipe() etc. */
+extern int my_vsnprintf(char *, int, const char *, va_list);
+#define VSNPRINTF(buf, len, format, args) my_vsnprintf(buf, len, format, args)
+
+#endif /* HAVE_VSNPRINTF && HAVE_GOOD_VSNPRINTF */
+
+#endif /* MY_VSNPRINTF_H__ */
diff --git a/Build/source/texk/xdvik/pagehist.c b/Build/source/texk/xdvik/pagehist.c
new file mode 100644
index 00000000000..e3ba0e7e0de
--- /dev/null
+++ b/Build/source/texk/xdvik/pagehist.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+*/
+
+/*
+ Very simple page history (i.e. stack of visited pages) for xdvik
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "util.h"
+#include "string-utils.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "message-window.h"
+#include "xm_toolbar.h"
+#include "pagehist.h"
+
+/****************************************************************************
+ *
+ * File-scope globals
+ *
+ ****************************************************************************/
+
+/* maximum number of items to print before truncating (10 left and right) */
+static const int HISTORY_MAX_CONTEXT = 21;
+
+/* list of pages in history */
+static struct dl_list *m_page_history = NULL;
+
+/* pointer to the head of the list, which only gets changed when
+ truncating the head (when list has reached its max size). */
+static struct dl_list *m_page_history_head = NULL;
+
+/* current size of the list */
+static int m_page_history_length = 0;
+
+/* current position in the list */
+static int m_page_history_currpos = 0;
+
+/* lookup table of filenames visited so far */
+static char **m_filename_list = NULL;
+static size_t m_filename_size = 0;
+
+/* item in above list */
+struct page_history {
+ int pageno;
+ int file_idx; /* index in file_list */
+};
+
+#define DEBUG 0
+
+/****************************************************************************
+ *
+ * Private functions
+ *
+ ****************************************************************************/
+
+static void
+page_history_show(struct dl_list *head, const struct dl_list *curr)
+{
+#if DEBUG
+ int n;
+ for (n = 0; head != NULL; head = head->next, n++) {
+ struct page_history *item = (struct page_history *)(head->item);
+ if (head == curr) {
+ fprintf(stderr, "item %d: <%d>\n", n, item->pageno);
+ }
+ else {
+ fprintf(stderr, "item %d: %d\n", n, item->pageno);
+ }
+ }
+#else
+ UNUSED(head);
+ UNUSED(curr);
+#endif /* DEBUG */
+}
+
+/* like above, but output goes to the statusline, and it prints only up to HISTORY_MAX_CONTEXT
+ items around the current one.
+*/
+static void
+page_history_show_statusline(struct dl_list *head,
+ const struct dl_list *curr,
+ const char *msg)
+{
+#define HIST_LEN 1024 /* should be ample since statusline is limited to 512 MAX_LEN */
+
+ int file_idx = 0;
+
+ int n;
+ char history[HIST_LEN];
+ char *ptr = history;
+ int tot_len = m_page_history_length;
+ int curr_pos = m_page_history_currpos;
+ int initial_offset = 0;
+ int printed_len = 0;
+
+#if DEBUG
+ fprintf(stderr, "tot_len: %d, curr_pos: %d\n", tot_len, curr_pos);
+#endif
+
+ if (head == NULL){
+ strcpy(ptr, "Page history empty.");
+ ptr += strlen("Page history empty.");
+ }
+ else {
+ strcpy(ptr, "Page history:");
+ ptr += strlen("Page history:");
+ }
+
+ /* check if we need to truncate at the beginning or end */
+ if (tot_len > HISTORY_MAX_CONTEXT) {
+ /* need to truncate, try to make first and second chunk around current position of same length */
+ int good_pos = HISTORY_MAX_CONTEXT / 2.0 + 0.5;
+ while (curr_pos > good_pos /* && */
+/* m_page_history_length - m_page_history_currpos > good_pos */) {
+#if DEBUG
+ fprintf(stderr, "%d > %d; %d > %d\n", curr_pos, good_pos,
+ m_page_history_length - m_page_history_currpos, good_pos);
+#endif
+ curr_pos--;
+ initial_offset++;
+ }
+#if DEBUG
+ fprintf(stderr, "initial offset: %d\n", initial_offset);
+#endif
+ /* if we're more to the end, adjust good_pos and initial_offset */
+ while (good_pos - 1 > m_page_history_length - m_page_history_currpos) {
+#if DEBUG
+ fprintf(stderr, "%d > %d\n", m_page_history_length - m_page_history_currpos, good_pos);
+#endif
+ initial_offset--;
+ good_pos--;
+ }
+#if DEBUG
+ fprintf(stderr, "initial offset adjusted: %d\n", initial_offset);
+#endif
+ }
+
+ for (n = 0; head != NULL; head = head->next, n++) {
+ struct page_history *item;
+ /* skip initial offset, and insert truncation marker at beginning/end */
+ if (initial_offset == 1 || printed_len >= HISTORY_MAX_CONTEXT) {
+ strcpy(ptr, " ...");
+ ptr += strlen(" ...");
+ if (printed_len >= HISTORY_MAX_CONTEXT)
+ break;
+ }
+ if (initial_offset > 0) {
+ initial_offset--;
+ continue;
+ }
+
+ printed_len++;
+
+ item = (struct page_history *)(head->item);
+
+ /* insert a marker if item is in different file ... */
+ if (item->file_idx != file_idx) {
+ if (n > 0) { /* ... but only if we're not at the beginning of the list */
+#if 1
+ strcpy(ptr, " -");
+ ptr += 2;
+#else
+ char *fname = m_filename_list[item->file_idx];
+ char *tmp;
+ if ((tmp = strrchr(m_filename_list[item->file_idx], '/')) != NULL)
+ fname = tmp + 1;
+ strcpy(ptr, " [");
+ ptr += 2;
+ strcpy(ptr, fname);
+ ptr += strlen(fname);
+ strcpy(ptr, "]");
+ ptr++;
+#endif
+ }
+ file_idx = item->file_idx;
+ }
+
+ if (head == curr) {
+ ASSERT(m_page_history_currpos == n + 1, "Consistency check for pagelist position failed!");
+ sprintf(ptr, " [%d]", item->pageno + 1);
+ ptr += 3 + length_of_int(item->pageno + 1);
+ }
+ else {
+ sprintf(ptr, " %d", item->pageno + 1);
+ ptr += 1 + length_of_int(item->pageno + 1);
+ }
+ }
+#if DEBUG
+ fprintf(stderr, "Statusline string: |%s|; printed len: %d\n", history, printed_len);
+#endif
+ statusline_print(STATUS_LONG, "%s %s", history, msg ? msg : "");
+#undef HIST_LEN
+}
+
+static void
+goto_location(const char *filename, int pageno)
+{
+#if DEBUG
+ fprintf(stderr, "going to page %d of file %s\n", pageno, filename);
+#endif
+ if (strcmp(globals.dvi_name, filename) != 0) { /* it's a different file */
+ Boolean tried_dvi_ext = True;
+ char *new_dvi_name;
+#if DEBUG
+ fprintf(stderr, "different file: |%s|\n", filename);
+#endif
+ if ((new_dvi_name = open_dvi_file_wrapper(filename, True, False,
+ &tried_dvi_ext, True)) == NULL) {
+ statusline_append(STATUS_MEDIUM,
+ "Re-opening file",
+ "Re-opening file \"%s\" failed!", filename);
+#if DEBUG
+ fprintf(stderr, "Re-opening file \"%s\" failed!\n", filename);
+#endif
+ page_history_delete(1);
+ return;
+ }
+ else {
+ dviErrFlagT errflag;
+ if (load_dvi_file(True, &errflag)) {
+ set_dvi_name(new_dvi_name);
+
+ globals.ev.flags |= EV_NEWDOC;
+#if DEBUG
+ fprintf(stderr, "Back to file: \"%s\"\n", globals.dvi_name);
+#endif
+ }
+ else { /* re-open old file */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Could not open `%s': %s.\n"
+ /* "Removing this file from the history." */,
+ globals.dvi_name, get_dvi_error(errflag));
+
+ if (!internal_open_dvi(globals.dvi_name, &errflag, True)) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Couldn't reopen `%s': %s.\n"
+ /* "Removing this file from the history." */,
+ globals.dvi_name, get_dvi_error(errflag));
+ }
+ else {
+ globals.ev.flags |= EV_NEWPAGE;
+ }
+ page_history_delete(1);
+ }
+ }
+ }
+ if (pageno != current_page) {
+ if (pageno < total_pages) {
+ goto_page(pageno, resource.keep_flag ? NULL : home, False);
+ }
+ else {
+ XDVI_WARNING((stderr, "Could not go to page %d (file has shrunken)", pageno));
+ statusline_print(STATUS_MEDIUM,
+ "Could not go to page %d (file has shrunken)", pageno);
+ }
+ }
+}
+
+/****************************************************************************
+ *
+ * Exported functions
+ *
+ ****************************************************************************/
+
+/*
+ Move n elements in page history; n == 0 doesn't move,
+ n < 0 moves n items back, n > 0 moves n items forward.
+*/
+void page_history_move(int n)
+{
+ struct dl_list *pos;
+ struct page_history *item;
+ const char *msg = NULL;
+
+ page_history_show(m_page_history_head, m_page_history);
+
+ if (resource.page_history_size == 0)
+ return;
+
+ if (m_page_history_head == NULL)
+ m_page_history_head = m_page_history;
+
+ if (n < 0) { /* move backwards */
+ for (pos = NULL; n < 0; n++) {
+ if (m_page_history != NULL)
+ pos = m_page_history->prev;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at begin of page history.";
+ break;
+ }
+ else {
+ m_page_history = pos;
+ m_page_history_currpos--;
+ }
+ }
+ }
+ else { /* move forward */
+ for (pos = NULL; n > 0; n--) {
+ if (m_page_history != NULL)
+ pos = m_page_history->next;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at end of page history.";
+ break;
+ }
+ else {
+ m_page_history = pos;
+ m_page_history_currpos++;
+ }
+ }
+ }
+ item = (struct page_history *)m_page_history->item;
+#if DEBUG
+ fprintf(stderr, "going to page %d\n", item->pageno);
+#endif
+ goto_location(m_filename_list[item->file_idx], item->pageno);
+
+#if defined(MOTIF) && HAVE_XPM
+ tb_set_pagehist_back_sensitivity(m_page_history->prev != NULL);
+ tb_set_pagehist_forward_sensitivity(m_page_history->next != NULL);
+#endif
+
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_show_statusline(m_page_history_head, m_page_history, msg);
+ page_history_update_toolbar_navigation();
+}
+
+/* add page n to the page history */
+void page_history_insert(int n)
+{
+ struct page_history *item = NULL;
+ static char *current_filename = NULL;
+ static size_t filename_idx = 0; /* index of current filename */
+
+#if DEBUG
+ fprintf(stderr, "inserting into history: %d\n", n);
+#endif
+ page_history_show(m_page_history_head, m_page_history);
+ /* do nothing if no history is used */
+ if (resource.page_history_size == 0)
+ return;
+
+ if (m_page_history_head == NULL)
+ m_page_history_head = m_page_history;
+
+ item = xmalloc(sizeof *item);
+ /* first call, or filename changed -> update file_list */
+ if (current_filename == NULL || strcmp(current_filename, globals.dvi_name) != 0) {
+ size_t i;
+ current_filename = xstrdup(globals.dvi_name);
+
+ for (i = 0; i < m_filename_size; i++) {
+#if DEBUG
+ fprintf(stderr, "comparing %d: |%s|%s|\n", i, current_filename, m_filename_list[i]);
+#endif
+ if (strcmp(current_filename, m_filename_list[i]) == 0) { /* found */
+ filename_idx = i;
+ break;
+ }
+ }
+
+ if (i >= m_filename_size) { /* not found, insert into file list */
+ m_filename_list = xrealloc(m_filename_list, (m_filename_size + 1) * sizeof *m_filename_list);
+ m_filename_list[m_filename_size] = filename_append_dvi(current_filename);
+ filename_idx = m_filename_size++;
+#if DEBUG
+ fprintf(stderr, "NEW file %d: %s\n", filename_idx, current_filename);
+#endif
+ }
+ }
+
+#if DEBUG
+ fprintf(stderr, "-------- %d >= %d?\n", m_page_history_length, resource.page_history_size - 1);
+#endif
+ if (m_page_history_length >= resource.page_history_size - 1) { /* truncate history */
+ free(m_page_history_head->item);
+ m_page_history_head = dl_list_truncate_head(m_page_history_head);
+ }
+ else {
+ m_page_history_length++;
+ }
+
+ item->pageno = n;
+ item->file_idx = filename_idx;
+
+#if DEBUG
+ fprintf(stderr, "inserting %d\n", item->pageno);
+#endif
+ m_page_history = dl_list_insert(m_page_history, item);
+ m_page_history_currpos++;
+
+#if DEBUG
+ fprintf(stderr, "head: %p, curr: %p\n", (void *)m_page_history_head, (void *)m_page_history);
+#endif
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_update_toolbar_navigation();
+}
+
+void
+page_history_update_toolbar_navigation(void)
+{
+#if defined(MOTIF) && HAVE_XPM
+ tb_set_htex_back_sensitivity(m_page_history->prev != NULL);
+ tb_set_htex_forward_sensitivity(m_page_history->next != NULL);
+#endif
+}
+
+void
+page_history_clear()
+{
+ struct dl_list *pos, *curr;
+
+ if (resource.page_history_size == 0)
+ return;
+
+ m_page_history_head = m_page_history;
+
+ for (curr = m_page_history; curr != NULL && curr->prev != NULL; curr = pos) {
+ pos = curr->prev;
+ free(curr->item);
+ (void)dl_list_remove_item(&curr);
+ m_page_history_length--;
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_show_statusline(m_page_history_head, m_page_history, NULL);
+ }
+
+/* for (curr = m_page_history; curr != NULL && curr->next != NULL; curr = pos) { */
+/* pos = curr->next; */
+/* free(curr->item); */
+/* (void)dl_list_remove_item(&curr); */
+/* m_page_history_length--; */
+/* page_history_show(m_page_history_head, m_page_history); */
+/* } */
+
+
+}
+
+/*
+ Delete n elements from the page history.
+ If n < 0, delete current and n-1 previous items and move to the item before them.
+ If n > 0, delete current and n-1 next items and move to the item after them.
+ E.g. (with current position marked by `<>'):
+
+ a b <c> d e
+ -> page_history_delete(-2)
+ -> <a> d e
+
+ a b <c> d e
+ -> page_history_delete(2)
+ -> a b <e>
+
+ Prints an error to the statusline if number of deletions exceeds the limits
+ of the list.
+*/
+void page_history_delete(int n)
+{
+ struct dl_list *pos;
+ struct page_history *item;
+ const char *msg = NULL;
+
+ if (resource.page_history_size == 0)
+ return;
+
+ if (m_page_history_head == NULL)
+ m_page_history_head = m_page_history;
+
+ /* fprintf(stderr, "deleting items: |%d|\n", n); */
+
+ if (n < 0) { /* delete backwards */
+ for (pos = NULL; n < 0; n++) {
+ if (m_page_history != NULL)
+ pos = m_page_history->prev;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at begin of page history.";
+ break;
+ }
+ else {
+ /* remove item */
+ free(m_page_history->item);
+ (void)dl_list_remove_item(&m_page_history);
+ m_page_history = pos;
+ m_page_history_currpos--;
+ m_page_history_length--;
+ }
+ }
+ }
+ else { /* delete forward */
+ for (pos = NULL; n > 0; n--) {
+ if (m_page_history != NULL)
+ pos = m_page_history->next;
+ if (pos == NULL) {
+ XBell(DISP, 0);
+ msg = " - at end of page history.";
+ break;
+ }
+ else {
+ /* remove item */
+ free(m_page_history->item);
+ if (m_page_history->prev == NULL) { /* at head */
+ m_page_history_head = m_page_history = dl_list_truncate_head(m_page_history);
+ }
+ else {
+ (void)dl_list_remove_item(&m_page_history);
+ m_page_history = pos;
+ }
+ /* Note: m_page_history_currpos remains unchanged here */
+ m_page_history_length--;
+ }
+ }
+ }
+ item = (struct page_history *)m_page_history->item;
+#if DEBUG
+ fprintf(stderr, "going to page %d\n", item->pageno);
+#endif
+ goto_location(m_filename_list[item->file_idx], item->pageno);
+ page_history_show(m_page_history_head, m_page_history);
+ page_history_show_statusline(m_page_history_head, m_page_history, msg);
+}
+
diff --git a/Build/source/texk/xdvik/pagehist.h b/Build/source/texk/xdvik/pagehist.h
new file mode 100644
index 00000000000..2b23b1a4261
--- /dev/null
+++ b/Build/source/texk/xdvik/pagehist.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * 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.
+ */
+
+#ifndef PAGEHIST_H_
+#define PAGEHIST_H_
+
+extern void page_history_move(int n);
+extern void page_history_insert(int n);
+extern void page_history_delete(int n);
+extern void page_history_update_toolbar_navigation(void);
+extern void page_history_clear(void);
+
+#endif /* PAGEHIST_H_ */
+
diff --git a/Build/source/texk/xdvik/pixmaps/drag_horiz.xbm b/Build/source/texk/xdvik/pixmaps/drag_horiz.xbm
new file mode 100644
index 00000000000..39cd20118fd
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/drag_horiz.xbm
@@ -0,0 +1,8 @@
+#define drag_horiz_width 17
+#define drag_horiz_height 7
+#define drag_horiz_x_hot 8
+#define drag_horiz_y_hot 3
+static unsigned char drag_horiz_bits[] = {
+ 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x04, 0x40, 0x00, 0xfe, 0xff, 0x00,
+ 0x04, 0x40, 0x00, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
+
diff --git a/Build/source/texk/xdvik/pixmaps/drag_horiz_mask.xbm b/Build/source/texk/xdvik/pixmaps/drag_horiz_mask.xbm
new file mode 100644
index 00000000000..cd81e08115c
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/drag_horiz_mask.xbm
@@ -0,0 +1,8 @@
+#define drag_horiz_mask_width 17
+#define drag_horiz_mask_height 7
+#define drag_horiz_mask_x_hot 8
+#define drag_horiz_mask_y_hot 3
+static unsigned char drag_horiz_mask_bits[] = {
+ 0x08, 0x20, 0x00, 0x0c, 0x60, 0x00, 0xfe, 0xff, 0x00, 0xff, 0xff, 0x01,
+ 0xfe, 0xff, 0x00, 0x0c, 0x60, 0x00, 0x08, 0x20, 0x00};
+
diff --git a/Build/source/texk/xdvik/pixmaps/drag_omni.xbm b/Build/source/texk/xdvik/pixmaps/drag_omni.xbm
new file mode 100644
index 00000000000..8b81c97e5da
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/drag_omni.xbm
@@ -0,0 +1,10 @@
+#define drag_omni_width 17
+#define drag_omni_height 17
+#define drag_omni_x_hot 8
+#define drag_omni_y_hot 8
+static unsigned char drag_omni_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x05, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x08, 0x21, 0x00, 0x04, 0x41, 0x00,
+ 0xfe, 0xff, 0x00, 0x04, 0x41, 0x00, 0x08, 0x21, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x01, 0x00, 0x40, 0x05, 0x00, 0x80, 0x03, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00};
diff --git a/Build/source/texk/xdvik/pixmaps/drag_omni_mask.xbm b/Build/source/texk/xdvik/pixmaps/drag_omni_mask.xbm
new file mode 100644
index 00000000000..60feeb54c79
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/drag_omni_mask.xbm
@@ -0,0 +1,10 @@
+#define drag_omni_mask_width 17
+#define drag_omni_mask_height 17
+#define drag_omni_mask_x_hot 8
+#define drag_omni_mask_y_hot 8
+static unsigned char drag_omni_mask_bits[] = {
+ 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x07, 0x00, 0xe0, 0x0f, 0x00,
+ 0x80, 0x03, 0x00, 0x88, 0x23, 0x00, 0x8c, 0x63, 0x00, 0xfe, 0xff, 0x00,
+ 0xff, 0xff, 0x01, 0xfe, 0xff, 0x00, 0x8c, 0x63, 0x00, 0x88, 0x23, 0x00,
+ 0x80, 0x03, 0x00, 0xe0, 0x0f, 0x00, 0xc0, 0x07, 0x00, 0x80, 0x03, 0x00,
+ 0x00, 0x01, 0x00};
diff --git a/Build/source/texk/xdvik/pixmaps/drag_vert.xbm b/Build/source/texk/xdvik/pixmaps/drag_vert.xbm
new file mode 100644
index 00000000000..65e0eddc302
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/drag_vert.xbm
@@ -0,0 +1,7 @@
+#define drag_vert_width 7
+#define drag_vert_height 17
+#define drag_vert_x_hot 3
+#define drag_vert_y_hot 8
+static unsigned char drag_vert_bits[] = {
+ 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x2a, 0x1c, 0x08, 0x00};
diff --git a/Build/source/texk/xdvik/pixmaps/drag_vert_mask.xbm b/Build/source/texk/xdvik/pixmaps/drag_vert_mask.xbm
new file mode 100644
index 00000000000..d7a461a7743
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/drag_vert_mask.xbm
@@ -0,0 +1,7 @@
+#define drag_vert_mask_width 7
+#define drag_vert_mask_height 17
+#define drag_vert_mask_x_hot 3
+#define drag_vert_mask_y_hot 8
+static unsigned char drag_vert_mask_bits[] = {
+ 0x08, 0x1c, 0x3e, 0x7f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
+ 0x1c, 0x7f, 0x3e, 0x1c, 0x08};
diff --git a/Build/source/texk/xdvik/pixmaps/fist.xbm b/Build/source/texk/xdvik/pixmaps/fist.xbm
new file mode 100644
index 00000000000..260b8917264
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/fist.xbm
@@ -0,0 +1,6 @@
+#define fist_width 16
+#define fist_height 16
+static unsigned char fist_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4f, 0xf2,
+ 0x0f, 0xd0, 0x0f, 0xc0, 0x0b, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xe0,
+ 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf0, 0x1f, 0xf0};
diff --git a/Build/source/texk/xdvik/pixmaps/fist_mask.xbm b/Build/source/texk/xdvik/pixmaps/fist_mask.xbm
new file mode 100644
index 00000000000..64ae49821ff
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/fist_mask.xbm
@@ -0,0 +1,6 @@
+#define fist_mask_width 16
+#define fist_mask_height 16
+static unsigned char fist_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x0d, 0xf8, 0x3f,
+ 0xf8, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f,
+ 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x1f};
diff --git a/Build/source/texk/xdvik/pixmaps/hand.xbm b/Build/source/texk/xdvik/pixmaps/hand.xbm
new file mode 100644
index 00000000000..3fb8dbcb9aa
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/hand.xbm
@@ -0,0 +1,6 @@
+#define hand_width 16
+#define hand_height 16
+static unsigned char hand_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x67, 0xf2, 0x67, 0xf2, 0x4f, 0xb2,
+ 0x4f, 0x92, 0x1f, 0x90, 0x19, 0x80, 0x11, 0xc0, 0x03, 0xc0, 0x07, 0xc0,
+ 0x07, 0xe0, 0x0f, 0xe0, 0x1f, 0xf0, 0x3f, 0xf0};
diff --git a/Build/source/texk/xdvik/pixmaps/hand_mask.xbm b/Build/source/texk/xdvik/pixmaps/hand_mask.xbm
new file mode 100644
index 00000000000..37fa6ef6d2b
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/hand_mask.xbm
@@ -0,0 +1,6 @@
+#define hand_mask_width 16
+#define hand_mask_height 16
+static unsigned char hand_mask_bits[] = {
+ 0x00, 0x00, 0x80, 0x01, 0xd8, 0x0f, 0xfc, 0x1f, 0xfc, 0x5f, 0xf8, 0xff,
+ 0xf8, 0xff, 0xf6, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f,
+ 0xfc, 0x3f, 0xf8, 0x3f, 0xf0, 0x1f, 0xe0, 0x1f};
diff --git a/Build/source/texk/xdvik/pixmaps/magglass.xbm b/Build/source/texk/xdvik/pixmaps/magglass.xbm
new file mode 100644
index 00000000000..fca92ba1a46
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/magglass.xbm
@@ -0,0 +1,10 @@
+#define magglass_width 20
+#define magglass_height 20
+#define magglass_x_hot 7
+#define magglass_y_hot 7
+static unsigned char magglass_bits[] = {
+ 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x18, 0x0c, 0x00, 0x04, 0x13, 0x00,
+ 0x04, 0x14, 0x00, 0x02, 0x28, 0x00, 0x02, 0x28, 0x00, 0x02, 0x20, 0x00,
+ 0x02, 0x20, 0x00, 0x02, 0x20, 0x00, 0x04, 0x10, 0x00, 0x04, 0x38, 0x00,
+ 0x18, 0x6c, 0x00, 0xe0, 0xdb, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x60, 0x03,
+ 0x00, 0xc0, 0x06, 0x00, 0x80, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
diff --git a/Build/source/texk/xdvik/pixmaps/magglass_mask.xbm b/Build/source/texk/xdvik/pixmaps/magglass_mask.xbm
new file mode 100644
index 00000000000..1c26d193421
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/magglass_mask.xbm
@@ -0,0 +1,10 @@
+#define magglass_mask_width 20
+#define magglass_mask_height 20
+#define magglass_mask_x_hot 7
+#define magglass_mask_y_hot 7
+static unsigned char magglass_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0xf8, 0x0f, 0x00, 0x1c, 0x1f, 0x00,
+ 0x0c, 0x1c, 0x00, 0x06, 0x38, 0x00, 0x06, 0x38, 0x00, 0x06, 0x30, 0x00,
+ 0x06, 0x30, 0x00, 0x06, 0x30, 0x00, 0x0c, 0x18, 0x00, 0x1c, 0x3c, 0x00,
+ 0xf8, 0x7f, 0x00, 0xe0, 0xfb, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xe0, 0x03,
+ 0x00, 0xc0, 0x07, 0x00, 0x80, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 };
diff --git a/Build/source/texk/xdvik/pixmaps/time16.xbm b/Build/source/texk/xdvik/pixmaps/time16.xbm
new file mode 100644
index 00000000000..d7f13f29244
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/time16.xbm
@@ -0,0 +1,8 @@
+#define time16_width 16
+#define time16_height 16
+#define time16_x_hot 7
+#define time16_y_hot 7
+static unsigned char time16_bits[] = {
+ 0x00, 0x00, 0xfe, 0x7f, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0xe4, 0x27,
+ 0xc4, 0x23, 0x84, 0x21, 0x84, 0x21, 0x44, 0x22, 0x24, 0x24, 0x94, 0x29,
+ 0xd4, 0x2b, 0xf4, 0x2f, 0xfe, 0x7f, 0x00, 0x00};
diff --git a/Build/source/texk/xdvik/pixmaps/time16_mask.xbm b/Build/source/texk/xdvik/pixmaps/time16_mask.xbm
new file mode 100644
index 00000000000..d550e73dac2
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/time16_mask.xbm
@@ -0,0 +1,6 @@
+#define time16_mask_width 16
+#define time16_mask_height 16
+static unsigned char time16_mask_bits[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xf6, 0x6f,
+ 0xe6, 0x67, 0xc6, 0x63, 0xc6, 0x63, 0xe6, 0x67, 0xf6, 0x6f, 0xfe, 0x7f,
+ 0xfe, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff};
diff --git a/Build/source/texk/xdvik/pixmaps/toolbar.xpm b/Build/source/texk/xdvik/pixmaps/toolbar.xpm
new file mode 100644
index 00000000000..e752fef011e
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/toolbar.xpm
@@ -0,0 +1,41 @@
+/* XPM */
+static char * toolbar_xpm[] = {
+/* width height colors colordepth */
+" 378 18 16 1 0 0",
+" s none c None",
+". m white c red",
+"+ m black c #000000",
+"$ m none c #ADADAD",
+"% m black c #232323",
+"& m none c #FFFFFF",
+": m black c #FFFFFF",
+", m none c #DEDEDE",
+"y m black c #DEDEDE",
+"' m black c #13A706",
+"t s bottomShadowColor c #636363",
+"w m black c #125006",
+"N m none c #C9C9C9",
+"O m none c #949494",
+"` m none c #404040",
+"Y m none c #303030",
+/* pixels */ /*
+ ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** */
+" ",
+" ++++++++ YY YY ++++++++ ",
+" +++++++++ t+++t ++++ ++++ .... +&&&&&+&+ ttt &$Y &$Y $%%%%$ +&&&&&&+ ttttt ",
+" +&&&&&&+&+ t++++++ %% % % % % %% +,,,,+ +,,,,+ + + ........ +&&&&&+&&+ t , `YY `YY $%%%%%%$ +&&&&&&+ +++++ t+++t ",
+" +&&&&&&+&&+ +++t t+ %% %% %% %% %% %% +,,&,,,+ +,,&,,,+ ++ ++ .......... +&&&&&++++ ,,, ......... %%%%%%%%% %%%%%%%%% %%%%%%%%% ttt Y$ttt %%$ $%% ' +&&&&&&+ t++t ++ ",
+" +&&&&&&++++ t++t +t %% %%% %%% %%% %%% %% +,,&&,,+ +,,&&,,+ +:+ +:+ ...&....&... +&&&&&&&&+ ttt tYYYYtYtYYYY` %% %% ''+&&&&&&+ ++++ t++t ",
+" +++&&&&&&&&&+++ +++ %% %%%% %%%% %%%% %%%% %% +,,,,,,+ +,,,,,,+ +++ +::++++++++++++++:y+ +++ ..&&&..&&&.. ++&&&&&&&&++ t , t$&&$t$t`t&&$t` %% $%% '''&&&++&+ t+tt+t + + ",
+" +,+&&&&&&&&&+t+ +++++++ + %% %%%%% %%%%% %%%%% %%%%% %% +,,,,,,+ +,,,,,,+ +$&$+ +:yy::::::++:::::::yy+ +$&$+ ....&&&&&&.... +$+&&&&&&&&+t+t %%%%%%%%% ,,, ......... %%%%%%%%% %%%%%%%%% `&&&$t&$`&&&$tY $%%$ ''''''''''&&++&+ ++ ++ t+ +t ",
+"+++++++++++++,+t+ +++++ +++ %% %%%%%% %%%%%% %%%%%% %%%%%% %% +,,,,+t +,,,,+t +&&$+ +:yyyyyyyyy++:yyyyyyyyy+ +&&$+ .....&&&&..... ++++++++++++$t+t ttt ttt `&$$tt```t&&$tY $%%$ '''''''''''&&&&+ t+t t+t +t t+ ",
+"+$&&&&&&&&&&&++t+ +++ +++++ %% %%%%% %%%%% %%%%% %%%%% %% ++++t++ ++++t++ +$$$+ +yyyyyyyyy++:yyyyyyyy+ +$$$+ .....&&&&..... +&&&&&&&&&&&&&,t+ t , t , `&``YY&$t```ttY %%$ ''''''''''w&&&&+ ++++++++ t+++++++ ",
+" +,$$$$$$$$$$t+t+ + +++++++ %% %%%% %%%% %%%% %%%% %% %% +++ +++ +++ +yy++++++++++++++yy+ +++ ....&&&&&&.... +&$$$$$$$$$$$$$t+ ,,, ......... %%%%%%%%% ,,, ......... %%%%%%%%% `&$tY ``$`&$tY %% wwwwww'''w&&&&&+ t+tttttt+t +t t+ ",
+" +$,$$$$$$$$$$+t+ +++ %% %%% %%% %%% %%% %% %% ++% ++% +y+ +y+ ..&&&..&&&.. +&tttttttttttt$t+ ttt `&$tY `&$tY %% ''w&&&&&&+ +t t+ t+ +t ",
+" +,$$$$$$$$$$t++ t+ t++t %% %% %% %% %% %% %%%%%% %% %%%%%% %% ++ ++ ...&....&... +&t++++++++++&$t+ t , `&$tY `&$tY 'w+&&&&&&+ ++t t++t +t t+ ",
+" +$,$$$$$$$$$$++ +t t+++ %% % % % % %% %%%%%% %%%%%% + + .......... +&&&&&&&&&&&&&$t+ %%%%%%%%% ,,, ......... %%%%%%%%% %%%%%%%%% `tt`Y `tt`Y w +&&&&&$+ t++++ t++++ t++++ t++++ ",
+" +$ttttttttttt+ ++++++t %% ........ +Ottttttttttttt++ `&$tY `&$tY %% +&&&N$O+ ",
+" ++++++++++++++ t+++t %% .... +++++++++++++++ ````` ````` %% +&N$Ott+ ",
+" ++++++++ ",
+" "}; /*
+ ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** */
diff --git a/Build/source/texk/xdvik/pixmaps/toolbar2.xpm b/Build/source/texk/xdvik/pixmaps/toolbar2.xpm
new file mode 100644
index 00000000000..edacd450833
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/toolbar2.xpm
@@ -0,0 +1,40 @@
+/* XPM */
+static char * tools2_xpm[] = {
+/* width height colors colordepth */
+" 378 18 15 1 0 0",
+" m none c None",
+". m white c red",
+"+ m black c #000000",
+"$ m none c #ADADAD",
+"% m black c #232323",
+"& m none c #FFFFFF",
+", m none c #DEDEDE",
+"' m black c #13A706",
+"k m black c #737373",
+"t m none c #636363",
+"w m black c #125006",
+"N m none c #C9C9C9",
+"O m none c #949494",
+"` m none c #404040",
+"Y m none c #303030",
+/* pixels */ /*
+ ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** */
+" ",
+" ++++++++ YY YY ++++++++ ",
+" +++++++++ t+++t $++++$ $++++$ .... +&&&&&+&+ kkk &$Y &$Y $%%%%$ +&&&&&&+ ttttt ",
+" +&&&&&&+&+ t++++++ $+,,,,+$ $+,,,,+$ '' '' ........ +&&&&&+&&+ k , `YY `YY $%%%%%%$ +&&&&&&+ +++++ t+++t ",
+" +&&&&&&+&&+ +++t t+ %% $% $% %$ %$ %% +,,& ,,+ +,,& ,,+ ''' ''' .......... +&&&&&++++ ,,, ......... %%%%%%%%% %%%%%%%%% %%%%%%%%% kkk Y$kkk %%$ $%% ' +&&&&&&+ t++t ++ ",
+" +&&&&&&++++ t++t +t %% $%% $%% %%$ %%$ %% +,,&&,,+ +,,&&,,+ '''' '''' ...&....&... +&&&&&&&&+ kkk kYYYYkYkYYYY` %% %% ''+&&&&&&+ ++++ t++t ",
+" +++&&&&&&&&&+++ +++ %% $%%% $%%% %%%$ %%%$ %% +,,,,,,+ +,,,,,,+ '''''''' ''''''''' ..&&&..&&&.. ++&&&&&&&&++ k , k$&&$k$k`k&&$k` %% $%% '''&&&++&+ t+tt+t + + ",
+" +,+&&&&&&&&&+k+ +++++++ + %% $%%%% $%%%% %%%%$ %%%%$ %% +,,,,,,+ +,,,,,,+ '''''''''w '''''''''' ....&&&&&&.... +$+&&&&&&&&+k+t %%%%%%%%% ,,, ......... %%%%%%%%% %%%%%%%%% `&&&$k&$`&&&$kY $%%$ ''''''''''&&++&+ ++ ++ t+ +t ",
+"+++++++++++++,+k+ +++++ +++ %% $%%%%% $%%%%% %%%%%$ %%%%%$ %% $+,,,,+k $+,,,,+k ''''''''''w ''''''''''' .....&&&&..... ++++++++++++$k+t kkk kkk `&$$kk```k&&$kY $%%$ '''''''''''&&&&+ t+t t+t +t t+ ",
+"+$&&&&&&&&&&&++k+ +++ +++++ %% $%%%%% $%%%%% %%%%%$ %%%%%$ %% $++++k++ $++++k++ ''''''''''w ''''''''''w .....&&&&..... +&&&&&&&&&&&&&,k+ k , k , `&``YY&$k```kkY %%$ ''''''''''w&&&&+ ++++++++ t+++++++ ",
+"$+,$$$$$$$$$$k+k+ + +++++++ %% $%%%% $%%%% %%%%$ %%%%$ %% %% +++ +++ '''''''''w '''''''''w ....&&&&&&.... +&$$$$$$$$$$$$$k+ ,,, ......... %%%%%%%%% ,,, ......... %%%%%%%%% `&$kY ``$`&$kY %% wwwwww'''w&&&&&+ t+tttttt+t +t t+ ",
+" +$,$$$$$$$$$$+k+ +++ %% $%%% $%%% %%%$ %%%$ %% %% ++% ++% ''''wwwww wwwww'''w ..&&&..&&&.. +&kkkkkkkkkkkk$k+ kkk `&$kY `&$kY %% ''w&&&&&&+ +t t+ t+ +t ",
+" $+,$$$$$$$$$$k++ t+ t++t %% $%% $%% %%$ %%$ %% %%%%%% %% %%%%%% %% '''w '''w ...&....&... +&k++++++++++&$k+ k , `&$kY `&$kY 'w+&&&&&&+ ++t t++k +t t+ ",
+" +$,$$$$$$$$$$++ +t t+++ %% $% $% %$ %$ %% %%%%%% %%%%%% ''w ''w .......... +&&&&&&&&&&&&&$k+ %%%%%%%%% ,,, ......... %%%%%%%%% %%%%%%%%% `kk`Y `kk`Y w +&&&&&$+ t++++ t++++ t++++ t++++ ",
+" +$kkkkkkkkkkk+ ++++++t %% 'w 'w ........ +Okkkkkkkkkkkkk++ `&$kY `&$kY %% +&&&N$O+ ",
+" ++++++++++++++ t+++t %% .... +++++++++++++++ ````` ````` %% +&N$Okt+ ",
+" ++++++++ ",
+" "}; /*
+ ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** ***************** */
diff --git a/Build/source/texk/xdvik/pixmaps/xdvi16x16.xpm b/Build/source/texk/xdvik/pixmaps/xdvi16x16.xpm
new file mode 100644
index 00000000000..8a722b80ca0
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/xdvi16x16.xpm
@@ -0,0 +1,100 @@
+/* XPM */
+static const char * xdvi16x16_xpm[] = {
+"16 16 81 1",
+" c None",
+". c #616060",
+"+ c #161311",
+"@ c #7B7A7B",
+"# c #0F0C0A",
+"$ c #6F7178",
+"% c #FFD549",
+"& c #D39A2D",
+"* c #C4BBB6",
+"= c #000006",
+"- c #6B6D72",
+"; c #7C5A20",
+"> c #8B621A",
+", c #D79C2E",
+"' c #FFCC41",
+") c #DCD0BF",
+"! c #D8D1C9",
+"~ c #FFFFFF",
+"{ c #FCB529",
+"] c #DA9E2E",
+"^ c #CE9834",
+"/ c #8C5B0B",
+"( c #96702C",
+"_ c #626874",
+": c #D3B276",
+"< c #F4B73C",
+"[ c #FDBF42",
+"} c #8B6727",
+"| c #C5A469",
+"1 c #AD915D",
+"2 c #D19F3C",
+"3 c #D7A542",
+"4 c #FFC640",
+"5 c #7E4C00",
+"6 c #CBA153",
+"7 c #ECB03B",
+"8 c #F4BB48",
+"9 c #FFC54A",
+"0 c #785A2B",
+"a c #CCA25E",
+"b c #A8874E",
+"c c #FABD41",
+"d c #CEA55A",
+"e c #845E1D",
+"f c #D8A23D",
+"g c #F5BB48",
+"h c #DBA339",
+"i c #DEA53A",
+"j c #EBB345",
+"k c #856226",
+"l c #A28352",
+"m c #F3B63C",
+"n c #F9BF4B",
+"o c #EAB345",
+"p c #382205",
+"q c #785820",
+"r c #DEA539",
+"s c #987C51",
+"t c #8C6625",
+"u c #F9BA3D",
+"v c #9B8769",
+"w c #FFD049",
+"x c #8E6826",
+"y c #BA8A30",
+"z c #D9A139",
+"A c #A77C2D",
+"B c #F8BB41",
+"C c #FDC24C",
+"D c #FFC646",
+"E c #FFBF40",
+"F c #6E5128",
+"G c #FEC24C",
+"H c #707279",
+"I c #5E6678",
+"J c #596276",
+"K c #482E09",
+"L c #AD894C",
+"M c #777777",
+"N c #090503",
+"O c #04050A",
+"P c #636976",
+".+++. .+.",
+" @###$%% & *=- ",
+" @##=;>,';&=;) ",
+" @#=!~{;]%^%/(",
+" _#!=~~:<;[} ",
+" |12345~=678;90",
+" a%b%%ccdefghi;j",
+" %k%lmccggg8;gn;",
+" opqrsccctc;8;uv",
+" wxyccccxccz;n;j",
+" wyAxAyccBC8;n;",
+" '''wDEEFp%G;j",
+" H=I hJ==K%;L",
+" MNM @#O=P ",
+".NM @###.",
+"+. .+++"};
diff --git a/Build/source/texk/xdvik/pixmaps/xdvi32x32.xpm b/Build/source/texk/xdvik/pixmaps/xdvi32x32.xpm
new file mode 100644
index 00000000000..143ff6dca05
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/xdvi32x32.xpm
@@ -0,0 +1,55 @@
+/* XPM */
+static const char * xdvi32x32_xpm[] = {
+"32 32 20 1",
+" c None",
+". c #767A87",
+"X c #030203",
+"o c #626162",
+"O c #2F1C0F",
+"+ c #160807",
+"@ c #4D310F",
+"# c #FDCB4F",
+"$ c #FEE75B",
+"% c #EFB647",
+"& c #94681D",
+"* c #775117",
+"= c #DCA234",
+"- c #FEFEFE",
+"; c #B0A799",
+": c #937B54",
+"> c #B4852E",
+", c #A48B69",
+"< c #D8D3CA",
+"1 c #D8A847",
+" .XXXXXXX. .XXXo ",
+" OXXXXXX+ @@@ .OXXO ",
+" +XXXXXX.@###O X X oXXX ",
+" XXXXXXX.#+##@O$@%O&.XXX. ",
+" .XXXXXXX%&+#&##O#O#*O+@ ",
+" OXXXXXX&@&###O#O##O&#++ & ",
+" XXXXXXX@@@##%###O####+&=@",
+" XXXXX@--;@:@=#O##&O#+@%>",
+" XXXX@--;:&--@=##&+##+#X ",
+" **:,@-XX;----@#*X##X&#O*",
+" ,&######=@+&--<<-@##%#X&#O& ",
+" ,##########=@--++@=######+#&O",
+" o&#>##>######=@-OO=####+++&&#&",
+" #@&#>###@####%=@@==#######$++@",
+" #*X&#@>@#################++#$@",
+" ##X@@@###############%++###+% ",
+" #@##@>@##############*+++##O ",
+" *@#############+###O####@O@* ",
+" ##+###########+#####+++###O&+",
+" ###++#######++###+&###++###=&",
+" &###+++++++#####%+++##++++&@",
+" ,#############O%%##+#####& ",
+" >*&#%1#%#%#==1@%%%%+#&+%#O",
+" .+X&%=>=*= O@@+%+##+#+@& ",
+" OXX+.,= % XXX@X&#+##+= ",
+" oXXX. XXXX>#+&#+=*",
+" .X+X. o+XXO+X;@& ",
+" XXXo OXXXXXX ",
+" XXXO XXXX+Xo ",
+" oXXX o+XXXXX ",
+" .XXX. XX+XXX+ ",
+" .XXXo XXXXXXo "};
diff --git a/Build/source/texk/xdvik/pixmaps/xdvi48x48.xpm b/Build/source/texk/xdvik/pixmaps/xdvi48x48.xpm
new file mode 100644
index 00000000000..c65fa3347fd
--- /dev/null
+++ b/Build/source/texk/xdvik/pixmaps/xdvi48x48.xpm
@@ -0,0 +1,86 @@
+/* XPM */
+static const char * xdvi48x48_xpm[] = {
+"48 48 35 1",
+" c None",
+". c #848484",
+"+ c #080808",
+"@ c #343434",
+"# c #808080",
+"$ c #3C3B3C",
+"% c #7D7D7D",
+"& c #505050",
+"* c #946924",
+"= c #FDC54E",
+"- c #523611",
+"; c #2F261C",
+"> c #6D4E1E",
+", c #665641",
+"' c #EBB345",
+") c #9F896C",
+"! c #B78833",
+"~ c #626262",
+"{ c #A9A5A2",
+"] c #FEFEFE",
+"^ c #DAD6D1",
+"/ c #D7A03A",
+"( c #C7BFB5",
+"_ c #493415",
+": c #64471A",
+"< c #E9B345",
+"[ c #8D7757",
+"} c #696159",
+"| c #EFEEEE",
+"1 c #8F7C5A",
+"2 c #65513A",
+"3 c #9C9C9B",
+"4 c #D59E39",
+"5 c #444444",
+"6 c #4C4C4C",
+".+++++++++++@ @++@ ",
+" #++++++++++++ +++$ ",
+" $+++++++++++@ @+++ ",
+" @+++++++++++% +++++ ++ ++ &+++ ",
+" ++++++++++++ +*===+ +==+ +==+ -.+++. ",
+" +++++++++++@ +==;>=+===+ +==++++++, ",
+" #+++++++++++& +'>;==+===+==+=+==+=+ ++ ",
+" @+++++++++++ +'*>=+==+==+==+=+'+++''+ ",
+" ++++++++++++ )+========+==+===-''+''+ ",
+" +++++++++++@ ----!========+===-=+''+'+ ",
+" @+++++++++++~-{]]^-=/========!-=++++='+ ",
+" +++++++++++-{]]]]-)---!======!+!''*++ ",
+" ++++++++++-]);](-(]]^-!====!+=====+- ",
+" +++++;-->-];;)-^]]]]^-===/+==*-*=+=+ ",
+" *-_:!/===<-^(--^]]]]]]-===+=!>++/=+'+ ",
+" **==========!---[]]]^^](-=====+++!=+''+ ",
+" *==============/*}]]^;;|-/===/+-!==+!++* ",
+" *==**/===========/-^]^;;}-=========+!'''- ",
+" *+=*===============!-^]^^-======++++!=+'='-",
+" ='+===*/============/----==============+++ ",
+" !*--=*====+*/=====================++++===+}",
+" ''>+>===++/==========================++===+",
+" '''++++>=======================++=====+=++ ",
+" '*-*+''++======================+++====+ ",
+" +'*==++''+!======================+++===+ ",
+" =;+====+!============-==============++=++ ",
+" /==+================-+=====+++========+=> ",
+" !==+==============-+========+++=======++}",
+" ===+-/==========-+======+====+++======+ ",
+" !===>++*======-+-=======-+======++++=+ ",
+" !=====++++++++=====-=====+++======++= ",
+" !=================+======++======++- ",
+" 1#/============+-====+==+++======+ ",
+" .+++/=/====++++++++==+====+==-==+2 ",
+" .+++@>=>=-=- @++++'-==+===+===-=+ ",
+" @+++3[>->4- @++++'-=+===+===-=+ ",
+" ~+++. +++++===++==+===-=+ ",
+" .+++# ++++++==++++===-+ ",
+" +++5 #+++++++++++++++ ",
+" @+++. @++++++++++- ",
+" 6+++ +++++++++++& ",
+" .+++# +++++++++++. ",
+" +++# @+++++++++++ ",
+" +++5 +++++++++++@ ",
+" @+++. +++++++++++~ ",
+" 6+++. +++++++++++# ",
+" #+++# +++++++++++& ",
+" +++++++++++."};
diff --git a/Build/source/texk/xdvik/pk.c b/Build/source/texk/xdvik/pk.c
new file mode 100644
index 00000000000..4ef0170ae48
--- /dev/null
+++ b/Build/source/texk/xdvik/pk.c
@@ -0,0 +1,387 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2004 Paul Vojta
+
+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
+ in xdvi.c.
+
+\*========================================================================*/
+
+/*
+ * PK font reading routines.
+ * Public routines are read_PK_index and read_PK_char.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "dvi-init.h"
+#include "util.h"
+
+#define PK_ID 89
+#define PK_CMD_START 240
+#define PK_X1 240
+#define PK_X2 241
+#define PK_X3 242
+#define PK_X4 243
+#define PK_Y 244
+#define PK_POST 245
+#define PK_NOOP 246
+#define PK_PRE 247
+
+static int PK_flag_byte;
+static unsigned PK_input_byte;
+static int PK_bitpos;
+static int PK_dyn_f;
+static int PK_repeat_count;
+
+static int
+PK_get_nyb(FILE *fp)
+{
+ unsigned temp;
+ if (PK_bitpos < 0) {
+ PK_input_byte = get_byte(fp);
+ PK_bitpos = 4;
+ }
+ temp = PK_input_byte >> PK_bitpos;
+ PK_bitpos -= 4;
+ return (temp & 0xf);
+}
+
+
+static int
+PK_packed_num(FILE *fp)
+{
+ int i, j;
+
+ if ((i = PK_get_nyb(fp)) == 0) {
+ do {
+ j = PK_get_nyb(fp);
+ ++i;
+ }
+ while (j == 0);
+ while (i > 0) {
+ j = (j << 4) | PK_get_nyb(fp);
+ --i;
+ }
+ return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f);
+ }
+ else {
+ if (i <= PK_dyn_f)
+ return i;
+ if (i < 14)
+ return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp)
+ + PK_dyn_f + 1);
+ if (i == 14)
+ PK_repeat_count = PK_packed_num(fp);
+ else
+ PK_repeat_count = 1;
+ return PK_packed_num(fp);
+ }
+}
+
+
+static void
+PK_skip_specials(struct font *fontp)
+{
+ int i, j;
+ FILE *fp = fontp->file;
+
+ do {
+ PK_flag_byte = get_byte(fp);
+ if (PK_flag_byte >= PK_CMD_START) {
+ switch (PK_flag_byte) {
+ case PK_X1:
+ case PK_X2:
+ case PK_X3:
+ case PK_X4:
+ i = 0;
+ for (j = PK_CMD_START; j <= PK_flag_byte; ++j)
+ i = (i << 8) | get_byte(fp);
+ while (i--)
+ (void)get_byte(fp);
+ break;
+ case PK_Y:
+ (void)get_bytes(fp, 4);
+ case PK_POST:
+ case PK_NOOP:
+ break;
+ default:
+ XDVI_FATAL((stderr, "Unexpected %d in PK file %s", PK_flag_byte,
+ fontp->filename));
+ break;
+ }
+ }
+ }
+ while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START);
+}
+
+/*
+ * Public routines
+ */
+
+static void
+read_PK_char(struct font *fontp,
+ wide_ubyte ch)
+{
+ int i, j;
+ int n;
+ int row_bit_pos;
+ Boolean paint_switch;
+ bmUnitT *cp;
+ struct glyph *g;
+ FILE *fp = fontp->file;
+ long fpwidth;
+ bmUnitT word = 0;
+ int word_weight, bytes_wide;
+ int rows_left, h_bit, count;
+
+ g = &fontp->glyph[ch];
+ PK_flag_byte = g->x2;
+ PK_dyn_f = PK_flag_byte >> 4;
+ paint_switch = ((PK_flag_byte & 8) != 0);
+ PK_flag_byte &= 0x7;
+ if (PK_flag_byte == 7)
+ n = 4;
+ else if (PK_flag_byte > 3)
+ n = 2;
+ else
+ n = 1;
+
+ if (globals.debug & DBG_PK)
+ printf("loading pk char %d, char type %d ", ch, n);
+
+ /*
+ * now read rest of character preamble
+ */
+ if (n != 4)
+ fpwidth = get_bytes(fp, 3);
+ else {
+ fpwidth = get_lbytes(fp, 4);
+ (void)get_bytes(fp, 4); /* horizontal escapement */
+ }
+ (void)get_bytes(fp, n); /* vertical escapement */
+ {
+ unsigned long w, h;
+
+ w = get_bytes(fp, n);
+ h = get_bytes(fp, n);
+ /* bitmap.w and bitmap.h are of type `unsigned short', so check for possible
+ overflow here. USHRT_MAX should be sufficient, since a character of
+ 30pt at 1200dpi requires about 560 x 560 pixels; and the maximum
+ bitmap of size USHRT_MAX * USHRT_MAX would consume USHRT_MAX * USHRT_MAX / 8
+ bytes ~= 530MB of RAM (per character/font!)
+ */
+ if (w > USHRT_MAX || h > USHRT_MAX)
+ XDVI_FATAL((stderr, "Character %d too large (%ld x %ld, max is %d x %d) in file %s",
+ ch, w, h, USHRT_MAX, USHRT_MAX, fontp->fontname));
+ g->bitmap.w = w;
+ g->bitmap.h = h;
+ }
+ g->x = get_lbytes(fp, n);
+ g->y = get_lbytes(fp, n);
+
+ g->dvi_adv = fontp->dimconv * fpwidth;
+
+ if (globals.debug & DBG_PK) {
+ if (g->bitmap.w != 0)
+ printf(", size=%dx%d, dvi_adv=%ld", g->bitmap.w, g->bitmap.h,
+ g->dvi_adv);
+ putchar('\n');
+ }
+
+ alloc_bitmap(&g->bitmap);
+ cp = (bmUnitT *) g->bitmap.bits;
+
+ /*
+ * read character data into *cp
+ */
+ bytes_wide = ROUNDUP((int)g->bitmap.w, BMBITS) * BMBYTES;
+ PK_bitpos = -1;
+ if (PK_dyn_f == 14) { /* get raster by bits */
+ memset(g->bitmap.bits, 0, (int)g->bitmap.h * bytes_wide);
+ for (i = 0; i < (int)g->bitmap.h; i++) { /* get all rows */
+ cp = ADD(g->bitmap.bits, i * bytes_wide);
+#ifndef WORDS_BIGENDIAN
+ row_bit_pos = -1;
+#else
+ row_bit_pos = BMBITS;
+#endif
+ for (j = 0; j < (int)g->bitmap.w; j++) { /* get one row */
+ if (--PK_bitpos < 0) {
+ word = get_byte(fp);
+ PK_bitpos = 7;
+ }
+#ifndef WORDS_BIGENDIAN
+ if (++row_bit_pos >= BMBITS) {
+ cp++;
+ row_bit_pos = 0;
+ }
+#else
+ if (--row_bit_pos < 0) {
+ cp++;
+ row_bit_pos = BMBITS - 1;
+ }
+#endif
+ if (word & (1 << PK_bitpos))
+ *cp |= 1 << row_bit_pos;
+ }
+ }
+ }
+ else { /* get packed raster */
+ rows_left = g->bitmap.h;
+ h_bit = g->bitmap.w;
+ PK_repeat_count = 0;
+ word_weight = BMBITS;
+ word = 0;
+ while (rows_left > 0) {
+ count = PK_packed_num(fp);
+ while (count > 0) {
+ if (count < word_weight && count < h_bit) {
+#ifndef WORDS_BIGENDIAN
+ if (paint_switch)
+ word |= bit_masks[count] << (BMBITS - word_weight);
+#endif
+ h_bit -= count;
+ word_weight -= count;
+#ifdef WORDS_BIGENDIAN
+ if (paint_switch)
+ word |= bit_masks[count] << word_weight;
+#endif
+ count = 0;
+ }
+ else if (count >= h_bit && h_bit <= word_weight) {
+ if (paint_switch)
+ word |= bit_masks[h_bit] <<
+#ifndef WORDS_BIGENDIAN
+ (BMBITS - word_weight);
+#else
+ (word_weight - h_bit);
+#endif
+ *cp++ = word;
+ /* "output" row(s) */
+ for (i = PK_repeat_count * bytes_wide / BMBYTES; i > 0; --i) {
+ *cp = *SUB(cp, bytes_wide);
+ ++cp;
+ }
+ rows_left -= PK_repeat_count + 1;
+ PK_repeat_count = 0;
+ word = 0;
+ word_weight = BMBITS;
+ count -= h_bit;
+ h_bit = g->bitmap.w;
+ }
+ else {
+ if (paint_switch)
+#ifndef WORDS_BIGENDIAN
+ word |= bit_masks[word_weight] <<
+ (BMBITS - word_weight);
+#else
+ word |= bit_masks[word_weight];
+#endif
+ *cp++ = word;
+ word = 0;
+ count -= word_weight;
+ h_bit -= word_weight;
+ word_weight = BMBITS;
+ }
+ }
+ paint_switch = 1 - paint_switch;
+ }
+ if (cp != ((bmUnitT *) (g->bitmap.bits + bytes_wide * g->bitmap.h)))
+ XDVI_FATAL((stderr, "Wrong number of bits stored: char. %d, font %s", ch,
+ fontp->fontname));
+ if (rows_left != 0 || h_bit != g->bitmap.w)
+ XDVI_FATAL((stderr, "Bad pk file (%s), too many bits", fontp->fontname));
+ }
+}
+
+void
+read_PK_index(struct font *fontp, wide_bool hushcs)
+{
+ int hppp, vppp;
+ long checksum;
+
+ fontp->read_char = read_PK_char;
+ if (globals.debug & DBG_PK)
+ printf("Reading PK pixel file %s\n", fontp->filename);
+
+ fseek(fontp->file, (long)get_byte(fontp->file), SEEK_CUR); /* skip comment */
+
+ (void)get_bytes(fontp->file, 4); /* skip design size */
+ checksum = get_bytes(fontp->file, 4);
+ if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
+ && !hushcs)
+ XDVI_WARNING((stderr, "Checksum mismatch (dvi = %lu, pk = %lu) in font file %s",
+ fontp->checksum, checksum, fontp->filename));
+ hppp = get_lbytes(fontp->file, 4);
+ vppp = get_lbytes(fontp->file, 4);
+ if (hppp != vppp && (globals.debug & DBG_PK))
+ printf("Font has non-square aspect ratio %d:%d\n", vppp, hppp);
+ /*
+ * Prepare glyph array.
+ */
+ fontp->glyph = xmalloc(256 * sizeof(struct glyph));
+ memset((char *)fontp->glyph, 0, 256 * sizeof(struct glyph));
+ /*
+ * Read glyph directory (really a whole pass over the file).
+ */
+ for (;;) {
+ int bytes_left, flag_low_bits;
+ unsigned int ch;
+
+ PK_skip_specials(fontp);
+ if (PK_flag_byte == PK_POST)
+ break;
+ flag_low_bits = PK_flag_byte & 0x7;
+ if (flag_low_bits == 7) {
+ bytes_left = get_bytes(fontp->file, 4);
+ ch = get_bytes(fontp->file, 4);
+ }
+ else if (flag_low_bits > 3) {
+ bytes_left = ((flag_low_bits - 4) << 16) + get_bytes(fontp->file, 2);
+ ch = get_byte(fontp->file);
+ }
+ else {
+ bytes_left = (flag_low_bits << 8) + get_byte(fontp->file);
+ ch = get_byte(fontp->file);
+ }
+ fontp->glyph[ch].addr = ftell(fontp->file);
+ fontp->glyph[ch].x2 = PK_flag_byte;
+#ifdef linux
+# ifndef SHORTSEEK
+# define SHORTSEEK 2048
+# endif
+ /* A bug in Linux libc (as of 18oct94) makes a short read faster
+ than a short forward seek. Totally non-intuitive. */
+ if (bytes_left > 0 && bytes_left < SHORTSEEK) {
+ char *dummy = xmalloc(bytes_left);
+ fread(dummy, 1, bytes_left, fontp->file);
+ free(dummy);
+ }
+ else
+ /* seek backward, or long forward */
+#endif /* linux */
+ fseek(fontp->file, (long)bytes_left, SEEK_CUR);
+ if (globals.debug & DBG_PK)
+ printf("Scanning pk char %u, at %ld.\n", ch, fontp->glyph[ch].addr);
+ }
+}
diff --git a/Build/source/texk/xdvik/print-internal.c b/Build/source/texk/xdvik/print-internal.c
new file mode 100644
index 00000000000..c47ab73ed84
--- /dev/null
+++ b/Build/source/texk/xdvik/print-internal.c
@@ -0,0 +1,814 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * 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.
+ */
+
+/*
+ * SU: Printing/saving backend code (all the non-GUI stuff),
+ * adapted from non-k xdvi's popups.c.
+ *
+ * Implementation notes:
+ * All inter-process communication happens in an asynchronous
+ * fasion, so that the GUI remains responsive. This means that if
+ * there are several processes in sequence (e.g. dvips invocation,
+ * then ps2pdf invocation), the latter must be called by the child
+ * watching procedure of the former (e.g. ps2pdf_exited by the
+ * fork_process() callback in call_ps2pdf()), else we can't catch its
+ * return status, do cleanup afterwards etc., because the code inside
+ * the caller may be executed *before* the child has finished. (Note
+ * e.g. how unlink()ing the temporary PS file is done inside
+ * ps2pdf_exited() and not in the callers). This is the reason why we
+ * often need to pass information to the subprocess (via a data `void *').
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "dvisel.h" /* for select_pages_info struct */
+#include "print-internal.h"
+#include "print-log.h"
+#include "search-internal.h"
+#include "events.h"
+#include "message-window.h"
+#include "util.h"
+#include "x_util.h"
+#include "string-utils.h"
+#include "my-snprintf.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+# define O_NONBLOCK O_NDELAY
+#endif
+
+#ifdef EWOULDBLOCK
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+# else
+# define AGAIN_CONDITION (errno == EWOULDBLOCK)
+# endif
+#else /* EWOULDBLOCK */
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EAGAIN)
+# endif
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif /* HAVE_POLL */
+
+static struct xchild print_child = {NULL, 0, True, "dvips", NULL, NULL, NULL };
+
+static char *read_from_dvips(int);
+static struct xio print_xio = { NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_dvips,
+ NULL /* write proc - not needed */
+};
+
+static void dvips_alarm(struct xtimer *);
+static struct xtimer dvips_timer = {NULL, {0, 0}, XTM_DEFAULT, dvips_alarm
+#if XDVI_XT_TIMER_HACK
+ , NULL, NULL
+#endif
+};
+
+static int dvips_sig; /* SIGINT or SIGKILL */
+
+static int dvips_status;
+static const int DVIPS_STAT_NONE = 0;
+static const int DVIPS_STAT_RUN = 1;
+static const int DVIPS_STAT_WAIT = 2;
+
+/*
+ FIXME: implement this in terms of fork_process()!
+ Currently it doesn't work since the DVI file and the
+ output file are realized via redirecting stdin/stdout.
+ This also obscures the log output (the I/O redirection
+ isn't visible to users).
+
+ TODO: Remove the detailed log output, and implement
+ a progress window that only shows the page numbers.
+ The detailed log should go to an `xdvi log output' page.
+*/
+
+static void
+fork_dvips(char **argv, const struct select_pages_info *pinfo, childProcT proc)
+{
+ int print_io[2];
+ int i;
+ const struct file_info *finfo = pinfo->finfo;
+ /* printlog_append(argv[0], strlen(argv[0])); */
+ FILE *fout = NULL;
+
+ if (finfo->ps_out.fname != NULL) {
+ /* printing to PS file, open file for writing */
+ if ((fout = XFOPEN(finfo->ps_out.fname, "w")) == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL, "Could not open %s for writing: %s.",
+ finfo->ps_out.fname,
+ strerror(errno));
+ return;
+ }
+ }
+
+ printlog_popup();
+
+ printlog_append_str("Calling: `");
+ printlog_append_str(argv[0]);
+
+ for (i = 1; argv[i] != NULL; i++) {
+ printlog_append_str(" ");
+ printlog_append_str(argv[i]);
+ }
+ printlog_append_str("'\n");
+
+ if (xpipe(print_io) != 0) {
+ perror("[xdvi] pipe");
+ return;
+ }
+
+ /* Fork process */
+
+ /* 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(stderr);
+ fflush(stdout);
+
+ print_child.name = xstrdup(argv[0]);
+ print_child.proc = proc;
+ print_child.data = (void *)pinfo;
+ print_child.pid = fork();
+ if (print_child.pid == 0) { /* if child */
+ /* change into dir of DVI file so that included image files etc. are found */
+ chdir(globals.dvi_file.dirname);
+
+ if (globals.debug & DBG_FILES) {
+ char path[MAXPATHLEN];
+ getcwd(path, MAXPATHLEN);
+ fprintf(stderr, "Directory of running `%s': `%s'\n",
+ argv[0], path);
+ }
+
+ /* make the input file pointer the STDIN of the dvips process */
+ if (finfo->dvi_tmp.fp != NULL) { /* printing selected pages from temporary file */
+ (void)dup2(fileno(finfo->dvi_tmp.fp), STDIN_FILENO);
+ }
+ else { /* printing from main or backup file */
+ (void)dup2(fileno(finfo->dvi_in.fp), STDIN_FILENO);
+ }
+ (void)lseek(0, 0, SEEK_SET);
+
+ if (fout != NULL) { /* printing to file, make stdout of child go to fout */
+ (void)dup2(fileno(fout), STDOUT_FILENO);
+ (void)close(fileno(fout));
+ }
+ else { /* printing to printer, make stdout of child go to print_io[1] */
+ (void)dup2(print_io[1], STDOUT_FILENO);
+ }
+
+ /* make stderr of child go to print_io[1] */
+ (void)dup2(print_io[1], STDERR_FILENO);
+ (void)close(print_io[1]);
+ (void)close(print_io[0]);
+
+ if (setsid() == -1) { /* so we can kill the process group */
+ perror("setsid");
+ fflush(stderr);
+ _exit(1);
+ }
+ (void)execvp(*argv, argv);
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Execution of \"%s\" failed: %s.\n", *argv, strerror(errno));
+ fflush(stderr);
+ _exit(1);
+ }
+
+ if (fout != NULL)
+ fclose(fout);
+
+ if (print_child.pid == -1) { /* error */
+ perror("[xdvi] vfork");
+ return;
+ }
+
+ set_chld(&print_child);
+ dvips_sig = SIGINT;
+
+ (void)close(print_io[1]);
+
+ /* Set up file descriptor for non-blocking I/O */
+ prep_fd(print_io[0], True);
+ print_xio.fd = print_io[0];
+ set_io(&print_xio);
+
+ dvips_status = DVIPS_STAT_RUN; /* running */
+}
+
+/*
+ * Create an argument list for dvips, using information from pinfo
+ * and X resources. Returns the result list in freshly allocated
+ * memory.
+ */
+static char **
+create_dvips_argv(const struct select_pages_info *pinfo, Boolean do_pdf, printOrSaveActionT act)
+{
+ size_t argv_len = 128; /* should be ample ... */
+ char **argv = xmalloc(argv_len * sizeof *argv);
+ size_t idx = 0;
+ const char *printer_options = get_printer_options();
+ char *dvips_options = get_dvips_options(act);
+ char from_page[LENGTH_OF_INT];
+ char to_page[LENGTH_OF_INT];
+
+ TRACE_GUI((stderr, "dvips options: |%s|", dvips_options));
+
+ argv[idx++] = xstrdup(resource.dvips_path);
+
+ if (dvips_options != NULL) {
+ char **dvips_args = get_separated_list(dvips_options, " \t", True); /* this allocates dvips_args */
+ int i;
+ for (i = 0; dvips_args[i] != NULL; i++) {
+ argv[idx++] = dvips_args[i];
+ }
+ free(dvips_args);
+ }
+
+ if (do_pdf)
+ argv[idx++] = xstrdup("-Ppdf");
+
+ argv[idx++] = xstrdup("-f");
+
+ if (printer_options != NULL && pinfo->finfo->ps_out.fname == NULL) { /* printing to printer */
+ char **printer_args = get_separated_list(printer_options, " \t", True); /* this allocates printer_args */
+ int i;
+ ASSERT(*printer_args != NULL, "args should contain at least the string \"lpr\"");
+ argv[idx] = xstrdup("-o!");
+ argv[idx] = xstrcat(argv[idx], printer_args[0]);
+ free(printer_args[0]);
+ /* now append everything to the printer pipe command, so that dvips doesn't see it as an option */
+ for (i = 1; printer_args[i] != NULL; i++) {
+ argv[idx] = xstrcat(argv[idx], " ");
+ argv[idx] = xstrcat(argv[idx], printer_args[i]);
+ free(printer_args[i]);
+ }
+ free(printer_args);
+ idx++;
+ }
+
+ if (pinfo->callback == check_pagerange) {
+ /* convert back from 0-based to 1-based, also taking globals.pageno_correct into accout
+ * (which is 1 by default, so we need to add 2) */
+ argv[idx] = xstrdup("-p=");
+ SNPRINTF(from_page, LENGTH_OF_INT, "%d", pinfo->from - globals.pageno_correct + 2);
+ argv[idx] = xstrcat(argv[idx], from_page);
+ idx++;
+ argv[idx] = xstrdup("-l=");
+ SNPRINTF(to_page, LENGTH_OF_INT, "%d", pinfo->to - globals.pageno_correct + 2);
+ argv[idx] = xstrcat(argv[idx], to_page);
+ idx++;
+ }
+
+ argv[idx] = NULL; /* terminate it */
+ ASSERT(idx <= argv_len, "Too many elements");
+ return argv;
+}
+
+/* Check if selecting pages worked, report error else */
+static Boolean
+select_pages_report_error(const struct select_pages_info *pinfo)
+{
+ if (pinfo->errflag == NO_ERROR)
+ return False;
+
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ NULL,
+ "Could not save DVI file to %s: %s.",
+ pinfo->finfo->dvi_tmp.fname,
+ get_dvi_error(pinfo->errflag));
+ return True;
+}
+
+
+/*
+ * Collect dvips output, appending to print log.
+ * Currently return value is a dummy (NULL); TODO: return
+ * the output, for later filtering.
+ */
+static char *
+read_from_dvips(int ignored)
+{
+ int bytes;
+ char line[80];
+
+ UNUSED(ignored);
+
+ for (;;) {
+#ifndef MOTIF
+ bytes = read(print_xio.fd, line, sizeof line);
+#else
+ bytes = read(print_xio.fd, line, sizeof line - 1);
+#endif
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi: read_from_dvips");
+ break;
+ }
+
+ if (bytes == 0)
+ break;
+ else {
+#ifdef MOTIF
+ line[bytes] = '\0';
+#endif
+ printlog_append(line, bytes);
+ }
+ }
+ return NULL; /* TODO */
+}
+
+/*
+ * Report dvips exit status, and remove temporary DVI file if needed.
+ */
+static void
+dvips_exited(int exitval, struct xchild *child)
+{
+ char str[128] = "";
+ int ms;
+
+ struct select_pages_info *pinfo = (struct select_pages_info *)child->data;
+
+ read_from_dvips(0);
+ clear_io(&print_xio);
+ (void)close(print_xio.fd);
+
+ if (WIFEXITED(exitval)) {
+ if (WEXITSTATUS(exitval) == 0) {
+ if (pinfo->finfo->ps_out.fname != NULL) {
+ printlog_append_str("\nCreated Postscript file ");
+ printlog_append_str(pinfo->finfo->ps_out.fname);
+ printlog_append_str(".\n");
+ }
+ else {
+ printlog_append_str("Done.\n");
+ }
+
+ /* remove temporary DVI file if it exists */
+ if (pinfo->finfo->dvi_tmp.fname != NULL) {
+ if (globals.debug & DBG_GUI)
+ TRACE_GUI((stderr, "NOT removing temporary DVI file: |%s|", pinfo->finfo->dvi_tmp.fname));
+ else
+ unlink(pinfo->finfo->dvi_tmp.fname);
+ }
+ }
+ else
+ sprintf(str, "\nDvips returned exit code %d.\n", WEXITSTATUS(exitval));
+ }
+ else if (WIFSIGNALED(exitval))
+ sprintf(str, "\nDvips terminated by signal %d.\n", WTERMSIG(exitval));
+ else
+ sprintf(str, "\nDvips returned unknown status 0x%x.\n", exitval);
+
+ ms = resource.dvips_hang;
+ if (str[0] != '\0') {
+ XBell(DISP, 0);
+ ms = resource.dvips_fail_hang;
+ printlog_append_str(str);
+ }
+
+ if (ms > 0) {
+ set_timer(&dvips_timer, ms);
+ dvips_status = DVIPS_STAT_WAIT;
+ }
+ else {
+ dvips_status = DVIPS_STAT_NONE;
+ }
+
+ printlog_enable_closebutton();
+}
+
+/*
+ * Report pd2pdf exit status, and remove temporary PS file if needed.
+ */
+static void
+ps2pdf_exited(int status, struct xchild *this)
+{
+ char *err_msg = NULL;
+ int ms = resource.dvips_hang;
+ /* if child exited with error and xio struct is available for child,
+ print error text */
+ if (this->io != NULL && (WIFEXITED(status) != 0)) {
+ if ((WEXITSTATUS(status) != 0)
+ && (err_msg = (this->io->read_proc)(this->io->fd)) != NULL) {
+ char buf[LENGTH_OF_INT];
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", WEXITSTATUS(status));
+ ms = resource.dvips_fail_hang;
+ XBell(DISP, 0);
+ printlog_append_str("\n\nError calling ");
+ if (this->name != NULL) {
+ printlog_append_str("\"");
+ printlog_append_str(this->name);
+ printlog_append_str("\" ");
+ }
+ printlog_append_str("\nCommand exited with error code ");
+ printlog_append_str(buf);
+ printlog_append_str(":\n");
+ printlog_append_str(err_msg);
+ free(err_msg);
+ }
+ else {
+ const struct select_pages_info *pinfo = (const struct select_pages_info *)this->data;
+ int retval;
+ printlog_append_str("\nCreated PDF file ");
+ printlog_append_str(pinfo->finfo->pdf_out.fname);
+ printlog_append_str(".\n");
+ TRACE_FILES((stderr, "Removing temporary PS file: `%s'",
+ pinfo->finfo->ps_out.fname));
+ retval = unlink(pinfo->finfo->ps_out.fname);
+ if (retval != 0) {
+ fprintf(stderr, "Could not unlink `%s': %s.\n",
+ pinfo->finfo->ps_out.fname, strerror(errno));
+ }
+ }
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, REPORT_XDVI_BUG_TEMPLATE,
+ "Internal error: ps2pdf_exited() called while child still running?");
+ }
+ if (ms > 0) {
+ set_timer(&dvips_timer, ms);
+ dvips_status = DVIPS_STAT_WAIT;
+ }
+ else {
+ dvips_status = DVIPS_STAT_NONE;
+ }
+
+ printlog_enable_closebutton();
+
+ free(this->name);
+ free(this->io);
+ free(this);
+}
+
+static void
+call_ps2pdf(const char *path, const struct select_pages_info *pinfo)
+{
+ const char *argv[5];
+ size_t idx = 0;
+
+ argv[idx++] = path;
+ argv[idx++] = pinfo->finfo->ps_out.fname;
+ argv[idx++] = pinfo->finfo->pdf_out.fname;
+ argv[idx++] = NULL;
+
+ /* need to run this in globals.xdvi_dir again, since the dvips conversion directory
+ globals.dvi_file.dirname may not be writable! */
+ if (!fork_process("ps2pdf", True, globals.xdvi_dir, ps2pdf_exited, (void *)pinfo, (char **)argv)) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL, "Couldn't fork %s process: %s\n", argv[0], strerror(errno));
+ }
+}
+
+static void
+dvips_ps2pdf(int exitval, struct xchild *child)
+{
+ char str[128] = "";
+ int ms;
+ struct select_pages_info *pinfo = (struct select_pages_info *)child->data;
+
+ read_from_dvips(0);
+ clear_io(&print_xio);
+ (void)close(print_xio.fd);
+
+ if (WIFEXITED(exitval)) {
+ if (WEXITSTATUS(exitval) == 0) {
+ /* dvips ended OK; call ps2pdf: */
+ TRACE_GUI((stderr, "Created temporary PS file |%s|", pinfo->finfo->ps_out.fname));
+ printlog_append_str("\nCalling ");
+ printlog_append_str(resource.ps2pdf_path);
+ printlog_append_str(" ...");
+
+ /* remove temporary DVI file if it exists */
+ if (pinfo->finfo->dvi_tmp.fname != NULL) {
+ if (globals.debug & DBG_GUI)
+ TRACE_GUI((stderr, "NOT removing temporary DVI file: |%s|", pinfo->finfo->dvi_tmp.fname));
+ else
+ unlink(pinfo->finfo->dvi_tmp.fname);
+ }
+ /* invoke ps2pdf conversion */
+ call_ps2pdf(resource.ps2pdf_path, pinfo);
+ }
+ else
+ sprintf(str, "\nPrint process returned exit code %d.\n",
+ WEXITSTATUS(exitval));
+ }
+ else if (WIFSIGNALED(exitval))
+ sprintf(str, "\nPrint process terminated by signal %d.\n",
+ WTERMSIG(exitval));
+ else
+ sprintf(str, "\nPrint process returned unknown status 0x%x.\n",
+ exitval);
+
+ /* enable close button only if dvips conversion already failed */
+ ms = resource.dvips_hang;
+ if (str[0] != '\0') {
+ XBell(DISP, 0);
+ ms = resource.dvips_fail_hang;
+ printlog_append_str(str);
+
+ if (ms > 0) {
+ set_timer(&dvips_timer, ms);
+ dvips_status = DVIPS_STAT_WAIT;
+ }
+ else {
+ dvips_status = DVIPS_STAT_NONE;
+ }
+
+ printlog_enable_closebutton();
+ }
+}
+
+
+static void
+dvips_alarm(struct xtimer *should_be_timer)
+{
+ UNUSED(should_be_timer);
+
+ printlog_popdown(False);
+
+ dvips_status = DVIPS_STAT_NONE;
+}
+
+
+
+static void
+cb_dvips_unkeep(Widget w, XtPointer client_data, XtPointer call_data)
+{
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ /* use negative value so that we don't loose the value itself */
+ TRACE_GUI((stderr, "toggling resource from %d to %d, %d to %d",
+ resource.dvips_hang, -resource.dvips_hang,
+ resource.dvips_fail_hang, -resource.dvips_fail_hang));
+ resource.dvips_hang = -resource.dvips_hang;
+ resource.dvips_fail_hang = -resource.dvips_fail_hang;
+
+ store_preference(NULL, "dvipsHangTime", "%d", resource.dvips_hang);
+ store_preference(NULL, "dvipsFailHangTime", "%d", resource.dvips_fail_hang);
+
+
+ if (dvips_status == DVIPS_STAT_WAIT) {
+ dvips_status = DVIPS_STAT_NONE;
+ cancel_timer(&dvips_timer);
+ }
+}
+
+/* if user selects the window manager destroy button */
+static void
+cb_dvips_destroy(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (dvips_status == DVIPS_STAT_RUN) {
+ kill(print_child.pid, dvips_sig);
+ dvips_sig = SIGKILL;
+ printlog_append_str("^C");
+ }
+
+ if (dvips_status == DVIPS_STAT_WAIT) {
+ dvips_status = DVIPS_STAT_NONE;
+ cancel_timer(&dvips_timer);
+ }
+
+ printlog_reset();
+ printlog_popdown(True);
+}
+
+static void
+cb_dvips_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (dvips_status != DVIPS_STAT_RUN)
+ return; /* How did we get here? */
+
+ kill(print_child.pid, dvips_sig);
+ dvips_sig = SIGKILL;
+ printlog_append_str("^C");
+}
+
+static void
+cb_dvips_close(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (dvips_status == DVIPS_STAT_RUN)
+ return; /* How did we get here? */
+
+ if (dvips_status == DVIPS_STAT_WAIT) {
+ dvips_status = DVIPS_STAT_NONE;
+ cancel_timer(&dvips_timer);
+ }
+
+ printlog_popdown(True);
+}
+
+
+void
+internal_save(struct select_pages_info *pinfo,
+ outputFormatT output_format)
+{
+ struct file_info *finfo = pinfo->finfo;
+ int tmp_fd;
+ char **argv = NULL;
+ int i;
+ childProcT dvips_exit_proc = dvips_exited; /* default procedure to call after fork_dvips() */
+ Boolean do_pdf = False; /* force `-Ppdf' for dvips? (used for ps2pdf conversion) */
+
+ ASSERT(output_format != FMT_NONE, "No valid output format selected!");
+
+ switch (output_format) {
+
+ case FMT_DVI:
+ /* here we first create a temporary file, and if that succeeded,
+ move it to the final position */
+ select_pages(pinfo);
+
+ if (!select_pages_report_error(pinfo)) {
+ /*
+ * ... else, move the temporary file to its final destination. For that, we
+ * try the more efficient rename() first; if this fails, try copying the file
+ * (rename() will e.g. fail if the tmp directory is on a different file
+ * system). We could perhaps examine errno after the renaming attempt to
+ * find out whether we need to do the copy attempt in the first place, but
+ * that'd be rather error-prone ... */
+ ASSERT(finfo->dvi_tmp.fname != NULL, "filename mustn't be NULL");
+ if (rename(finfo->dvi_tmp.fname, finfo->dvi_out.fname) != 0
+ && !copy_file(finfo->dvi_tmp.fname, finfo->dvi_out.fname)) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL, "Creating %s failed: %s",
+ finfo->dvi_out.fname, strerror(errno));
+ }
+ else { /* moving worked */
+ TRACE_GUI((stderr, "renamed %s to %s\n", finfo->dvi_tmp.fname, finfo->dvi_out.fname));
+
+ if (pinfo->warn_files.stack_len > 0) { /* do we need to warn user about referenced files? */
+ char *warn_files = xstrdup("");
+ size_t i;
+ for (i = 0; i < pinfo->warn_files.stack_len; i++) {
+ warn_files = xstrcat(warn_files, pinfo->warn_files.items[i].content);
+ warn_files = xstrcat(warn_files, "\n");
+ }
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ "The files listed in the message (probably images) are not part "
+ "of the newly created DVI file; they are only referenced by that file. "
+ "Therefore, if you want to distribute this file or use it on a different computer,"
+ "you will need to distribute all the referenced files, too.\n\n"
+ "Tip: A better format for distributing files is Postscript or PDF. "
+ "To create a Postscript file, use the `File->Print' menu, "
+ "then select `Print to file' in the dialog window.",
+ "Created %s.\n"
+ "Please note that the following files are referenced by this file, "
+ "and are needed for displaying or printing it correctly:\n%s\n",
+ finfo->dvi_out.fname, warn_files);
+ free(warn_files);
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ NULL,
+ "Created DVI file: %s.", finfo->dvi_out.fname);
+ }
+ unlink(finfo->dvi_tmp.fname);
+ }
+ }
+ break;
+
+ case FMT_PS2PDF:
+ tmp_fd = xdvi_temp_fd(&(finfo->ps_out.fname)); /* this allocates finfo->ps_out.fname */
+ if (tmp_fd == -1) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL,
+ "Couldn't create temporary PS file for conversion to PDF: %s",
+ strerror(errno));
+ return;
+ }
+ else {
+ TRACE_GUI((stderr, "name of temporary PS file: |%s|", finfo->ps_out.fname));
+ }
+ dvips_exit_proc = dvips_ps2pdf; /* call ps2pdf conversion after dvips exited */
+ do_pdf = True;
+ /* fall through */
+ case FMT_PS:
+ if (pinfo->callback == check_marked) { /* want to print selected pages? */
+ ASSERT(finfo->dvi_tmp.fp != NULL, "Temporary file pointer musn't be NULL!");
+ ASSERT(finfo->dvi_tmp.fname != NULL, "Temporary filename musn't be NULL!");
+ select_pages(pinfo);
+ }
+ printlog_create("Xdvik: Saving", "Automatically close this window after file has been saved",
+ cb_dvips_close, cb_dvips_cancel, cb_dvips_destroy, cb_dvips_unkeep);
+
+ if ((argv = create_dvips_argv(pinfo, do_pdf, FILE_SAVE)) == NULL) {
+ /* something went *really* wrong; assume user has already been warned about it */
+ return;
+ }
+ fork_dvips(argv, pinfo, dvips_exit_proc);
+
+ /* dellocate argv */
+ for (i = 0; argv[i] != NULL; i++) {
+ free(argv[i]);
+ }
+ free(argv);
+
+ break;
+ case FMT_ISO_8859_1:
+ case FMT_UTF8:
+ if (search_extract_text(output_format, pinfo)) {
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ NULL,
+ "Created text file %s.", finfo->txt_out.fname);
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ NULL,
+ "Extracting text from DVI file failed!");
+ }
+ break;
+ case FMT_NONE:
+ break;
+ }
+}
+
+void
+internal_print(struct select_pages_info *pinfo)
+{
+ char **argv = NULL;
+ int i;
+
+ if (pinfo->callback == check_marked) { /* want to print selected pages? */
+ ASSERT(pinfo->finfo->dvi_tmp.fp != NULL, "Temporary file pointer musn't be NULL!");
+ ASSERT(pinfo->finfo->dvi_tmp.fname != NULL, "Temporary filename musn't be NULL!");
+ select_pages(pinfo);
+ }
+ printlog_create("Xdvik: Printing", "Automatically close this window when printing finishes",
+ cb_dvips_close, cb_dvips_cancel, cb_dvips_destroy, cb_dvips_unkeep);
+
+ if ((argv = create_dvips_argv(pinfo, False, FILE_PRINT)) == NULL) {
+ /* something went *really* wrong; assume user has already been warned about it */
+ return;
+ }
+
+ fork_dvips(argv, pinfo, dvips_exited);
+
+ /* dellocate argv */
+ for (i = 0; argv[i] != NULL; i++) {
+ free(argv[i]);
+ }
+ free(argv);
+}
diff --git a/Build/source/texk/xdvik/print-internal.h b/Build/source/texk/xdvik/print-internal.h
new file mode 100644
index 00000000000..4969c356396
--- /dev/null
+++ b/Build/source/texk/xdvik/print-internal.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * 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 ANY AUTHO 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.
+ */
+
+#ifndef PRINT_INTERNAL_H_
+#define PRINT_INTERNAL_H_
+
+#include "dvi-init.h"
+#include "print-dialog.h"
+
+typedef enum { FMT_PS, FMT_PS2PDF, FMT_DVI, FMT_ISO_8859_1, FMT_UTF8, FMT_NONE } outputFormatT;
+
+/* file IO help struct */
+struct file_IO {
+ FILE *fp;
+ char *fname;
+};
+
+/* collection of all file IOs used in printing/saving */
+struct file_info {
+ struct file_IO dvi_in;
+ struct file_IO dvi_tmp;
+ struct file_IO dvi_out;
+ struct file_IO ps_out;
+ struct file_IO pdf_out;
+ struct file_IO txt_out;
+};
+
+/* stacks for communication with selection routines */
+struct specials_stack_elem {
+ char *content; /* string content */
+};
+
+struct specials_stack {
+ size_t stack_len;
+ struct specials_stack_elem *items;
+};
+
+
+/* wrapper struct for all kinds of information about selected pages. */
+struct select_pages_info {
+ printOrSaveActionT act; /* whether we're printing or saving */
+ int from; /* lower bound of page range to be selected */
+ int to; /* upper bound of page range to be selected */
+ struct file_info *finfo; /* additional file info pointer */
+ /* callback function that says whether a page should be selected or not;
+ will be passed a pointer to the current struct select_pages_info,
+ and the current page */
+ Boolean (*callback)(struct select_pages_info *info, int page);
+ struct specials_stack warn_files; /* collect warnings about included files */
+ dviErrFlagT errflag; /* collect all kinds of errors that can happen while copying */
+};
+
+extern void internal_print(struct select_pages_info *pinfo);
+extern void internal_save(struct select_pages_info *pinfo,
+ outputFormatT output_format);
+
+#endif /* PRINT_INTERNAL_H_ */
+
diff --git a/Build/source/texk/xdvik/psdps.c b/Build/source/texk/xdvik/psdps.c
new file mode 100644
index 00000000000..a570a481f66
--- /dev/null
+++ b/Build/source/texk/xdvik/psdps.c
@@ -0,0 +1,858 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2004 Paul Vojta
+
+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.
+
+NOTES:
+ This code was originally written by Ricardo Telichevesky
+ (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
+ (lms@rle-vlsi-mit.edu).
+ It was largely influenced by similar code in the SeeTeX/XTeX
+ package by Dirk Grunwald (grunwald@colorado.edu).
+
+\*========================================================================*/
+
+#ifdef PS_DPS /* entire file */
+
+
+#include <setjmp.h>
+#include <signal.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <DPS/XDPSlib.h>
+#include <DPS/dpsXclient.h>
+#include <DPS/dpsexcept.h>
+#include <DPS/dpsclient.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#if defined(sun) || defined(__sun)
+#ifndef SUNHACK
+#define SUNHACK 1
+#endif
+#endif
+
+
+#include "dvi-init.h"
+#include "dvi-draw.h"
+#include "events.h"
+
+/*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ */
+#if !SUNHACK
+static char preamble[] =
+ "/xdvi$line 81 string def "
+ "/xdvi$run {{$error null ne {$error /newerror false put}if "
+ " currentfile cvx stopped "
+ " $error null eq {false} {$error /newerror get} ifelse and "
+ " {handleerror} if} stopped pop} def "
+ "/xdvi$dslen countdictstack def "
+ "{currentfile read not {exit} if 72 eq "
+ " {xdvi$run} "
+ " {/xdvi$sav save def xdvi$run "
+ " clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} "
+ " ifelse "
+ " {(%%xdvimark) currentfile xdvi$line {readline} stopped "
+ " {clear} {pop eq {exit} if} ifelse }loop "
+ " (xdvi$Ack\n) print flush "
+ "}loop\nH";
+#else /* SUNHACK */
+static char preamble[] =
+ "/xdvi$line 81 string def "
+ "/xdvi$run {{$error null ne {$error /newerror false put}if "
+ "currentfile cvx stopped "
+ "$error null eq {false} {$error /newerror get} ifelse and "
+ "{handleerror} if} stopped pop} def "
+ "/xdvi$dslen countdictstack def "
+ "/xdvi$ack {{(%%xdvimark) currentfile xdvi$line {readline} stopped "
+ " {clear} {pop eq {exit} if} ifelse }loop "
+ " (xdvi$Ack\n) print flush} bind def "
+ "errordict begin /interrupt{(xdvi$Int\n) print flush stop}bind def "
+ "end "
+ "{{currentfile read not {exit} if 72 eq "
+ " {xdvi$run} "
+ " {/xdvi$sav save def xdvi$run "
+ " clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} "
+ " ifelse "
+ " xdvi$ack "
+ " }loop "
+ "xdvi$ack "
+ "}loop\nH";
+#endif /* SUNHACK */
+
+extern const char psheader[];
+extern unsigned psheaderlen;
+
+
+/* global procedures (besides initDPS) */
+
+static void toggleDPS(int flag);
+static void destroyDPS(void);
+static void interruptDPS(void);
+static void endpageDPS(void);
+static void drawbeginDPS(int, int, const char *);
+static void drawbeginDPS_box(int, int, const char *);
+static void drawrawDPS(const char *);
+static void drawfileDPS(const char *, FILE *);
+static void drawendDPS(const char *);
+static void beginheaderDPS(void);
+static void endheaderDPS(void);
+static void newdocDPS(void);
+
+static struct psprocs dps_procs = {
+ /* toggle */ toggleDPS,
+ /* destroy */ destroyDPS,
+ /* interrupt */ interruptDPS,
+ /* endpage */ endpageDPS,
+ /* drawbegin */ drawbeginDPS,
+ /* drawraw */ drawrawDPS,
+ /* drawfile */ drawfileDPS,
+ /* drawend */ drawendDPS,
+ /* beginheader */ beginheaderDPS,
+ /* endheader */ endheaderDPS,
+ /* newdoc */ newdocDPS
+};
+
+#define DPS_MASK_NORMAL EV_GE_NEWPAGE
+#define DPS_MASK_HEADER EV_GE_PS_TOGGLE
+#define DPS_MASK_INIT (EV_GE_TERM | EV_PS_TOGGLE)
+
+static DPSContext DPS_ctx = NULL;
+static DPSSpace DPS_space = NULL;
+static int DPS_mag; /* magnification currently in use */
+static int DPS_shrink; /* shrink factor currently in use */
+static Boolean DPS_active; /* if we've started a page */
+static int DPS_pending; /* number of ack's we're expecting */
+static Boolean DPS_in_header; /* if we're sending a header */
+static Boolean DPS_in_doc; /* if we've sent header information */
+
+static int DPS_ev_mask = DPS_MASK_NORMAL; /* events for which we'll stop */
+
+
+#if 0
+static void DPSErrorProcHandler();
+#else
+#define DPSErrorProcHandler DPSDefaultErrorProc
+#endif
+
+
+static char ackstr[] = "xdvi$Ack\n";
+#if SUNHACK
+static char intstr[] = "xdvi$Int\n";
+static char intstr2[] = "xdvi$In2\n";
+#endif
+
+#define LINELEN 81
+#define BUFLEN (LINELEN + sizeof ackstr)
+static char line[BUFLEN + 1];
+static char *linepos = line;
+
+static void
+TextProc(DPSContext ctxt, char *buf, unsigned long count)
+{
+ int i;
+ char *p;
+ char *p0;
+
+ while (count > 0) {
+ i = line + BUFLEN - linepos;
+ if (i > count)
+ i = count;
+ (void)bcopy(buf, linepos, i);
+ linepos += i;
+ buf += i;
+ count -= i;
+ p0 = line;
+ for (;;) {
+ if (p0 >= linepos) {
+ linepos = line;
+ break;
+ }
+ p = memchr(p0, '\n', linepos - p0);
+ if (p == NULL) {
+ if (p0 != line) {
+ (void)bcopy(p0, line, linepos - p0);
+ linepos -= p0 - line;
+ }
+ else if (linepos == line + BUFLEN) {
+ char c;
+
+ c = line[LINELEN];
+ line[LINELEN] = '\0';
+ printf("DPS: %s\n", line);
+ line[LINELEN] = c;
+ linepos -= LINELEN;
+ (void)bcopy(line + LINELEN, line, linepos - line);
+ }
+ break;
+ }
+ if (p >= p0 + 8 && memcmp(p - 8, ackstr, 9) == 0) {
+ --DPS_pending;
+ if (DPS_pending == 0)
+ globals.ev.flags |= EV_ACK;
+ if (globals.debug & DBG_PS)
+ printf("Got DPS ack; %d pending.\n", DPS_pending);
+ ++p;
+ (void)bcopy(p, p - 9, linepos - p);
+ linepos -= 9;
+ continue;
+ }
+#if SUNHACK
+ if (p >= p0 + 8 && memcmp(p - 8, intstr, 9) == 0) {
+ if (globals.debug & DBG_PS)
+ puts("Got DPS int.");
+ ++p;
+ (void)bcopy(p, p - 9, linepos - p);
+ linepos -= 9;
+ globals.ev.flags |= EV_ACK;
+ continue;
+ }
+ if (p >= p0 + 8 && memcmp(p - 8, intstr2, 9) == 0) {
+ if (globals.debug & DBG_PS)
+ puts("Got DPS int 2.");
+ ++p;
+ (void)bcopy(p, p - 9, linepos - p);
+ linepos -= 9;
+ DPS_pending = 3;
+
+ continue;
+ }
+#endif /* SUNHACK */
+ *p = '\0';
+ printf("DPS: %s\n", p0);
+ p0 = p + 1;
+ }
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ waitack()
+
+ Arguments: none.
+
+ Returns: (void)
+
+ Description:
+ Waits until the requisite number of acknowledgements has been received from
+ the context.
+
++----------------------------------------------------------------------------*/
+
+#if SUNHACK
+static void DPS_alarm ARGS((struct xtimer *));
+
+static struct xtimer DPS_timer = {NULL, {0, 0}, DPS_alarm};
+static Boolean DPS_timer_set;
+
+static void DPS_alarm(struct xtimer *arg)
+{
+ if (globals.debug & DBG_PS)
+ puts("Received DPS alarm");
+
+ DPS_timer_set = False;
+ globals.ev.flags |= EV_ACK;
+}
+#endif /* SUNHACK */
+
+static void
+waitack(void)
+{
+ if (DPS_pending <= 0)
+ return;
+
+ DPSFlushContext(DPS_ctx);
+ if (read_events(DPS_ev_mask | EV_ACK) & EV_ACK) {
+ globals.ev.flags &= ~EV_ACK;
+ return;
+ }
+
+ if (globals.debug & DBG_PS)
+ printf("Interrupting DPS in waitack(); code is now %d %x\n",
+ XDPSGetContextStatus(DPS_ctx), globals.ev.flags);
+
+ DPS_active = DPS_in_header = DPS_in_doc = False;
+ DPS_ev_mask = DPS_MASK_NORMAL;
+
+ /*
+ * I would really like to use DPSInterruptContext() here, but (at least
+ * on an RS6000) I can't get it to work.
+ */
+
+#if SUNHACK
+
+ /*
+ * On the other hand, under OpenWindows 3.3 (at least), destroying and
+ * re-creating contexts has a nasty habit of crashing the server.
+ */
+
+ DPS_pending = 32767;
+ DPSInterruptContext(DPS_ctx);
+ DPSFlushContext(DPS_ctx);
+ (void) read_events(EV_GE_TERM | EV_ACK);
+ globals.ev.flags &= ~EV_ACK;
+
+ XSync(DISP, False);
+ DPSPrintf(DPS_ctx, " stop\n%%%%xdvimark\n stop\n%%%%xdvimark\n");
+ DPSPrintf(DPS_ctx, " (xdvi$In2\n) print flush stop\n%%%%xdvimark\n");
+ DPSPrintf(DPS_ctx, " stop\n%%%%xdvimark\n stop\n%%%%xdvimark\n");
+ DPSFlushContext(DPS_ctx);
+
+ if (globals.debug & DBG_PS)
+ puts("Setting DPS timer");
+
+ DPS_timer_set = True;
+ set_timer(&DPS_timer, 500);
+ (void) read_events(EV_GE_TERM | EV_ACK);
+ globals.ev.flags &= ~EV_ACK;
+
+ if (DPS_pending <= 0) {
+ if (DPS_timer_set) {
+ cancel_timer(&DPS_timer);
+ }
+
+ return;
+ }
+
+ /*
+ * However, under Solaris 2.6 (at least), sometimes interrupting the
+ * context leaves it in an uncommunicative state, so destruction
+ * is the only alternative.
+ */
+
+ if (globals.debug & DBG_PS)
+ puts("Plan B: Destroying DPS context");
+
+#endif /* SUNHACK */
+
+ DPSDestroyContext(DPS_ctx);
+ DPS_ctx = NULL;
+ DPS_pending = 0;
+}
+
+
+/*---------------------------------------------------------------------------*
+ initDPS()
+
+ Arguments: (none)
+ Returns: (void)
+ Side-Effects: DPS_ctx may be set as well as other static variables.
+
+ Description:
+ Initializes variables from the application main loop. Checks to see if
+ a connection to the DPS server can be opened.
+
++----------------------------------------------------------------------------*/
+
+static int
+get_shift(Pixel mask)
+{
+ int k;
+
+ for (k = 0; (mask & 1) == 0; ++k)
+ mask >>= 1;
+ return k;
+}
+
+Boolean initDPS(void)
+{
+
+ /* Try to create a context */
+
+#if GREY
+
+ if (G_colormap == DefaultColormapOfScreen(SCRN))
+ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, globals.gc.copy, 0, 0,
+ TextProc, DPSDefaultErrorProc, NULL);
+ else {
+ static XStandardColormap *ccube = NULL;
+ static XStandardColormap *grayramp = NULL;
+ int shift;
+
+ if (grayramp == NULL) {
+ grayramp = XAllocStandardColormap();
+ if (grayramp == NULL)
+ return False;
+ }
+
+ if (ccube == NULL) {
+ ccube = XAllocStandardColormap();
+ if (ccube == NULL)
+ return False;
+ }
+
+ shift = get_shift(G_visual->red_mask);
+ ccube->red_max = G_visual->red_mask >> shift;
+ ccube->red_mult = 1 << shift;
+
+ shift = get_shift(G_visual->green_mask);
+ ccube->green_max = G_visual->green_mask >> shift;
+ ccube->green_mult = 1 << shift;
+
+ shift = get_shift(G_visual->blue_mask);
+ ccube->blue_max = G_visual->blue_mask >> shift;
+ ccube->blue_mult = 1 << shift;
+
+ grayramp->red_max = ccube->red_max & ccube->green_max & ccube->blue_max;
+ grayramp->red_mult = ccube->red_mult + ccube->green_mult
+ + ccube->blue_mult;
+
+ ccube->colormap = grayramp->colormap = G_colormap;
+ ccube->visualid = grayramp->visualid = G_visual->visualid;
+
+ DPS_ctx = XDPSCreateContext(DISP, mane.win, globals.gc.copy, 0, 0,
+ 0, grayramp, ccube,
+ /* actual */
+ (ccube->red_max + 1) * (ccube->green_max +
+ 1) *
+ (ccube->blue_max + 1), TextProc,
+ DPSDefaultErrorProc, NULL);
+ }
+
+#else /* not GREY */
+
+ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, globals.gc.copy, 0, 0,
+ TextProc, DPSDefaultErrorProc, NULL);
+
+#endif /* not GREY */
+
+ if (DPS_ctx == NULL)
+ return False;
+
+ DPS_mag = DPS_shrink = -1;
+ DPS_active = False;
+ DPS_pending = 1;
+
+ DPS_space = DPSSpaceFromContext(DPS_ctx);
+ DPSWritePostScript(DPS_ctx, preamble, (sizeof preamble) - 1);
+ DPSWritePostScript(DPS_ctx, (char *)psheader, psheaderlen);
+ DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n");
+ DPSFlushContext(DPS_ctx);
+
+ psp = dps_procs;
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ toggleDPS(int flag)
+
+ Arguments: flag for toggling PostScript
+ Returns: (void)
+ Side-Effects: psp.drawbegin is changed.
+
+ Description:
+ Used to toggle the rendering of PostScript by the DPS server
+ This routine may be called from within read_events().
+
++----------------------------------------------------------------------------*/
+
+static void
+toggleDPS(int flag)
+{
+ if (globals.debug & DBG_PS)
+ Puts("Toggling DPS to %d", flag);
+
+ switch (flag) {
+ case 0:
+ psp.drawbegin = drawbegin_none;
+ break;
+ case 1:
+ psp.drawbegin = drawbeginDPS;
+ break;
+ default:
+ psp.drawbegin = drawbeginDPS_box;
+ break;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ destroyDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the context is nulled out and destroyed.
+
+ Description:
+ Close the connection to the DPS server; used when rendering is terminated
+ in any way.
+
++----------------------------------------------------------------------------*/
+
+static void
+destroyDPS(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Calling destroyDPS()");
+ if (linepos > line) {
+ *linepos = '\0';
+ printf("DPS: %s\n", line);
+ }
+ if (DPS_space != NULL)
+ DPSDestroySpace(DPS_space);
+ psp = no_ps_procs;
+ scanned_page = scanned_page_ps = scanned_page_reset;
+}
+
+
+/*---------------------------------------------------------------------------*
+ interruptDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the context may be nulled out and destroyed.
+
+ Description:
+ Close the connection to the DPS server; used when rendering is terminated
+ because of an interruption in the viewing of the current page.
+
++----------------------------------------------------------------------------*/
+
+static void
+interruptDPS(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running interruptDPS()");
+
+ if (DPS_pending <= 0)
+ return; /* nothing to do */
+
+ if (DPS_active) {
+ DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
+ DPS_active = False;
+ }
+
+ waitack();
+}
+
+
+/*---------------------------------------------------------------------------*
+ endpageDPS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the DPS_active variable is cleared.
+
+ Description:
+ Should be called at the end of a page to end this chunk for the DPS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+endpageDPS(void)
+{
+ if (DPS_active) {
+ if (globals.debug & DBG_PS)
+ puts("Endpage sent to context");
+ DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
+ DPS_active = False;
+ waitack();
+ }
+}
+
+
+/*
+ * checkDPS - Check that the DPS interpreter is still running.
+ * Return True for success, False for failure.
+ */
+
+static Boolean
+checkDPS(void)
+{
+ /* static char faulty_display_vs[]
+ * ="DECWINDOWS DigitalEquipmentCorporation UWS4.2LA"; */
+
+ if (DPS_ctx == NULL) {
+ DPS_ctx = XDPSCreateSimpleContext(DISP, mane.win, globals.gc.copy, 0, 0,
+ TextProc, DPSErrorProcHandler, DPS_space);
+ if (DPS_ctx == NULL) {
+ psp = no_ps_procs;
+ draw_bbox();
+ return False;
+ }
+ DPSWritePostScript(DPS_ctx, preamble, (sizeof preamble) - 1);
+ /* it already has psheader */
+ DPSPrintf(DPS_ctx, "matrix setmatrix stop\n%%%%xdvimark\n");
+ DPS_mag = DPS_shrink = -1;
+ DPS_active = False;
+ DPS_pending = 1;
+ }
+
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawbeginDPS ()
+
+ Arguments: xul, yul - coordinates of the upper left corner of the figure
+ cp - string with the bounding box line data
+ Returns: (void)
+ Side-Effects: DPS_ctx is set is set and connection to DPS server is
+ opened.
+
+ Description:
+ Opens a connection to the DPS server and send in the preamble and the
+ bounding box information after correctly computing resolution factors.
+ In case no rendering is to be done, outlines the figure.
+ An outline is also generated whenever the a context cannot be allocated
+
++----------------------------------------------------------------------------*/
+
+static void
+drawbeginDPS(int xul, int yul, const char *cp)
+{
+ if (globals.debug & DBG_PS)
+ printf("Begin drawing at xul= %d, yul= %d.\n", xul, yul);
+
+ if (!checkDPS()) return;
+
+ if (!DPS_active) {
+ /* send initialization to context */
+ if (magnification != DPS_mag) {
+ DPSPrintf(DPS_ctx, "H TeXDict begin /DVImag %d 1000 div def "
+ "end stop\n%%%%xdvimark\n", DPS_mag = magnification);
+ ++DPS_pending;
+ }
+ if (mane.shrinkfactor != DPS_shrink) {
+ DPSPrintf(DPS_ctx, "H TeXDict begin %d %d div dup "
+ "/Resolution X /VResolution X "
+ "end stop\n%%%%xdvimark\n", resource.pixels_per_inch, DPS_shrink = mane.shrinkfactor);
+ ++DPS_pending;
+ }
+ DPSPrintf(DPS_ctx, " TeXDict begin\n");
+ DPS_active = True;
+ ++DPS_pending;
+ }
+
+ if (globals.ev.flags & DPS_MASK_NORMAL)
+ longjmp(globals.ev.canit, 1);
+
+ DPSPrintf(DPS_ctx, "%d %d moveto\n", xul, yul);
+ DPSPrintf(DPS_ctx, "%s\n", cp);
+}
+
+static void
+drawbeginDPS_box(int xul, int yul, const char *cp)
+{
+ drawbeginDPS(int xul, int yul, const char *cp);
+ draw_bbox();
+}
+
+/*---------------------------------------------------------------------------*
+
+ drawrawDPS()
+
+ Arguments: cp - the raw string to be sent to the postscript interpreter
+ Returns: (void)
+ Side-Effects: (none)
+
+ Description:
+ If there is a valid postscript context, just send the string to the
+ interpreter, else leave.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawrawDPS(const char *cp)
+{
+ if (!DPS_active || (globals.ev.flags & DPS_ev_mask))
+ return;
+
+ if (globals.debug & DBG_PS)
+ printf("Sending raw PS to context: %s\n", cp);
+
+ DPSPrintf(DPS_ctx, "%s\n", cp);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawfileDPS()
+
+ Arguments: cp - string with the postscript file pathname
+ psfile - opened file pointer
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Postscript file containing the figure is opened and sent to the DPS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawfileDPS(const char *cp, FILE *psfile)
+{
+ char buffer[1025];
+ int blen;
+
+ if (DPS_active && !(read_events(EV_NOWAIT) & DPS_ev_mask)) {
+ if (globals.debug & DBG_PS)
+ printf("sending file %s\n", cp);
+ for (;;) {
+ blen = fread(buffer, sizeof(char), 1024, psfile);
+ if (blen == 0) break;
+ DPSWritePostScript(DPS_ctx, buffer, blen);
+ if (read_events(EV_NOWAIT) & DPS_ev_mask) {
+ /* ||| stop at a good place */
+ if (globals.debug & DBG_PS)
+ puts("Interrupting in drawfileDPS");
+ break;
+ }
+ }
+ }
+
+ fclose(psfile);
+
+ if (globals.ev.flags & DPS_ev_mask)
+ longjmp(globals.ev.canit, 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawendDPS()
+
+ Arguments: cp - string with indication of the end of the special
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Sends the indication of end of the figure PostScript code.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawendDPS(const char *cp)
+{
+ if (!DPS_active || (globals.ev.flags & DPS_MASK_NORMAL))
+ return;
+
+ if (globals.debug & DBG_PS)
+ printf("End PS: %s\n", cp);
+ DPSPrintf(DPS_ctx, "%s\n", cp);
+}
+
+
+/*---------------------------------------------------------------------------*
+ beginheaderDPS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+beginheaderDPS(void)
+{
+ if (globals.ev.flags & DPS_MASK_HEADER || !checkDPS())
+ return;
+
+ if (globals.debug & DBG_PS)
+ puts("Running beginheaderDPS()");
+
+ if (DPS_active) {
+ if (!DPS_in_header)
+ XDVI_FATAL((stderr, "Internal error in beginheaderDPS()."));
+ return;
+ }
+
+ DPS_in_header = True;
+ DPS_ev_mask = DPS_MASK_HEADER;
+
+ if (DPS_in_doc)
+ DPSPrintf(DPS_ctx, "H");
+ else {
+ DPSPrintf(DPS_ctx, "Hsave /xdvi$doc exch def\n");
+ DPS_in_doc = True;
+ }
+ DPS_active = True;
+ ++DPS_pending;
+}
+
+
+/*---------------------------------------------------------------------------*
+ endheaderDPS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+endheaderDPS(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running endheaderDPS()");
+
+ if (DPS_active) {
+ DPSPrintf(DPS_ctx, "stop\n%%%%xdvimark\n");
+ DPS_active = False;
+ waitack();
+ DPS_in_header = False;
+ DPS_ev_mask = DPS_MASK_NORMAL;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ newdocDPS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Clears out headers stored from the previous document.
+
++----------------------------------------------------------------------------*/
+
+static void
+newdocDPS(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running newdocDPS()");
+
+ if (DPS_in_doc) {
+ DPSPrintf(DPS_ctx, "H xdvi$doc restore stop\n%%%%xdvimark\n");
+ ++DPS_pending;
+ DPS_mag = DPS_shrink = -1;
+ DPS_in_doc = False;
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* PS_DPS */
diff --git a/Build/source/texk/xdvik/psdps.h b/Build/source/texk/xdvik/psdps.h
new file mode 100644
index 00000000000..0d2be7a72e2
--- /dev/null
+++ b/Build/source/texk/xdvik/psdps.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef PSDPS_H_
+#define PSDPS_H_
+
+extern Boolean initDPS(void);
+
+#endif /* PSDPS_H_ */
diff --git a/Build/source/texk/xdvik/psgs.c b/Build/source/texk/xdvik/psgs.c
new file mode 100644
index 00000000000..e0d902848a4
--- /dev/null
+++ b/Build/source/texk/xdvik/psgs.c
@@ -0,0 +1,1090 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2004 Paul Vojta
+
+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.
+
+\*========================================================================*/
+
+#ifdef PS_GS /* entire file */
+
+
+#include <setjmp.h>
+#include <X11/Xatom.h>
+#include <sys/time.h> /* for timeval */
+
+#include <signal.h>
+
+/* Condition for retrying a write */
+#include <errno.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "psgs.h"
+
+#include "kpathsea/c-pathmx.h"
+#include "dvi-init.h"
+#include "dvi-draw.h"
+#include "events.h"
+#include "statusline.h"
+#include "special.h"
+#include "util.h"
+
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef EWOULDBLOCK
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+# else
+# define AGAIN_CONDITION (errno == EWOULDBLOCK)
+# endif
+#else
+# ifdef EAGAIN
+# define AGAIN_CONDITION (errno == EAGAIN)
+# endif
+#endif
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+#ifdef MOTIF
+# include <Xm/Xm.h>
+#endif
+
+extern const char psheader[];
+extern unsigned psheaderlen;
+
+Boolean gs_postpone_prescan = False;
+
+/* global procedures (besides initGS) */
+
+static void toggle_gs(int flag);
+static void destroy_gs(void);
+static void interrupt_gs(void);
+static void endpage_gs(void);
+static void drawbegin_gs(int, int, const char *);
+static void drawbegin_gs_box(int, int, const char *);
+void drawraw_gs(const char *);
+static void drawfile_gs(const char *, FILE *);
+static void drawend_gs(const char *);
+static void beginheader_gs(void);
+static void endheader_gs(void);
+static void newdoc_gs(void);
+
+static struct psprocs gs_procs = {
+ /* toggle */ toggle_gs,
+ /* destroy */ destroy_gs,
+ /* interrupt */ interrupt_gs,
+ /* endpage */ endpage_gs,
+ /* drawbegin */ drawbegin_gs,
+ /* drawraw */ drawraw_gs,
+ /* drawfile */ drawfile_gs,
+ /* drawend */ drawend_gs,
+ /* beginheader */ beginheader_gs,
+ /* endheader */ endheader_gs,
+ /* newdoc */ newdoc_gs
+};
+
+static int std_io[2];
+Pixmap bpixmap;
+
+#define GS_fd (std_io[0])
+
+ /* some arguments are filled in later */
+static char arg4[] = "-dDEVICEWIDTH=xxxxxxxxxx";
+static char arg5[] = "-dDEVICEHEIGHT=xxxxxxxxxx";
+
+static const char *argv[] = {
+ NULL, NULL, "-dNOPAUSE", "-q", arg4, arg5,
+ "-dDEVICEXRESOLUTION=72",
+ "-dDEVICEYRESOLUTION=72",
+ "-dNOSAFER", "-dNOEPS", NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static unsigned int GS_page_w; /* how big our current page is */
+static unsigned int GS_page_h;
+static Boolean GS_alpha; /* remember if we are using the alpha driver */
+static unsigned long GS_mag; /* magnification currently in use */
+static int GS_shrink; /* shrink factor currently in use */
+static Boolean GS_active; /* if we've started a page yet */
+static int GS_pending; /* number of ack's we're expecting */
+static char GS_outb[257]; /* circular output buffer */
+static char *GS_outb_in; /* next position in output buffer */
+static char *GS_outb_out; /* next byte to come out of buffer */
+#define GS_outb_limit (GS_outb + sizeof GS_outb) /* last+1 byte */
+static int GS_write_ack; /* flag to set when done writing */
+static Boolean GS_in_header; /* if we're sending a header */
+static Boolean GS_in_doc; /* if we've sent header information */
+static int GS_ev_mask; /* events for which we'll stop */
+static int GS_die_ack = 0; /* flags to set when GS dies */
+static Boolean GS_timer_set; /* if there's a timer set */
+static Boolean GS_old; /* if we're using gs 2.xx */
+
+#define GS_MASK_NORMAL EV_GE_NEWPAGE
+#define GS_MASK_HEADER EV_GE_PS_TOGGLE
+#define GS_MASK_INIT (EV_GE_TERM | EV_PS_TOGGLE)
+
+static Atom gs_atom;
+static Atom gs_colors_atom;
+
+#define Landscape 90
+
+#define LINELEN 81
+static char line[LINELEN + 1];
+static char *linepos = line;
+static char ackstr[] = "\347\310\376";
+static char oldstr[] = "\347\310\375";
+
+static void gs_died(int, struct xchild *);
+
+static char *read_from_gs(int);
+static void write_to_gs(int);
+
+static struct xio gs_xio = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_gs, write_to_gs
+};
+
+static struct xchild gs_child = { NULL, 0, True, NULL, NULL, NULL, gs_died };
+#define GS_pid (gs_child.pid)
+
+/* It seems that XtTimers don't work reliably with xdvi's event treatment;
+ so use custom timers for the time being. Search for TIMER_PROBLEM_FIXED
+ to locate the relevant code parts.
+*/
+
+#if TIMER_PROBLEM_FIXED
+static XtIntervalId gs_timeout_id = 0;
+static void gs_timer_proc(XtPointer client_data, XtIntervalId * id);
+static struct xtimer gs_timer = {NULL, {0, 0}, gs_timer_proc};
+#else
+static void gs_alarm(struct xtimer *timer);
+static struct xtimer gs_timer = {NULL, {0, 0}, XTM_DEFAULT, gs_alarm
+#if XDVI_XT_TIMER_HACK
+ , NULL, NULL
+#endif
+};
+#endif
+
+
+static void
+showto(char *q)
+{
+ char *p = line;
+ char *p1;
+
+ while (p < q) {
+ p1 = memchr(p, '\n', q - p);
+ if (p1 == NULL)
+ p1 = q;
+ *p1 = '\0';
+ printf("gs: %s\n", p);
+ p = p1 + 1;
+ }
+}
+
+static char *
+read_from_gs(int fd)
+{
+ int bytes;
+ char *line_end = NULL;
+ char *p;
+
+ for (;;) {
+
+ bytes = read(fd, linepos, line + LINELEN - linepos);
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvik: read_from_gs");
+ break;
+ }
+ line_end = linepos + bytes;
+
+ if (bytes == 0) {
+ if (GS_pid != 0)
+ XDVI_WARNING((stderr, "Read_from_gs returned 0 bytes"));
+ break;
+ }
+
+ /* Check for ack strings */
+ for (p = line; p < line_end - 2; ++p) {
+ p = memchr(p, '\347', line_end - p - 2);
+ if (p == NULL) break;
+ if (memcmp(p, ackstr, 3) == 0) {
+ --GS_pending;
+ if (GS_pending == 0)
+ globals.ev.flags |= EV_ACK;
+ if (globals.debug & DBG_PS)
+ printf("Got GS ack; %d pending.\n", GS_pending);
+ } else if (memcmp(p, oldstr, 3) == 0) {
+ if (globals.debug & DBG_PS)
+ puts("Using old GS version.");
+ GS_old = True;
+ } else
+ continue;
+
+ showto(p);
+ p += 3;
+ memmove(line, p, line_end - p);
+ line_end -= p - line;
+ linepos = p = line;
+ --p;
+ }
+ *line_end = '\0';
+ p = rindex(linepos, '\n');
+ if (p != NULL) {
+ ++p;
+ showto(p);
+ memmove(line, p, line_end - p);
+ line_end -= p - line;
+ }
+ linepos = line_end;
+ /*
+ * Normally we'd hold text until a newline character, but the
+ * buffer is full. So we flush it, being careful not to cut up an
+ * ack string.
+ */
+ if (linepos >= line + LINELEN) {
+ p = line + LINELEN;
+ if ((*--p != '\347' && *--p != '\347' && *--p != '\347')
+ || (memcmp(p, ackstr, line + LINELEN - p) != 0
+ && memcmp(p, oldstr, line + LINELEN - p) != 0))
+ p = line + LINELEN;
+ *p = '\0';
+ printf("gs: %s\n", line);
+ *p = '\347';
+ linepos = line;
+ while (p < line + LINELEN)
+ *linepos++ = *p++;
+ }
+ }
+ return line_end; /* dummy */
+}
+
+static void
+write_to_gs(int fd)
+{
+ char *send_end;
+ int bytes;
+
+ UNUSED(fd);
+
+ for (;;) {
+ send_end = GS_outb_in;
+ if (send_end < GS_outb_out)
+ send_end = GS_outb_limit;
+ bytes = write(GS_fd, GS_outb_out, send_end - GS_outb_out);
+
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvik: write_to_gs");
+ break;
+ }
+
+ GS_outb_out += bytes;
+ if (GS_outb_out == GS_outb_limit)
+ GS_outb_out = GS_outb;
+ if (GS_outb_out == GS_outb_in) { /* if buffer is empty */
+ gs_xio.xio_events = XIO_IN;
+#if HAVE_POLL
+ if (gs_xio.pfd != NULL) /* write_to_gs is called directly */
+ gs_xio.pfd->events = XIO_IN;
+#endif
+ break;
+ }
+ }
+ globals.ev.flags |= GS_write_ack;
+ GS_write_ack = 0;
+}
+
+/*
+ * Main routine for writing to the GS interpreter.
+ */
+
+static void
+gs_send(const char *cp, size_t len)
+{
+ const char *cp_end = cp + len;
+ char *send_end;
+ size_t bytes;
+ char *old_out;
+ Boolean interrupting;
+
+ if (GS_pid == 0 || (globals.ev.flags & GS_ev_mask))
+ return;
+
+ /*
+ * Because cp might reside on the stack, don't return until we've
+ * copied all of it to our circular output buffer.
+ * Note that GS_outb_out == GS_outb_in means that the buffer is empty.
+ */
+
+ GS_timer_set = interrupting = False;
+ for (;;) {
+ send_end = GS_outb_out;
+ if (send_end == GS_outb)
+ send_end = GS_outb_limit;
+ --send_end;
+ if (send_end < GS_outb_in)
+ send_end = GS_outb_limit;
+ bytes = send_end - GS_outb_in;
+ if (bytes > 0) {
+ if (bytes >= (unsigned)(cp_end - cp))
+ bytes = cp_end - cp;
+ memcpy(GS_outb_in, cp, bytes);
+ cp += bytes;
+ GS_outb_in += bytes;
+ if (GS_outb_in == GS_outb_limit)
+ GS_outb_in = GS_outb;
+ if (cp < cp_end)
+ continue;
+ }
+
+ /* The buffer is now full --or-- we've run out of data */
+ old_out = GS_outb_out;
+ if (!(gs_xio.xio_events & XIO_OUT)) { /* restart output */
+ gs_xio.xio_events = XIO_IN | XIO_OUT;
+#if HAVE_POLL
+ if (gs_xio.pfd != NULL)
+ gs_xio.pfd->events = POLLIN | POLLOUT;
+#endif
+ write_to_gs(GS_fd);
+ if (GS_outb_out != old_out) {
+ if (cp == cp_end)
+ break;
+ else
+ continue;
+ }
+ }
+
+ if (cp == cp_end)
+ break;
+
+ GS_die_ack = GS_write_ack = EV_ACK;
+ for (;;) { /* loop because there may be stray ACKs */
+ if (!interrupting) {
+ (void) read_events(GS_ev_mask | EV_ACK);
+ globals.ev.flags &= ~EV_ACK;
+
+ if (GS_pid == 0) { /* if GS died */
+ GS_die_ack = 0;
+ return;
+ }
+
+ if (GS_outb_out != old_out) /* if more room in buffer */
+ break;
+
+ if (globals.ev.flags & GS_ev_mask) { /* if a serious event */
+ if (globals.debug & DBG_PS)
+ puts("Setting timeout in gs_send()");
+
+ set_timer(&gs_timer, resource.gs_timeout);
+ GS_timer_set = interrupting = True;
+ }
+ }
+ else {
+ (void) read_events(EV_GE_TERM | EV_PS_TOGGLE | EV_ACK);
+ globals.ev.flags &= ~EV_ACK;
+
+ if (GS_outb_out != old_out) /* if more room in buffer */
+ break;
+
+ if (GS_timer_set) /* if timer still set */
+ cancel_timer(&gs_timer);
+
+ destroy_gs();
+ GS_die_ack = 0;
+ return;
+ }
+ }
+ }
+
+ if (GS_timer_set) /* if timer still set */
+ cancel_timer(&gs_timer);
+
+ GS_die_ack = GS_write_ack = 0;
+}
+
+static void
+#if TIMER_PROBLEM_FIXED
+gs_timer_proc(XtPointer client_data, XtIntervalId * id)
+#else
+gs_alarm(struct xtimer *timer)
+#endif
+{
+ UNUSED(timer);
+
+ if (globals.debug & DBG_PS)
+ puts("GS timeout expired");
+
+ globals.ev.flags |= EV_ACK;
+ GS_timer_set = False;
+#if TIMER_PROBLEM_FIXED
+ gs_timeout_id = 0;
+#endif
+}
+
+/*
+ * Wait for acknowledgement from GS.
+ */
+
+static void
+waitack(void)
+{
+ if (GS_pending == 0) {
+ globals.ev.flags &= ~EV_ACK;
+ return;
+ }
+
+ GS_die_ack = EV_ACK;
+
+ for (;;) { /* loop because there might be stray ACKs. */
+/* fprintf(stderr, "looping for stray ACKs, page %d\n", current_page); */
+ (void) read_events(EV_GE_ACK);
+ globals.ev.flags &= ~EV_ACK;
+
+ if (GS_pending == 0) {
+ GS_die_ack = 0;
+ return;
+ }
+ if (globals.ev.flags & EV_GE_ACK)
+ break;
+ }
+
+ if (globals.debug & DBG_PS)
+ puts("Setting timeout in waitack()");
+
+#if TIMER_PROBLEM_FIXED
+ if (gs_timeout_id)
+ XtRemoveTimeOut(gs_timeout_id);
+ gs_timeout_id = XtAppAddTimeOut(app, resource.gs_timeout,
+ gs_timer_proc, (XtPointer) NULL);
+#else
+ set_timer(&gs_timer, resource.gs_timeout);
+#endif
+ GS_timer_set = True;
+
+ (void) read_events(EV_GE_TERM | EV_PS_TOGGLE | EV_ACK);
+ globals.ev.flags &= ~EV_ACK;
+
+ if (GS_timer_set) {
+#if TIMER_PROBLEM_FIXED
+ XtRemoveTimeOut(gs_timeout_id);
+ gs_timeout_id = 0;
+#else
+ cancel_timer(&gs_timer);
+#endif
+ }
+ GS_die_ack = 0;
+
+ if (GS_pending > 0)
+ destroy_gs();
+}
+
+
+/*
+ * Fork a process to run ghostscript. This is done using the
+ * x11 device (which needs to be compiled in). Normally the x11
+ * device uses ClientMessage events to communicate with the calling
+ * program, but we don't do this. The reason for using the ClientMessage
+ * events is that otherwise ghostview doesn't know when a non-conforming
+ * postscript program calls showpage. That doesn't affect us here,
+ * since in fact we disable showpage.
+ *
+ * SAFER mode is handled by providing both the -dNOSAFER and -dSAFER
+ * options. Ghostscript versions 7.04 and earlier ignore -dNOSAFER and use
+ * -dSAFER; the code in strsafe is ignored since .locksafe is not present.
+ * In versions 7.04 and higher, -dNOSAFER overrides -dSAFER; SAFER mode is
+ * optionally turned on by sending the strsafe string. It is possible in some
+ * versions of gs prior to 7.04 to use -dDELAYSAFER instead of -dNOSAFER, but
+ * there's no point in doing that since .locksafe is not defined in those
+ * versions. I don't know where 7.03 fits in on all of this (but it works with
+ * that version as well).
+ */
+
+Boolean
+initGS(void)
+{
+ char buf[100];
+ static Boolean did_putenv = False;
+ /*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ * `execute' is unique to ghostscript.
+ */
+
+ static const char strsafe[] =
+ "{ << /PermitFileReading [ (*) ] /PermitFileWriting [ ] /PermitFileControl [ ] "
+ ">> setuserparams .locksafe "
+ "} stopped pop\n";
+ static const char str1[] =
+ "/xdvi$run {$error /newerror false put {currentfile cvx execute} stopped pop} "
+ "def "
+ "/xdvi$ack (\347\310\376) def "
+ "/xdvi$dslen countdictstack def "
+ "{currentfile read pop 72 eq "
+ "{xdvi$run} "
+ "{/xdvi$sav save def xdvi$run "
+ "clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} "
+ "ifelse "
+ "{(%%xdvimark) currentfile =string {readline} stopped "
+ "{clear} {pop eq {exit} if} ifelse }loop "
+ "flushpage xdvi$ack print flush "
+ "}loop\nH";
+
+ static const char str2[] =
+ "[0 1 1 0 0 0] concat\n"
+ "revision 300 lt{(\347\310\375) print flush}if\n"
+ "stop\n%%xdvimark\n";
+
+ /*
+ * If we're prescanning *before* setting up the widgets (to get the
+ * page size, for example), then postpone starting up ghostscript.
+ */
+ if (mane.win == (Window)0) {
+ if (globals.debug & DBG_PS)
+ puts("Hit PS header in early prescan; postponing.");
+ psp = no_ps_procs;
+ gs_postpone_prescan = True;
+ return True;
+ }
+
+ if (globals.debug & DBG_PS)
+ puts("Running initGS ...");
+
+ gs_atom = XInternAtom(DISP, "GHOSTVIEW", False);
+ /* send bpixmap, orientation, bbox (in pixels), and h & v resolution */
+ sprintf(buf, "%ld %d 0 0 %u %u 72 72",
+ bpixmap, /* bpixmap */
+ Landscape, /* orientation */
+ GS_page_h = globals.page.h, GS_page_w = globals.page.w);
+
+ XChangeProperty(DISP, mane.win, gs_atom, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)buf, strlen(buf));
+ GS_alpha = resource.gs_alpha;
+
+ gs_colors_atom = XInternAtom(DISP, "GHOSTVIEW_COLORS", False);
+ sprintf(buf, "%s %ld %ld", resource.gs_palette,
+ color_data[0].pixel, color_data[1].pixel);
+
+ XChangeProperty(DISP, mane.win, gs_colors_atom, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)buf, strlen(buf));
+
+ if (!did_putenv) {
+ sprintf(buf, "%ld", mane.win);
+ xputenv("GHOSTVIEW", buf);
+ did_putenv = True;
+ }
+
+ XSync(DISP, False); /* update the window */
+
+ if (xpipe(std_io) != 0) {
+ perror("[xdvik] pipe");
+ return False;
+ }
+ fflush(stderr); /* to avoid double flushing */
+ GS_pid = vfork();
+ if (GS_pid == 0) { /* child */
+ const char **argvp = argv + 10;
+
+ argv[1] = resource.gs_alpha ? "-sDEVICE=x11alpha" : "-sDEVICE=x11";
+ sprintf(arg4 + 14, "%u", GS_page_w);
+ sprintf(arg5 + 15, "%u", GS_page_h);
+ if (resource.gs_safer)
+ *argvp++ = "-dSAFER";
+
+#if 0
+ if (resource.gs_alpha) {
+ *argvp++ = "-dGraphicsAlphaBits=4";
+ *argvp++ = "-dTextAlphaBits=4";
+ *argvp++ = "-dMaxBitmap=0";
+ }
+#endif
+
+ *argvp = "-";
+ (void) close(std_io[0]);
+ (void) dup2(std_io[1], 0);
+ (void) dup2(std_io[1], 1);
+ (void) dup2(std_io[1], 2);
+ (void) close(std_io[1]);
+
+ (void)execvp(argv[0] = resource.gs_path, (char *const *)argv);
+ /*TODO: use fork_process here?? */
+ XDVI_ERROR((stderr, "Execvp of %s failed: %s", argv[0], strerror(errno)));
+ _exit(EXIT_FAILURE);
+ }
+
+ (void)close(std_io[1]);
+
+ if (GS_pid == -1) { /* error */
+ GS_pid = 0;
+ perror("[xdvik] vfork");
+ (void)close(GS_fd);
+
+ return False;
+ }
+
+ prep_fd(GS_fd, True); /* Set file descriptor for non-blocking I/O */
+
+ gs_child.name = xstrdup("gs");
+ gs_child.io = &gs_xio;
+ set_chld(&gs_child);
+
+ psp = gs_procs;
+ GS_active = False;
+ GS_in_header = True;
+ GS_pending = 1;
+ GS_mag = GS_shrink = -1;
+ gs_xio.fd = GS_fd;
+ gs_xio.xio_events = XIO_IN;
+ GS_write_ack = 0;
+ GS_outb_in = GS_outb_out = GS_outb;
+ set_io(&gs_xio);
+ GS_ev_mask = GS_MASK_INIT;
+ (void) signal(SIGPIPE, SIG_IGN);
+
+ if (resource.gs_safer)
+ gs_send(strsafe, (sizeof strsafe) - 1);
+ gs_send(str1, (sizeof str1) - 1);
+ gs_send(psheader, psheaderlen);
+ gs_send(str2, (sizeof str2) - 1);
+ waitack();
+ GS_in_header = False;
+ GS_ev_mask = GS_MASK_NORMAL;
+
+ if (GS_pid == 0) { /* if something happened */
+ destroy_gs();
+ return False;
+ }
+ if (resource.postscript == 0)
+ toggle_gs(0); /* if we got a 'v' already */
+ else {
+ scanned_page = scanned_page_ps = scanned_page_reset;
+ globals.ev.flags |= EV_NEWPAGE; /* ||| redraw the page */
+ longjmp(globals.ev.canit, 1);
+ }
+ return True;
+}
+
+static void
+toggle_gs(int flag) /* this routine is callable from within read_events(). */
+{
+ if (globals.debug & DBG_PS)
+ fprintf(stdout, "Toggling GS to %d", flag);
+
+ switch (flag) {
+ case 0:
+ psp.drawbegin = drawbegin_none;
+ break;
+ case 1:
+ psp.drawbegin = drawbegin_gs;
+ break;
+ default:
+ psp.drawbegin = drawbegin_gs_box;
+ break;
+ }
+}
+
+void
+gs_resume_prescan()
+{
+ if (globals.debug & DBG_PS)
+ puts("Resuming prescan");
+
+ gs_postpone_prescan = False;
+ if (!initGS()) /* this may not return */
+ psp = no_ps_procs;
+}
+
+static void
+gs_died(int status, struct xchild *child)
+{
+ UNUSED(status);
+ if (globals.debug & DBG_PS)
+ fprintf(stderr, "process %s died\n", child->name);
+ GS_pid = 0;
+ (child->io->read_proc)(child->io->fd);
+ if (linepos > line) {
+ *linepos = '\0';
+ printf("%s: %s\n", child->name, line);
+ linepos = line;
+ }
+ clear_io(child->io);
+ (void)close(child->io->fd);
+
+ scanned_page = scanned_page_ps = scanned_page_reset;
+ GS_active = GS_in_doc = False;
+ GS_pending = 0;
+ globals.ev.flags |= GS_die_ack;
+}
+
+static void
+destroy_gs(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Destroying GS process");
+ if (GS_pid != 0) {
+ if (kill(GS_pid, SIGKILL) < 0 && errno != ESRCH)
+ perror("xdvik: destroy_gs");
+ GS_pid = 0;
+ clear_chld(&gs_child);
+ read_from_gs(GS_fd);
+ if (linepos > line) {
+ *linepos = '\0';
+ printf("gs: %s\n", line);
+ linepos = line;
+ }
+ clear_io(&gs_xio);
+ (void) close(GS_fd);
+
+ scanned_page = scanned_page_ps = scanned_page_reset;
+ }
+ GS_active = GS_in_doc = False;
+ GS_pending = 0;
+}
+
+static void
+deactivate(void)
+{
+ static const char str[] = " stop\n%%xdvimark\n";
+ int saved_mask;
+
+ saved_mask = GS_ev_mask;
+ GS_ev_mask = 0;
+ gs_send(str, (sizeof str) - 1);
+ GS_ev_mask = saved_mask;
+
+ GS_active = False;
+}
+
+static void
+interrupt_gs(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running interrupt_gs()");
+ /*
+ FIXME: added this special case, since otherwise EV_ACK might not get
+ reset at all, and hang xdvi forever when scrolling quickly through
+ a file that should be reloaded.
+ */
+ if (GS_pending == 0) {
+/* fprintf(stderr, "+++++++++ 1st case; waitack: %d\n", globals.ev.flags & EV_ACK); */
+ globals.ev.flags &= ~EV_ACK;
+ return;
+ }
+ else if (GS_pending < 0) {
+/* fprintf(stderr, "GS_pending: %d; waitack: %d\n", GS_pending, globals.ev.flags & EV_ACK); */
+ return; /* nothing to do */
+ }
+
+ /*
+ * ||| what I'd really like to do here is cause gs to execute
+ * the interrupt routine in errordict. But so far (gs 2.6.1)
+ * that has not been implemented in ghostscript.
+ */
+
+ if (GS_active)
+ deactivate();
+ waitack();
+}
+
+static void
+endpage_gs(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running endpage_gs()");
+ if (GS_active) {
+ deactivate();
+ waitack();
+ }
+}
+
+/*
+ * Checks that the GS interpreter is running correctly.
+ */
+
+static void
+checkgs(Boolean in_header)
+{
+ char buf[150];
+
+ /* For gs 2, we pretty much have to start over to enlarge the window. */
+ if ((GS_old && (globals.page.w > GS_page_w || globals.page.h > GS_page_h))
+ || GS_alpha != resource.gs_alpha)
+ destroy_gs();
+
+ if (GS_pid == 0)
+ (void)initGS();
+
+ if (!GS_active) {
+ /* check whether page_w or page_h have increased */
+ if (globals.page.w > GS_page_w || globals.page.h > GS_page_h) {
+ if (globals.ev.flags & GS_ev_mask)
+ longjmp(globals.ev.canit, 1);
+ ++GS_pending;
+ sprintf(buf,
+ "H mark /HWSize [%d %d] /ImagingBBox [0 0 %d %d] "
+ "currentdevice putdeviceprops pop\n"
+ "initgraphics [0 1 1 0 0 0] concat stop\n"
+ "%%%%xdvimark\n",
+ GS_page_w = globals.page.w,
+ GS_page_h = globals.page.h,
+ globals.page.h,
+ globals.page.w);
+ gs_send(buf, strlen(buf));
+ if (!in_header) {
+ globals.ev.flags |= EV_NEWPAGE; /* ||| redraw the page */
+ longjmp(globals.ev.canit, 1);
+ }
+ }
+
+ if (magnification != GS_mag) {
+ if (globals.ev.flags & GS_ev_mask)
+ longjmp(globals.ev.canit, 1);
+ ++GS_pending;
+ sprintf(buf,
+ "H TeXDict begin /DVImag %ld 1000 div def end stop\n"
+ "%%%%xdvimark\n",
+ GS_mag = magnification);
+ gs_send(buf, strlen(buf));
+ }
+
+ if (mane.shrinkfactor != GS_shrink) {
+ if (globals.ev.flags & GS_ev_mask)
+ longjmp(globals.ev.canit, 1);
+ ++GS_pending;
+ sprintf(buf,
+ "H TeXDict begin %d %d div dup /Resolution X /VResolution X end stop\n"
+ "%%%%xdvimark\n",
+ resource.pixels_per_inch,
+ GS_shrink = mane.shrinkfactor);
+ gs_send(buf, strlen(buf));
+ }
+ }
+}
+
+static void
+drawbegin_gs(int xul, int yul, const char *cp)
+{
+ char buf[32];
+ static const char str[] = " TeXDict begin\n";
+
+ checkgs(False);
+
+ if (!GS_active) {
+ if (globals.ev.flags & GS_ev_mask)
+ longjmp(globals.ev.canit, 1);
+ ++GS_pending;
+ gs_send(str, (sizeof str) - 1);
+ GS_active = True;
+ }
+
+ /* This allows the X side to clear the page */
+ XSync(DISP, False);
+
+ sprintf(buf, "%d %d moveto\n", xul, yul);
+ gs_send(buf, strlen(buf));
+/* gs_send(clear_bg, strlen(clear_bg)); */
+ if (globals.debug & DBG_PS)
+ printf("drawbegin at %d,%d: sending `%s'\n", xul, yul, cp);
+
+ /*
+ * added SU 2000/12/18:
+ * Try to detect some simple PS rotating commands, and warn about them.
+ * There are surely more than that ...
+ */
+ if (strstr(cp, "rotate") != NULL /* used by graphics.sty */
+ || strstr(cp, "RotBegin") != NULL /* used by pstricks */
+ ) {
+ statusline_print(STATUS_SHORT,
+ "Warning: PS code on page %d may contain rotation, "
+ "which is not supported by xdvi", current_page + 1);
+ }
+
+ gs_send(cp, strlen(cp));
+}
+
+static void
+drawbegin_gs_box(int xul, int yul, const char *cp)
+{
+ drawbegin_gs(xul, yul, cp);
+}
+
+
+void
+drawraw_gs(const char *cp)
+{
+ if (!GS_active)
+ return;
+ if (globals.debug & DBG_PS)
+ printf("raw ps sent to context: %s\n", cp);
+ gs_send(cp, strlen(cp));
+ gs_send("\n", 1);
+}
+
+static void
+drawfile_gs(const char *cp, FILE *f)
+{
+ char canonical_path[MAXPATHLEN + 1];
+ char *ret;
+
+ fclose(f); /* don't need it */
+
+ if (!GS_active)
+ return;
+
+ if (globals.debug & DBG_PS)
+ printf("original path: |%s|\n", cp);
+/* drawraw_gs("newpath 0 0 moveto 0 1000 rlineto 1000 0 rlineto 0 -1000 rlineto closepath 1 setgray fill"); */
+#if 0
+ /* if expand_symlinks or remove_dots from kpathsea were public,
+ we could use the following: */
+ ret = remove_dots(expand_symlinks(cp));
+#endif
+
+ ret = REALPATH(cp, canonical_path);
+ if (ret == NULL)
+ XDVI_WARNING((stderr, "Couldn't canonicalize path \"%s\": %s. Sending to gs unchanged.",
+ cp, strerror(errno)));
+ else
+ cp = canonical_path;
+
+ if (globals.debug & DBG_PS)
+ printf("expanded path: |%s|\n", cp);
+
+ gs_send("(", 1);
+ gs_send(cp, strlen(cp));
+ gs_send(")run\n", 5);
+/* { */
+/* char *clear_bg = "newpath 0 0 moveto 0 1000 rlineto 1000 0 rlineto 0 -1000 rlineto closepath .4 setgray fill\n"; */
+/* gs_send(clear_bg, strlen(clear_bg)); */
+/* } */
+}
+
+static void
+drawend_gs(const char *cp)
+{
+ if (!GS_active)
+ return;
+ if (globals.debug & DBG_PS)
+ printf("end ps: %s\n", cp);
+ gs_send(cp, strlen(cp));
+ gs_send("\n", 1);
+ save_bbox();
+}
+
+static void
+beginheader_gs(void)
+{
+ static const char str[] = "Hsave /xdvi$doc exch def\n";
+
+ if (globals.debug & DBG_PS)
+ puts("Running beginheader_gs()");
+
+ checkgs(True);
+
+ if (GS_active) {
+ if (!GS_in_header)
+ XDVI_FATAL((stderr, "Internal error in beginheader_gs()."));
+ return;
+ }
+
+ if (globals.ev.flags & GS_ev_mask) {
+/* fprintf(stderr, "longjmp!"); */
+ longjmp(globals.ev.canit, 1);
+ }
+
+ GS_in_header = True;
+ GS_ev_mask = GS_MASK_HEADER;
+ ++GS_pending;
+ if (GS_in_doc)
+ gs_send("H", 1);
+ else {
+ gs_send(str, (sizeof str) - 1);
+ GS_in_doc = True;
+ }
+ GS_active = True;
+}
+
+static void
+endheader_gs(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running endheader_gs()");
+
+ if (GS_active) {
+ deactivate();
+ waitack();
+ GS_in_header = False;
+ GS_ev_mask = GS_MASK_NORMAL;
+ }
+}
+
+static void
+newdoc_gs(void)
+{
+ static const char str[] = "Hxdvi$doc restore stop\n%%xdvimark\n";
+
+ if (globals.debug & DBG_PS)
+ puts("Running newdoc_gs()");
+
+ if (GS_in_doc) {
+ ++GS_pending;
+ gs_send(str, (sizeof str) - 1);
+ GS_mag = GS_shrink = -1;
+ GS_in_doc = False;
+
+ if (!GS_old) GS_page_w = GS_page_h = 0;
+ }
+}
+
+void erasepage_gs(void)
+{
+ /* In buffered mode, gs has no way of knowing that the screen has been
+ erased. Clear the gs window buffer with an erasepage command. */
+
+ if (resource.gs_alpha && GS_pid > 0 && !GS_active) {
+ if (globals.debug & DBG_PS)
+ puts("erasing page!");
+ beginheader_gs();
+ drawraw_gs("erasepage");
+ endheader_gs();
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* PS_GS */
diff --git a/Build/source/texk/xdvik/psgs.h b/Build/source/texk/xdvik/psgs.h
new file mode 100644
index 00000000000..9c7cb44b319
--- /dev/null
+++ b/Build/source/texk/xdvik/psgs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef PSGS_H_
+#define PSGS_H_
+
+extern Boolean initGS(void);
+extern void gs_resume_prescan(void);
+extern void restart_gs(void);
+extern void erasepage_gs(void);
+
+#endif /* PSGS_H_ */
diff --git a/Build/source/texk/xdvik/psheader.txt b/Build/source/texk/xdvik/psheader.txt
new file mode 100644
index 00000000000..8a8b456c3ba
--- /dev/null
+++ b/Build/source/texk/xdvik/psheader.txt
@@ -0,0 +1,313 @@
+%% These are from tex.lpro
+/TeXDict 250 dict def % define a working dictionary ( IBM: color - 200->250 )
+TeXDict begin % start using it.
+/N {def} def
+/B {bind def} N
+/S {exch} N
+/X { S N } B
+/TR {translate} N
+/vsize 11 72 mul N
+end % TeXDict
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% header for the \special command
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% The structure of the PostScript produced by dvips for \special is:
+% @beginspecial
+% - any number of @hsize, @hoffset, @hscale, etc., commands
+% @setspecial
+% - the user's file of PostScript commands
+% @endspecial
+
+TeXDict begin
+/SDict 200 dict N
+SDict begin
+
+/@SpecialDefaults
+ { /hs 612 N
+ /vs 792 N
+ /ho 0 N
+ /vo 0 N
+ /hsc 1 N
+ /vsc 1 N
+ /ang 0 N
+ /CLIP 0 N
+ /rwiSeen false N
+ /rhiSeen false N
+ /letter {} N /note {} N /a4 {} N /legal {} N
+ } B
+
+%
+% The following definition sets up the units that hscale/vscale are in.
+% For certain sites this might require change, but it is
+% recommended instead that any macro packages that require
+% hscale/vscale set the units appropriately via
+%
+% \special{! /@scaleunit 1 def }
+%
+% if global, or
+%
+% \special{" /@scaleunit 1 def }
+%
+% before each instance if multiple macro packages with
+% different requirements are being used.
+%
+/@scaleunit 100 N
+% s @hscale - set scale factor
+/@hscale {@scaleunit div /hsc X} B
+/@vscale {@scaleunit div /vsc X} B
+
+% d @hsize - specify a horizontal clipping dimension
+/@hsize {/hs X /CLIP 1 N} B
+/@vsize {/vs X /CLIP 1 N} B
+
+/@clip {/CLIP 2 N} B
+
+% d @hoffset - specify a shift for the figure
+/@hoffset {/ho X} B
+/@voffset {/vo X} B
+
+% a @angle - set rotation angle
+/@angle {/ang X} B
+
+%
+% Here we handle bounding box calculations, if necessary.
+%
+/@rwi { 10 div /rwi X /rwiSeen true N } B % rwi will be real width after scaling
+/@rhi { 10 div /rhi X /rhiSeen true N } B % rhi will be real height after scaling
+/@llx { /llx X } B
+/@lly { /lly X } B
+/@urx { /urx X } B
+/@ury { /ury X } B
+
+/magscale true def
+
+end % of SDict
+
+/@MacSetUp
+ { userdict /md known % if md is defined
+ { userdict /md get type /dicttype eq % and if it is a dictionary
+ {
+ userdict begin % expand it if necessary
+ md length 10 add md maxlength ge
+ {/md md dup length 20 add dict copy def}if
+ end
+ md begin % then redefine some stuff
+ /letter {} N
+ /note {} N
+ /legal {} N
+ /od{txpose
+ 1 0 mtx defaultmatrix dtransform S atan/pa X
+ newpath clippath mark
+ {transform{itransform moveto}}
+ {transform{itransform lineto}}
+ { 6 -2 roll transform
+ 6 -2 roll transform
+ 6 -2 roll transform
+ { itransform 6 2 roll
+ itransform 6 2 roll
+ itransform 6 2 roll
+ curveto
+ }
+ }
+ {{closepath}}
+ pathforall newpath counttomark array astore /gc xdf
+ pop ct 39 0 put
+ 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if
+ }N
+ /txpose{
+ pxs pys scale ppr aload pop
+ por {
+ noflips {
+ pop S neg S TR pop 1 -1 scale
+ }if
+ xflip yflip and {
+ pop S neg S TR 180 rotate 1 -1 scale
+ ppr 3 get ppr 1 get neg sub neg ppr 2 get
+ ppr 0 get neg sub neg TR
+ }if
+ xflip yflip not and {
+ pop S neg S TR pop 180 rotate
+ ppr 3 get ppr 1 get neg sub neg 0 TR
+ }if
+ yflip xflip not and {
+ ppr 1 get neg ppr 0 get neg TR
+ }if
+ }
+ {
+ noflips {
+ TR pop pop 270 rotate 1 -1 scale
+ }if
+ xflip yflip and {
+ TR pop pop 90 rotate 1 -1 scale
+ ppr 3 get ppr 1 get neg sub neg ppr 2 get
+ ppr 0 get neg sub neg TR
+ }if
+ xflip yflip not and {
+ TR pop pop 90 rotate ppr 3 get
+ ppr 1 get neg sub neg 0 TR
+ }if
+ yflip xflip not and {
+ TR pop pop 270 rotate ppr 2 get
+ ppr 0 get neg sub neg 0 S TR
+ }if
+ }ifelse
+ scaleby96 {
+ ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy
+ TR .96 dup scale neg S neg S TR
+ }if
+ }N
+ /cp {pop pop showpage pm restore}N
+ end
+ }if
+ } if
+ } N
+
+%
+% The following procedure brings us back to PostScript size. It takes
+% into account the current global dvi magnification, so graphics
+% scale with the document.
+%
+/normalscale {
+ Resolution 72 div VResolution 72 div neg scale
+ magscale { DVImag dup scale } if
+ 0 setgray
+} N
+%
+% We need the psfig macros.
+%
+% All software, documentation, and related files in this distribution of
+% psfig/tex are Copyright (c) 1987 Trevor J. Darrell
+%
+% Permission is granted for use and non-profit distribution of psfig/tex
+% providing that this notice be clearly maintained, but the right to
+% distribute any portion of psfig/tex for profit or as part of any commercial
+% product is specifically reserved for the author.
+%
+%
+% psfigTeX PostScript Prolog
+%
+/psfts { S 65781.76 div N } N
+
+% x y bb-llx bb-lly bb-urx bb-ury startTexFig -
+/startTexFig {
+ /psf$SavedState save N
+ userdict maxlength dict begin
+
+ /magscale true def
+ normalscale
+ currentpoint TR %set the current point as the user's origin
+
+ /psf$ury psfts
+ /psf$urx psfts
+ /psf$lly psfts
+ /psf$llx psfts
+ /psf$y psfts
+ /psf$x psfts
+
+ /psf$sx psf$x psf$urx psf$llx sub div N % scaling for x
+ /psf$sy psf$y psf$ury psf$lly sub div N % scaling for y
+
+ psf$sx psf$sy scale % scale by (sx,sy)
+
+ psf$llx neg psf$ury neg TR
+
+ /showpage {
+ } N
+ /erasepage {
+ } N
+ /copypage {
+ } N
+ /setpagedevice {pop} def
+ /p 3 def % necessary to get around a bug in Adobe Illustrator
+ @MacSetUp
+} N
+
+% llx lly urx ury doclip - (args in figure coordinates)
+/doclip {
+ psf$llx psf$lly psf$urx psf$ury
+ currentpoint 6 2 roll
+ newpath 4 copy
+ 4 2 roll moveto
+ 6 -1 roll S lineto
+ S lineto
+ S lineto
+ closepath clip
+ newpath
+ moveto
+} N
+% - endTexFig -
+/endTexFig { end psf$SavedState restore } N
+
+% this will be invoked as the result of a \special command (for the
+% inclusion of PostScript graphics). The basic idea is to change all
+% scaling and graphics back to defaults, but to shift the origin
+% to the current position on the page.
+
+/@beginspecial % - @beginspecial - -- enter special mode
+ {
+ /SpecialSave save N
+ SDict begin
+ gsave
+ normalscale
+ currentpoint TR %set the current point as the user's origin
+ @SpecialDefaults % setup default offsets, scales, sizes, and angle
+ count /ocount X /dcount countdictstack N
+ } N
+
+/@setspecial % to setup user specified offsets, scales, sizes (for clipping)
+ {
+ CLIP 1 eq
+ { newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
+ closepath clip }
+ if
+ ho vo TR
+ hsc vsc scale
+ ang rotate
+ rwiSeen {
+ rwi urx llx sub div
+ rhiSeen { rhi ury lly sub div } { dup } ifelse
+ scale llx neg lly neg TR
+ } {
+ rhiSeen { rhi ury lly sub div dup scale llx neg lly neg TR } if
+ } ifelse
+ CLIP 2 eq
+ { newpath llx lly moveto urx lly lineto urx ury lineto llx ury lineto
+ closepath clip }
+ if
+ /showpage {} N
+ /erasepage {} N
+ /copypage {} N
+ /setpagedevice {pop} def
+ newpath
+ } N
+
+/@endspecial % - @endspecial - -- leave special mode
+ { count ocount sub {pop} repeat
+ countdictstack dcount sub {end} repeat
+ grestore SpecialSave restore
+ end
+ } N
+
+% xdvik special treatment for saving definitions made in SDict (while using
+% the bang special; try to guarantee that the dictionary stack is ok!
+% xdvik should not systematically bracket code within save/restore pairs,
+% anyway: such bracketing breaks a lot of code (many packages do change
+% TeXDict from with ps: specials for instance) and we should only guarantee
+% that bracketing is done within @beginspecial and @endspecial. -- YA
+
+/@xdvisavestate
+ {
+ userdict /xdvi$sav save put
+ } N
+
+/@defspecial
+ {
+ SDict begin
+ } N
+/@fedspecial
+ {
+ end
+ @xdvisavestate
+ } B
+end % revert to previous dictionary
diff --git a/Build/source/texk/xdvik/psnews.c b/Build/source/texk/xdvik/psnews.c
new file mode 100644
index 00000000000..27781095824
--- /dev/null
+++ b/Build/source/texk/xdvik/psnews.c
@@ -0,0 +1,951 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2004 Paul Vojta
+
+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.
+
+NOTES:
+ This code was originally written by Ricardo Telichevesky
+ (ricardo@rle-vlsi-mit.edu) and Luis Miguel Silveira
+ (lms@rle-vlsi-mit.edu).
+ It was largely influenced by similar code in the SeeTeX/XTeX
+ package by Dirk Grunwald (grunwald@colorado.edu).
+
+\*========================================================================*/
+
+/* ||| To do:
+ * ALWAYS_CLOSE_SERVER_CONNECTION?
+ * Is there some way of interrupting a process?
+ * fork
+ * extra bytes on input
+ */
+
+#ifdef PS_NEWS /* whole file */
+
+#include <signal.h>
+#include <sys/file.h> /* this defines FASYNC */
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#undef SYSV /* To avoid defined SYSV_{WAIT,UCONTEXT} in xview/notify.h. */
+#include <NeWS/psio.h>
+#include <xvps/pscanvas.h>
+
+/* Condition for retrying a write */
+#include <errno.h>
+#include <setjmp.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "dvi-draw.h"
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined(O_NONBLOCK) && defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#endif
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#ifdef EWOULDBLOCK
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN)
+#else /* EAGAIN */
+#define AGAIN_CONDITION (errno == EWOULDBLOCK)
+#endif /* EAGAIN */
+#else /* EWOULDBLOCK */
+#ifdef EAGAIN
+#define AGAIN_CONDITION (errno == EAGAIN)
+#endif /* EAGAIN */
+#endif /* EWOULDBLOCK */
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+# define FLAKY_SIGPOLL 1
+#endif
+
+char *strtok(char *, const char *);
+
+/* define ALWAYS_CLOSE_SERVER_CONNECTION if you want to close the server
+ connection all the time */
+#undef ALWAYS_CLOSE_SERVER_CONNECTION
+
+
+/*
+ * Some setup code.
+ */
+static const char str0[] =
+ "/OW2? version cvi 2 eq def "
+ "OW2? "
+ "{ /setlinewidth { pop } def} "
+ "{ /NeWS 3 0 findpackage beginpackage "
+ " /X11 3 0 findpackage beginpackage} "
+ "ifelse "
+ "currentcanvas /Color get "
+ "currentcanvas /Colormap get getcubedescription null eq and "
+ " {8 {{currentcanvas /Colormap get 1 index dup dup dup newcube} stopped "
+ " {pop pop pop pop pop} {exit} ifelse "
+ " 2 div cvi dup 1 eq {exit} if} loop pop} "
+ "if\n";
+/*
+ * This string reads chunks (delimited by %%xdvimark).
+ * The first character of a chunk tells whether a given chunk
+ * is to be done within save/restore or not.
+ * The `H' at the end tells it that the first group is a
+ * header; i.e., no save/restore.
+ */
+static const char preamble[] =
+ "/xdvi$line 81 string def "
+ "/xdvi$run {$error null ne {$error /newerror false put} if "
+ " {currentfile cvx stopped "
+ " $error null eq {false} {$error /newerror get} ifelse and "
+ " {handleerror} if} stopped pop} def "
+ "/xdvi$dslen countdictstack def "
+ "{currentfile read not {exit} if 72 eq "
+ " {xdvi$run} "
+ " {/xdvi$sav save def xdvi$run "
+ " clear countdictstack xdvi$dslen sub {end} repeat xdvi$sav restore} "
+ " ifelse "
+ " {(%%xdvimark) currentfile xdvi$line {readline} stopped "
+ " {clear} {{eq {false exit} if} {true exit} ifelse} ifelse }loop {exit} if "
+ " 58 tagprint flush "
+ "}loop\nH";
+
+extern const char psheader[];
+extern int psheaderlen;
+
+static const char preamble2[] = " stop\n%%xdvimark\n";
+#define stopstring preamble2
+
+/* global procedures (besides initNeWS) */
+
+static void toggleNeWS(int flag);
+static void destroyNeWS(void);
+static void interruptNeWS(void);
+static void endpageNeWS(void);
+static void drawbeginNeWS(int, int, const char *);
+static void drawbeginNeWS_box(int, int, const char *);
+static void drawrawNeWS(const char *);
+static void drawrawNeWS_box(const char *);
+static void drawfileNeWS(const char *, FILE *);
+static void drawendNeWS(const char *);
+static void beginheaderNeWS(void);
+static void endheaderNeWS(void);
+static void newdocNeWS(void);
+
+static struct psprocs news_procs = {
+ /* toggle */ toggleNeWS,
+ /* destroy */ destroyNeWS,
+ /* interrupt */ interruptNeWS,
+ /* endpage */ endpageNeWS,
+ /* drawbegin */ drawbeginNeWS,
+ /* drawraw */ drawrawNeWS,
+ /* drawfile */ drawfileNeWS,
+ /* drawend */ drawendNeWS,
+ /* beginheader */ beginheaderNeWS,
+ /* endheader */ endheaderNeWS,
+ /* newdoc */ newdocNeWS
+};
+
+/* define local static variables */
+static int NeWS_mag; /* magnification currently in use */
+static int NeWS_shrink; /* shrink factor currently in use */
+static unsigned int NeWS_page_w; /* how big our current page is */
+static unsigned int NeWS_page_h;
+static Boolean NeWS_active; /* if we've started a page yet */
+static int NeWS_pending; /* number of ack's we're expecting */
+static const char *NeWS_send_byte; /* next byte to send to NeWS */
+static const char *NeWS_send_end; /* last + 1 byte to send */
+static Boolean NeWS_in_header; /* if we're sending a header */
+static Boolean NeWS_in_doc; /* if we've sent header information */
+static int NeWS_ev_mask; /* events for which we'll stop */
+static Boolean NeWS_destroyed = False;
+
+#define NEWS_MASK_NORMAL EV_GE_NEWPAGE
+#define NEWS_MASK_HEADER EV_GE_PS_TOGGLE
+#define NEWS_MASK_INIT (EV_GE_TERM | EV_PS_TOGGLE)
+
+
+/*
+ * NeWS I/O code. This should send PS code to NeWS,
+ * receive acknowledgements, and receive X events in the meantime.
+ * It also checks for SIGPIPE errors.
+ */
+
+static void read_from_NeWS(void);
+static void write_to_NeWS(void);
+
+static struct xio NeWS_xout = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_NeWS, write_to_NeWS};
+
+static struct xio NeWS_xin = {NULL, 0, XIO_IN,
+#if HAVE_POLL
+ NULL,
+#endif
+ read_from_NeWS, NULL};
+
+
+/*---------------------------------------------------------------------------*
+ psio_sigpipe_handler ()
+
+ Arguments: sig, code, scp, addr (see man page for signal)
+ Returns: (void)
+ Side-Effects: SIGPIPE signal is flagged as sigpipe_error variable is set.
+
+ Description:
+ Handler for SIGPIPE error generated by a broken pipe in the connection
+ to the NeWS server; this may be duer to some abnormal condition, or some
+ hairy PostScript code containing commands not implemented by the server.
+
++----------------------------------------------------------------------------*/
+
+static Boolean sigpipe_error = False;
+
+static struct sigaction psio_sigpipe_handler_struct;
+ /* initialized to {psio_sigpipe_handler, (sigset_t) 0, 0} in initNeWS */
+
+static RETSIGTYPE
+psio_sigpipe_handler(int sig, int code, struct sigcontext *scp, char *addr)
+{
+ sigpipe_error = True;
+}
+
+
+/*
+ * read_from_NeWS - This does the actual retrieving of acknowledgements.
+ * If other bytes appear on the file - tough.
+ */
+
+static void
+read_from_NeWS(void)
+{
+ for (;;) {
+ int retval;
+
+ retval = ps_checkfor(PostScriptInput, PSIO_FIND_TAG, 58);
+ if (retval == 0)
+ break;
+ if (retval < 0) {
+ fprintf(stderr, "[xdvik] ps_checkfor: %d\n", retval);
+ return;
+ }
+ (void)ps_checkfor(PostScriptInput, PSIO_WAIT_TAG, 58);
+ --NeWS_pending;
+ if (NeWS_pending == 0)
+ globals.ev.flags |= EV_ACK;
+ if (globals.debug & DBG_PS)
+ printf("Got NeWS ack; %d pending.\n", NeWS_pending);
+ }
+}
+
+
+/*
+ * write_to_NeWS - Write to the PostScript interpreter.
+ */
+
+static void
+write_to_NeWS(void)
+{
+ int old_flags;
+ int bytes;
+
+ old_flags = fcntl(PostScript->file, F_GETFL, 0);
+ if (old_flags < 0) return;
+ /* set to be non-blocking */
+ if (fcntl(PostScript->file, F_SETFL, old_flags | O_NONBLOCK) < 0)
+ return;
+
+ for (;;) {
+ bytes = write(PostScript->file, NeWS_send_byte,
+ NeWS_send_end - NeWS_send_byte);
+ if (bytes < 0) {
+ if (AGAIN_CONDITION)
+ break;
+ perror("xdvi NeWS_send");
+ break;
+ }
+ NeWS_send_byte += bytes;
+ if (NeWS_send_byte == NeWS_send_end) {
+ NeWS_send_byte = NULL;
+ NeWS_xout.xio_events &= ~XIO_OUT;
+#if HAVE_POLL
+ /* This check is necessary, since write_to_NeWS can be called
+ directly. */
+ if (NeWS_xout.pfd != NULL)
+ NeWS_xout.pfd->events &= ~POLLOUT;
+ globals.ev.flags |= EV_ACK;
+ break;
+#endif
+ }
+ }
+
+ fcntl(PostScript->file, F_SETFL, old_flags);
+}
+
+
+/*
+ * Clean up after NeWS_send()
+ */
+
+static void
+post_send(void)
+{
+ if (sigpipe_error) {
+ fputs("NeWS died unexpectedly.\n", stderr);
+ destroyNeWS();
+ draw_bbox();
+ }
+}
+
+
+/*
+ * Main routine for writing to the NeWS interpreter.
+ */
+
+static void
+NeWS_send(const char *cp, size_t len)
+{
+ struct sigaction orig;
+
+ if (PostScript == (PSFILE *) NULL || (globals.ev.flags & NeWS_ev_mask))
+ return;
+
+ (void) sigaction(SIGPIPE, &psio_sigpipe_handler_struct, &orig);
+ sigpipe_error = False;
+
+ NeWS_send_byte = cp;
+ NeWS_send_end = cp + len;
+ NeWS_xout.xio_events |= XIO_OUT;
+#if HAVE_POLL
+ if (NeWS_xout.pfd != NULL)
+ NeWS_xout.pfd->events |= POLLOUT;
+#endif
+
+ write_to_NeWS();
+ (void) read_events(NeWS_ev_mask | EV_ACK);
+
+ if (!(globals.ev.flags & EV_ACK)) { /* if interrupted */
+ /* ||| Do somthing more severe here */
+ }
+
+ globals.ev.flags &= ~EV_ACK;
+
+ /* put back generic handler for SIGPIPE */
+ (void) sigaction(SIGPIPE, &orig, (struct sigaction *) NULL);
+
+ if (!NeWS_in_header)
+ post_send();
+}
+
+/*
+ * Wait for acknowledgement from NeWS. With NeWS we have no choice but
+ * to wait (||| I think).
+ */
+
+static void
+waitack(void)
+{
+ if (PostScript == (PSFILE *) NULL)
+ return;
+
+ if (NeWS_pending > 0)
+ (void) read_events(EV_GE_ACK);
+
+ if (globals.ev.flags & EV_ACK) {
+ globals.ev.flags &= ~EV_ACK;
+ return;
+ }
+
+ /* ||| Do something more serious here */
+}
+
+
+/*---------------------------------------------------------------------------*
+ initNeWS()
+
+ Arguments: None.
+ Returns: True if and only if initialization succeeded
+ Side-Effects: Static variables may be set.
+
+ Description:
+ Initializes variables for the application main loop.
+
++----------------------------------------------------------------------------*/
+
+Boolean initNeWS()
+{
+ static NeWStoken newstoken;
+
+ /* now try to open the connection to the NeWS server */
+ if (ps_open_PostScript() == (PSFILE *) NULL)
+ return False;
+
+ psio_sigpipe_handler_struct.sa_handler = psio_sigpipe_handler;
+ sigemptyset(&psio_sigpipe_handler_struct.sa_mask);
+
+#if !FLAKY_SIGPOLL
+ if (fcntl(PostScript->file, F_SETOWN, getpid()) == -1)
+ perror("xdvi: fcntl F_SETOWN");
+ if (fcntl(PostScript->file, F_SETFL,
+ fcntl(PostScript->file, F_GETFL, 0) | FASYNC) == -1)
+ perror("xdvi: fcntl F_SETFL");
+#endif /* not FLAKY_SIGPOLL */
+ if (PostScriptInput->file != PostScript->file) {
+#if !FLAKY_SIGPOLL
+ if (fcntl(PostScriptInput->file, F_SETOWN, getpid()) == -1)
+ perror("xdvi: fcntl F_SETOWN");
+ if (fcntl(PostScriptInput->file, F_SETFL,
+ fcntl(PostScriptInput->file, F_GETFL, 0) | FASYNC) == -1)
+ perror("xdvi: fcntl F_SETFL");
+#endif /* not FLAKY_SIGPOLL */
+ NeWS_xout.xio_events &= ~XIO_IN;
+ NeWS_xin.fd = PostScriptInput->file;
+ set_io(&NeWS_xin);
+ }
+ NeWS_xout.fd = PostScript->file;
+ set_io(&NeWS_xout);
+
+ NeWS_active = False;
+ NeWS_in_header = True;
+ NeWS_ev_mask = NEWS_MASK_INIT;
+ NeWS_pending = 1;
+
+ ps_flush_PostScript();
+ NeWS_send(str0, (sizeof str0) - 1);
+ /* get xid of window, then make this window the NeWS canvas */
+ (void)ps_token_from_xid(mane.win, &newstoken);
+ if (newstoken != -1) {
+ ps_setcanvas(newstoken);
+ ps_flush_PostScript();
+
+ NeWS_send(preamble, (sizeof preamble) - 1);
+ NeWS_send(psheader, psheaderlen);
+ NeWS_send(preamble2, (sizeof preamble2) - 1);
+ NeWS_in_header = False;
+ post_send();
+ waitack();
+ }
+
+ if (NeWS_destroyed)
+ return False;
+
+ /* success */
+
+ NeWS_mag = NeWS_shrink = -1;
+ NeWS_page_w = globals.page.w;
+ NeWS_page_h = globals.page.h;
+
+ psp = news_procs;
+ if (!resource.postscript)
+ toggleNeWS(0); /* if we got a 'v' already */
+
+ return True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ toggleNeWS(int flag)
+
+ Arguments: flag for toggling PostScript
+ Returns: (void)
+ Side-Effects: psp.drawbegin is changed
+
+ Description:
+ Used to toggle the rendering of PostScript by the NeWS server
+ Callable from within read_events().
+
++----------------------------------------------------------------------------*/
+
+static void
+toggleNeWS(int flag)
+{
+ if (globals.debug & DBG_PS)
+ fprintf(stdout, "Toggling NeWS to %d", flag);
+
+ switch (flag) {
+ case 0:
+ psp.drawbegin = drawbegin_none;
+ break;
+ case 1:
+ psp.drawbegin = drawbeginNeWS;
+ break;
+ default:
+ psp.drawbegin = drawbeginNeWS_box;
+ break;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ destroyNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the pointer to the NeWS file is nulled
+
+ Description:
+ Close the connection to the NeWS server; used when rendering is terminated
+ in any way.
+
++----------------------------------------------------------------------------*/
+
+static void
+destroyNeWS(void)
+{
+ psp = no_ps_procs;
+ NeWS_destroyed = True;
+ scanned_page = scanned_page_ps = scanned_page_reset;
+}
+
+
+/*---------------------------------------------------------------------------*
+ interruptNeWS()
+
+ Arguments: none
+ Returns: void
+
+ Description:
+ Close the connection to the NeWS server; used when rendering is terminated
+ because of an interruption in the viewing of the current page.
+ ||| It would be nice if we could asynchronously ``wake up'' a NeWS process
+ (preferably by sending something along the X socket); then we could do
+ better than just to wait.
+
++----------------------------------------------------------------------------*/
+
+static void
+interruptNeWS(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("Running interruptNeWS()");
+ if (NeWS_pending <= 0) return; /* if nothing to do */
+
+ if (NeWS_active) {
+ NeWS_send(stopstring, (sizeof stopstring) - 1);
+ NeWS_active = False;
+ }
+
+ for (;;) {
+ ps_flush_PostScript();
+ if (NeWS_pending <= 0) break;
+ waitack();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ endpageNeWS()
+
+ Arguments: none
+ Returns: (void)
+ Side-Effects: the NeWS_active variable is cleared.
+
+ Description:
+ Should be called at the end of a page to end this chunk for the NeWS server.
+
++----------------------------------------------------------------------------*/
+
+static void
+endpageNeWS(void)
+{
+ if (globals.debug & DBG_PS)
+ puts("endpage sent to NeWS Server");
+ if (NeWS_active) {
+ NeWS_send(stopstring, (sizeof stopstring) - 1);
+ NeWS_active = False;
+ waitack();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawbeginNeWS ()
+
+ Arguments: xul, yul - coordinates of the upper left corner of the figure
+ cp - string with the bounding box line data
+ Returns: (void)
+
+ Description:
+ Opens a connection to the NeWS server and send in the preamble and the
+ bounding box information after correctly computing resolution factors.
+ In case no rendering is to be done, outlines the figure. An outline is
+ also generated whenever the PostScript code is too hairy and generates
+ a SIGPIPE signal.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawbeginNeWS(int xul, int yul, const char *cp)
+{
+ char buf[100];
+ static const char str[] = " TeXDict begin\n";
+ static const char str2[] = "Hinitgraphics stop\n%%xdvimark\n";
+
+ if (globals.debug & DBG_PS) {
+ printf("xul= %d yul= %d\n", xul, yul);
+ printf("String = < %s >\n", cp);
+ }
+
+ /* catch up on the X side */
+ XSync(DISP, False);
+
+ if (!NeWS_active) {
+ /* send initialization to NeWS server */
+ if (NeWS_page_w < globals.page.w || NeWS_page_h < globals.page.h) {
+ if (globals.ev.flags & NEWS_MASK_NORMAL)
+ longjmp(globals.ev.canit, 1);
+ ++NeWS_pending;
+ NeWS_page_w = globals.page.w;
+ NeWS_page_h = globals.page.h;
+ NeWS_send(str2, (sizeof str2) - 1);
+ }
+ if (magnification != NeWS_mag) {
+ if (globals.ev.flags & NEWS_MASK_NORMAL)
+ longjmp(globals.ev.canit, 1);
+ ++NeWS_pending;
+ sprintf(buf, "H TeXDict begin /DVImag %d 1000 div def "
+ "end stop\n%%%%xdvimark\n",
+ NeWS_mag = magnification);
+ NeWS_send(buf, strlen(buf));
+ }
+ if (mane.shrinkfactor != NeWS_shrink) {
+ if (globals.ev.flags & NEWS_MASK_NORMAL)
+ longjmp(globals.ev.canit, 1);
+ ++NeWS_pending;
+ sprintf(buf, "H TeXDict begin %d %d div dup "
+ "/Resolution X /VResolution X "
+ "end stop\n%%%%xdvimark\n",
+ resource.pixels_per_inch,
+ NeWS_shrink = mane.shrinkfactor);
+ NeWS_send(buf, strlen(buf));
+ }
+ if (globals.ev.flags & NEWS_MASK_NORMAL)
+ longjmp(globals.ev.canit, 1);
+ ++NeWS_pending;
+ NeWS_send(str, (sizeof str) - 1);
+ NeWS_active = True;
+ }
+
+ sprintf(buf, "%d %d moveto\n", xul, yul);
+ NeWS_send(buf, strlen(buf));
+ NeWS_send(cp, strlen(cp));
+}
+
+static void
+drawbeginNeWS_box(int xul, int yul, const char *cp)
+{
+ drawbeginNeWS(xul, yul, cp);
+ draw_bbox();
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawrawNeWS()
+
+ Arguments: origcp - the raw string to be sent to the postscript interpreter
+ Returns: (void)
+ Side-Effects: (none)
+
+ Description:
+ If there is a valid connection to the NeWS server, just send the string to
+ the interpreter, else leave.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawrawNeWS(const char *origcp)
+{
+ const char *pt, *ptm1, *ocp1;
+ static char *cp;
+ char *cp1;
+ static unsigned int cplen = 0;
+ unsigned int len;
+ double angle;
+ Boolean found = False;
+
+ if (!NeWS_active)
+ return;
+
+ if (globals.debug & DBG_PS)
+ printf("Raw PS sent to context: <%s>\n", origcp);
+
+ /* take a look at the string: NeWS bums on certain rotations */
+ len = strlen(origcp) + 4;
+ if (cplen < len) {
+ if (cplen != 0)
+ free(cp);
+ cplen = len;
+ cp = xmalloc(cplen);
+ }
+ ocp1 = origcp;
+ pt = origcp;
+ while (*pt == ' ' || *pt == '\t')
+ ++pt;
+ cp1 = cp;
+ for (;;) {
+ ptm1 = pt;
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t')
+ ++pt;
+ if (*pt == '\0')
+ break;
+ while (*pt == ' ' || *pt == '\t')
+ ++pt;
+ if (strncmp(pt, "rotate", 6) == 0
+ && (pt[6] == '\0' || pt[6] == ' ' || pt[6] == '\t')) {
+ /* found rotate; check angle */
+ if (sscanf(ptm1, "%lf", &angle) >= 1) {
+ found = True;
+ while (angle > 360.0)
+ angle -= 360;
+ while (angle < -360.0)
+ angle += 360;
+ if (angle == 90.0) {
+ angle = 89.999;
+ (void)memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ strcpy(cp1, "89.999 rotate ");
+ cp1 += strlen(cp1);
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t')
+ ++pt;
+ while (*pt == ' ' || *pt == '\t')
+ ++pt;
+ ocp1 = pt;
+ }
+ else if (angle == -90.0) {
+ angle = -89.999;
+ (void)memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ strcpy(cp1, "-89.999 rotate ");
+ cp1 += strlen(cp1);
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t')
+ ++pt;
+ while (*pt == ' ' || *pt == '\t')
+ ++pt;
+ ocp1 = pt;
+ }
+ else if (angle == 0.0) {
+ (void)memcpy(cp1, ocp1, ptm1 - ocp1);
+ cp1 += ptm1 - ocp1;
+ while (*pt != '\0' && *pt != ' ' && *pt != '\t')
+ ++pt;
+ while (*pt == ' ' || *pt == '\t')
+ ++pt;
+ ocp1 = pt;
+ }
+ }
+ }
+ }
+ strcpy(cp1, ocp1);
+ if ((globals.debug & DBG_PS) && found) {
+ printf("String is now <%s>\n", cp);
+ printf("Found rotate string. Angle is %g degrees.\n", angle);
+ }
+
+ len = strlen(cp);
+ cp[len] = '\n';
+ NeWS_send(cp, len + 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawfileNeWS()
+
+ Arguments: cp - string with the postscript file pathname
+ psfile - file, already opened
+ Returns: (void)
+ Side-Effects: none
+
+ Description:
+ Postscript file containing the figure is opened and sent to the NeWS server.
+ Figure is outlined in case hairy code produces a SIGPIPE signal.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawfileNeWS(const char *cp, FILE *psfile)
+{
+ char buffer[1025];
+ int blen;
+ struct sigaction orig;
+
+ if (!NeWS_active) {
+ fclose(psfile);
+ return;
+ }
+
+ if (globals.debug & DBG_PS)
+ printf("printing file %s\n", cp);
+
+ sigpipe_error = False;
+ for (;;) {
+ blen = fread(buffer, sizeof(char), 1024, psfile);
+ if (blen == 0) break;
+ NeWS_send(buffer, blen);
+ if (sigpipe_error || (globals.ev.flags & NeWS_ev_mask))
+ break;
+ }
+ fclose(psfile);
+
+ if (sigpipe_error) {
+ fputs("NeWS died unexpectedly.\n", stderr);
+ destroyNeWS();
+ draw_bbox();
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ drawendNeWS()
+
+ Arguments: cp - string with indication of the end of the special
+ Returns: (void)
+
+ Description:
+ Sends the indication of end of the figure PostScript code.
+
++----------------------------------------------------------------------------*/
+
+static void
+drawendNeWS(const char *cp)
+{
+ if (!NeWS_active)
+ return;
+
+ if (globals.debug & DBG_PS)
+ puts("drawend sent to NeWS Server");
+ NeWS_send(cp, strlen(cp));
+ NeWS_send("\n", 1);
+}
+
+
+/*---------------------------------------------------------------------------*
+ beginheaderNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+beginheaderNeWS(void)
+{
+ static const char str[] = "Hsave /xdvi$doc exch def\n";
+
+ if (globals.debug & DBG_PS)
+ puts("Running beginheaderNeWS()");
+
+ if (NeWS_active) {
+ if (!NeWS_in_header)
+ XDVI_FATAL((stderr, "Internal error in beginheaderNeWS()."));
+ return;
+ }
+
+ if (globals.ev.flags & NEWS_MASK_HEADER)
+ longjmp(globals.ev.canit, 1);
+
+ NeWS_in_header = True;
+ NeWS_ev_mask = NEWS_MASK_HEADER;
+ ++NeWS_pending;
+ if (NeWS_in_doc)
+ NeWS_send("H", 1);
+ else {
+ NeWS_send(str, (sizeof str) - 1);
+ NeWS_in_doc = True;
+ }
+ NeWS_active = True;
+}
+
+
+/*---------------------------------------------------------------------------*
+ endheaderNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Prepares the PostScript interpreter for receipt of header code.
+
++----------------------------------------------------------------------------*/
+
+static void
+endheaderNeWS(void)
+{
+ static const char str[] = "stop\n%%xdvimark\n";
+
+ if (globals.debug & DBG_PS)
+ puts("Running endheaderNeWS()");
+
+ if (NeWS_active) {
+ NeWS_send(str, (sizeof str) - 1);
+ NeWS_active = False;
+ post_send();
+ waitack();
+ NeWS_in_header = False;
+ NeWS_ev_mask = NEWS_MASK_NORMAL;
+ }
+}
+
+
+/*---------------------------------------------------------------------------*
+ newdocNeWS()
+
+ Arguments: none
+ Returns: (void)
+
+ Description:
+ Clears out headers stored from the previous document.
+
++----------------------------------------------------------------------------*/
+
+static void
+newdocNeWS(void)
+{
+ static const char str[] = "H xdvi$doc restore stop\n%%xdvimark\n";
+
+ if (globals.debug & DBG_PS)
+ puts("Running newdocNeWS()");
+
+ if (NeWS_in_doc) {
+ ++NeWS_pending;
+ NeWS_send(str, (sizeof str) - 1);
+ NeWS_mag = NeWS_shrink = -1;
+ NeWS_in_doc = False;
+ }
+}
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* PS_NEWS */
diff --git a/Build/source/texk/xdvik/psnews.h b/Build/source/texk/xdvik/psnews.h
new file mode 100644
index 00000000000..4fe42e80550
--- /dev/null
+++ b/Build/source/texk/xdvik/psnews.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef PSNEWS_H_
+#define PSNEWS_H_
+
+extern Boolean initNeWS(void);
+
+#endif /* PSNEWS_H_ */
diff --git a/Build/source/texk/xdvik/read-mapfile.c b/Build/source/texk/xdvik/read-mapfile.c
new file mode 100644
index 00000000000..043d4bb1309
--- /dev/null
+++ b/Build/source/texk/xdvik/read-mapfile.c
@@ -0,0 +1,156 @@
+/*
+ This code was stolen from dvips (getpsinfo() in resident.c) for xdvi
+ use. The file itself does not carry any licensing info, except for
+ reference to dvips.h, which doesn't have a standart-type license
+ either. The code seems to be either in the public domain, or, in
+ the worst case, GPL.
+
+ - Nicolai Langfeldt, 21/2/1999
+
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "util.h"
+#include "read-mapfile.h"
+#include "dvi-draw.h" /* for add_T1_mapentry */
+#include <stdio.h>
+
+#ifdef T1LIB
+
+#include "kpathsea/tex-file.h"
+
+#define INLINE_SIZE 2048
+
+/*
+ * Read a dvips psfont map file. Return True if it was read ok,
+ * False otherwise.
+ */
+Boolean
+read_map_file(char *name)
+{
+ FILE *fp;
+ char *p;
+ char *specinfo;
+ char specbuf[500];
+ char *fullname;
+ int lineno = 0;
+ static char inline_buf[INLINE_SIZE];
+
+ /* Try first for xdvi specific file */
+ fullname = kpse_find_file(name, kpse_program_text_format, 0);
+ /* Then any fontmap file */
+ if (fullname == NULL) {
+ fullname = kpse_find_file(name, kpse_fontmap_format, 0);
+ }
+
+ if (fullname == NULL) {
+ XDVI_WARNING((stderr, "Could not find map file \"%s\".", name));
+ return False;
+ }
+
+ fp = XFOPEN(fullname, "r");
+ if (fp == NULL) {
+ XDVI_WARNING((stderr, "Could not open map file \"%s\": %s.\n", name, strerror(errno)));
+ return False;
+ }
+
+ while (fgets(inline_buf, INLINE_SIZE, fp) != NULL) {
+ char *TeXname = NULL;
+ char *PSname = NULL;
+ char *Fontfile = NULL;
+ char *Vectfile = NULL;
+ char *hdr_name = NULL;
+ specinfo = NULL;
+ specbuf[0] = 0;
+ lineno++;
+
+ /* One line at a time */
+ p = inline_buf;
+
+ if (*p < ' ' || *p == '*' || *p == '#' || *p == ';' || *p == '%')
+ continue;
+
+ while (*p) {
+ while (*p && *p <= ' ')
+ p++;
+ if (*p) {
+ /* Note: In dvips, this flag is set outside the loop
+ so that font files may be scanned/included as encoding files
+ (I guess it doesn't matter for dvips, but it does for xdvi ...)
+ */
+ boolean encoding_p = False;
+ if (*p == '"') { /* PostScript instructions? */
+ if (specinfo) {
+ strcat(specbuf, specinfo);
+ strcat(specbuf, " ");
+ }
+ specinfo = p + 1;
+
+ }
+ else if (*p == '<') { /* Header to download? */
+ if (p[1] == '<') { /* << means always full download, ignore */
+ p++;
+ }
+ else if (p[1] == '[') { /* <[ means an encoding */
+ p++;
+ encoding_p = True;
+ }
+ p++;
+ /* skip whitespace after < */
+ while (*p && *p <= ' ')
+ p++;
+
+ /* save start of header name */
+ hdr_name = p;
+
+ }
+ else if (TeXname) /* second regular word on line? */
+ PSname = p;
+
+ else /* first regular word? */
+ TeXname = p;
+
+ if (*p == '"') {
+ p++; /* find end of "..." word */
+ while (*p != '"' && *p)
+ p++;
+ }
+ else
+ while (*p > ' ') /* find end of anything else */
+ p++;
+
+ /* Terminate the substring we just identified */
+ if (*p)
+ *p++ = 0;
+
+ /* If we had a header we were downloading, figure out what to do;
+ couldn't do this above since we want to check the suffix. */
+ if (hdr_name) {
+ char *suffix = find_suffix(hdr_name);
+ if (encoding_p
+ || (suffix != NULL && strcmp(suffix, "enc") == 0)) {
+ Vectfile = hdr_name;
+ }
+ else {
+ Fontfile = hdr_name;
+ }
+ }
+ }
+ } /* while (*p) */
+
+ /* Line finished. Lookit what we got */
+ if (specinfo) {
+ strcat(specbuf, specinfo);
+ }
+
+ if (TeXname) {
+ add_T1_mapentry(lineno, fullname, TeXname, Fontfile, Vectfile, specinfo);
+ }
+
+ }
+ fclose(fp);
+ return True;
+}
+
+#endif /* T1LIB */
diff --git a/Build/source/texk/xdvik/read-mapfile.h b/Build/source/texk/xdvik/read-mapfile.h
new file mode 100644
index 00000000000..ed56eb49614
--- /dev/null
+++ b/Build/source/texk/xdvik/read-mapfile.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef DVIPS_H_
+#define DVIPS_H_
+
+extern Boolean read_map_file(char *filename);
+
+#endif /* DVIPS_H_ */
diff --git a/Build/source/texk/xdvik/search-internal.c b/Build/source/texk/xdvik/search-internal.c
new file mode 100644
index 00000000000..5c8f806d263
--- /dev/null
+++ b/Build/source/texk/xdvik/search-internal.c
@@ -0,0 +1,1734 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+/*
+ How dvi search works:
+
+ (1) Map the search string passed by the user from resource.text_encoding
+ to UTF-8 (currently only maps ISO_8859-1), and create a regexp from
+ the string if needed.
+
+ If case-insensitive matching is activated and regexp search is not
+ active, the search string is converted to lowercase. For regexp
+ searches, the flag available with regcomp to ignore case is used.
+
+ (2) Scan 2 adjacent pages (so that we can also find matches across page
+ boundaries), collecting the text into a char *buffer.
+ This involves the following steps:
+
+ - Map characters from wide_ubyte to uint32_t encoding (ucs-4),
+ using and Adobe names lookup table (for Postscript Type1
+ fonts) or font-specific character info (for Metafont fonts).
+
+ This step also maps accented glyphs to composite glyphs,
+ expands ligatures to separate characters (e.g. `ffi' to
+ `f'`f'`i'), and tries to detect word boundaries and line
+ breaks.
+
+ If case-insensitive matching is activated, the characters are
+ also lowercased in this step.
+
+ Optionally, hyphenation can be removed in this step.
+
+ Routine: do_char() in dvi-draw.c (must be in dvi_draw.c since
+ we need access to drawing-related stuff like `currinf' to get
+ information about the current font, position in the DVI file
+ etc.).
+
+ - Save the uint32_t characters into a char *buffer, mapping to
+ utf-8.
+
+ (3) Search the buffer from (2) for the string from (1). If a match
+ has been found, the page is scanned again to store the bounding
+ box information of the matched text for highlighting it.
+*/
+
+
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#define SWITCH_TO_UTF8 1
+
+#if HAVE_REGEX_H
+#include <regex.h>
+#endif
+
+#if HAVE_ICONV_H
+#include <iconv.h>
+#endif
+
+#include <locale.h>
+
+#if USE_LANGINFO
+#include <langinfo.h>
+#endif
+
+#include <ctype.h>
+
+#include "dvi-init.h" /* for total_pages */
+#include "dvi-draw.h"
+#include "search-internal.h"
+
+#include "search-dialog.h"
+#include "message-window.h"
+#include "statusline.h"
+#include "events.h"
+#include "encodings.h"
+#include "pagesel.h"
+#include "events.h"
+#include "util.h"
+#include "x_util.h"
+#include "string-utils.h"
+#include "mag.h"
+#include "pagehist.h"
+
+#define DEBUG_SEARCH 0
+/* #define MATCH_HIGHLIGHT_INVERTED 1 */
+
+
+/* margins for highlighting the match */
+const int BBOX_LOWER_MARGIN = 2;
+const int BBOX_UPPER_MARGIN = 1;
+
+#if 0
+#define GET_BBOX(bbox, shrink, x, y, w, h) \
+ x = (bbox.ulx / (double)shrink + 0.5) - BBOX_UPPER_MARGIN; \
+ y = (bbox.uly / (double)shrink + 0.5) - BBOX_UPPER_MARGIN; \
+ w = ((bbox.lrx - bbox.ulx) / (double)shrink) + 0.5 \
+ + BBOX_UPPER_MARGIN + BBOX_LOWER_MARGIN + 1; \
+ h = ((bbox.lry - bbox.uly) / (double)shrink) + 0.5 \
+ + BBOX_UPPER_MARGIN + BBOX_LOWER_MARGIN + 2;
+#endif /* 0 */
+/* use integer arithmetic */
+#define GET_BBOX(bbox, shrink, x, y, w, h) \
+ x = (bbox.ulx + shrink / 2) / shrink - BBOX_UPPER_MARGIN; \
+ y = (bbox.uly + shrink / 2) / shrink - BBOX_UPPER_MARGIN; \
+ w = (bbox.lrx - bbox.ulx + shrink - 1) / shrink \
+ + BBOX_UPPER_MARGIN + BBOX_LOWER_MARGIN + 1; \
+ h = (bbox.lry - bbox.uly + shrink - 1) / shrink \
+ + BBOX_UPPER_MARGIN + BBOX_LOWER_MARGIN + 2;
+
+/* access from drawing routines */
+static struct word_info *m_info = NULL;
+static int m_match_page = -1;
+
+/* Force restarting search if user switches pages. E.g. if
+ the current match is the last of 3 matches on the page,
+ and user re-selects the page, the search should start again
+ with match 1. Similarly, if current page is second of two
+ pages scanned, and user clicks on first, search shouldn't continue
+ on second page but restart on current one.
+*/
+static Boolean m_changed_page = False;
+
+static Boolean m_highlight_region_changed = True;
+
+void
+search_signal_page_changed(void)
+{
+ m_changed_page = True;
+}
+
+
+static void
+reset_info(struct word_info *w_info)
+{
+ if (w_info == NULL)
+ return;
+
+ free(w_info->txt_buf);
+ w_info->txt_buf = NULL;
+ w_info->txt_buf_size = 0;
+ w_info->curr_buf_idx = 0;
+
+ free(w_info->bboxes);
+ w_info->bboxes = NULL;
+ w_info->bboxes_size = 0;
+ w_info->bboxes_idx = 0;
+
+ m_highlight_region_changed = True;
+}
+
+
+static void
+generate_highlight_expose(const struct word_info *info)
+{
+ int x1 = INT_MAX, y1 = INT_MAX, x2 = 0, y2 = 0;
+ size_t i;
+ for (i = 0; info->bboxes != NULL && i <= info->bboxes_idx && info->bboxes[i].ulx < INT_MAX; i++) {
+ if (info->bboxes[i].ulx < x1)
+ x1 = info->bboxes[i].ulx;
+ if (info->bboxes[i].uly < y1)
+ y1 = info->bboxes[i].uly;
+ if (info->bboxes[i].lrx > x2)
+ x2 = info->bboxes[i].lrx;
+ if (info->bboxes[i].lry > y2)
+ y2 = info->bboxes[i].lry;
+ }
+#if 0
+ fprintf(stderr, "region for exposure: %d,%d to %d,%d\n",
+ x1, y1, x2, y2);
+#endif /* 0 */
+ x1 -= MAX(BBOX_UPPER_MARGIN, BBOX_LOWER_MARGIN) - 2;
+ y1 -= MAX(BBOX_UPPER_MARGIN, BBOX_LOWER_MARGIN) - 2;
+ x2 += MAX(BBOX_UPPER_MARGIN, BBOX_LOWER_MARGIN) + 2;
+ y2 += MAX(BBOX_UPPER_MARGIN, BBOX_LOWER_MARGIN) + 2;
+ clearexpose(&mane, x1, y1, x2 - x1, y2 - y1);
+}
+
+static void
+draw_bboxes(const struct word_info *info)
+{
+ size_t i;
+ static GC bboxGC = 0;
+ static Boolean highlight_inverted_bak;
+
+ if (bboxGC != 0 && highlight_inverted_bak != resource.match_highlight_inverted) {
+ XFreeGC(DISP, bboxGC);
+ bboxGC = 0;
+ }
+ highlight_inverted_bak = resource.match_highlight_inverted;
+
+ if (resource.match_highlight_inverted) {
+ if (MAGNIFIER_ACTIVE && !INSIDE_MANE_WIN)
+ return;
+
+ TRACE_FIND((stderr, "-- EXPOSED region: x %d, y %d, w %d, h %d",
+ globals.win_expose.min_x, globals.win_expose.min_y, globals.win_expose.max_x - globals.win_expose.min_x, globals.win_expose.max_y - globals.win_expose.min_y));
+
+ if (bboxGC == 0) {
+ XGCValues values;
+ unsigned long valuemask;
+
+ values.function = GXinvert; /* was: GXxor; see bug #850788 */
+ if (values.function == GXinvert) {
+ valuemask = GCFunction;
+ }
+ else {
+ values.foreground = WhitePixelOfScreen(SCRN) ^ BlackPixelOfScreen(SCRN);
+/* fprintf(stderr, "foreground: 0x%lx, white pixel: 0x%lx, black pixel: 0x%lx\n", */
+/* values.foreground, WhitePixelOfScreen(SCRN), BlackPixelOfScreen(SCRN)); */
+ valuemask = GCFunction | GCForeground;
+ }
+ bboxGC = XCreateGC(DISP, XtWindow(globals.widgets.top_level), valuemask, &values);
+ }
+ }
+ else if (bboxGC == 0) {
+ XGCValues values;
+ values.function = GXcopy;
+ values.line_width = 2;
+ values.cap_style = CapRound;
+ values.foreground = resource.hl_Pixel;
+ values.background = resource.back_Pixel;
+ bboxGC = XCreateGC(DISP, XtWindow(globals.widgets.top_level),
+ GCFunction | GCLineWidth | GCCapStyle | GCForeground | GCBackground, &values);
+ }
+
+ TRACE_FIND((stderr, "bboxes_idx: %lu", (unsigned long)info->bboxes_idx));
+ for (i = 0; info->bboxes != NULL && i <= info->bboxes_idx && info->bboxes[i].ulx < INT_MAX; i++) {
+ int x, y, w, h;
+
+ if (info->bboxes[i].ulx > 10000 || info->bboxes[i].uly > 10000) {
+ TRACE_FIND((stderr, "skipping box: x %d, y %d",
+ info->bboxes[i].ulx, info->bboxes[i].uly));
+ continue;
+ }
+
+ GET_BBOX(info->bboxes[i], currwin.shrinkfactor, x, y, w, h);
+ TRACE_FIND((stderr, "DRAWING box: x %d, y %d, w %d, h %d; shrink: %d",
+ x, y, w, h, currwin.shrinkfactor));
+ if (resource.match_highlight_inverted) {
+ if (clip_region(&x, &y, &w, &h)) {
+ TRACE_FIND((stderr, "CLIPPED box: x %d, y %d, w %d, h %d",
+ x, y, w, h));
+ TEST_DELAY("Redrawing BBOX ............... ");
+ XFillRectangle(DISP, mane.win, bboxGC, x, y, w, h);
+ TEST_DELAY("Inverting BBOX ............... ");
+ }
+ }
+ /* XDrawRectangle(DISP, mane.win, globals.gc.high, x, y, w + 0, h + 0); */
+ /* clearexpose(&mane, x, y, w + 3, h + 3); */
+ /* XDrawRectangle(DISP, mane.win, globals.gc.high, x, y, w + 2, h + 2); */
+ /* XDrawRectangle(DISP, mane.win, globals.gc.high, x + 1, y + 1, w, h); */
+ else {
+ static XPoint points[5] = { {0,0}, {0,0}, {0,0}, {0,0}, {0,0} };
+
+ h++;
+
+ points[0].x = x;
+ points[0].y = y;
+
+ points[1].x = w;
+
+ points[2].y = h;
+
+ points[3].x = -w;
+
+ points[4].y = -h;
+
+ XDrawLines(DISP, mane.win, bboxGC, points, 5, CoordModePrevious);
+ }
+
+ if (!MAGNIFIER_ACTIVE) {
+ /* note: inverted y_max y_min, since we want to display the full box here */
+ scroll_page_if_needed(x + w, x, y + h, y);
+ }
+ }
+}
+
+/* return true if we have a match on page pageno */
+Boolean
+search_have_match(int pageno)
+{
+/* fprintf(stderr, "pageno: %d --- m_info: %p\n", pageno, m_info); */
+/* fprintf(stderr, "m_match_page: %d\n", m_match_page); */
+ return m_info != NULL && m_match_page == pageno;
+}
+
+/* TODO: Speed this up, by doing something like bsearch? */
+/*
+ Returns 2 if we're at the 1st or last character of the bbox, 1 if
+ inside the bbox, and 0 else (currently the return value 2 is unused).
+*/
+int
+search_inside_bbox_match(int x, int y)
+{
+ size_t i;
+
+ ASSERT(m_info != NULL, "inside_match musn't be called with m_info == NULL!");
+ TRACE_FIND((stderr, "m_info->bboxes: %p; idx: %lu", (void *)m_info->bboxes, (unsigned long)m_info->bboxes_idx));
+ for (i = 0; m_info->bboxes != NULL && i <= m_info->bboxes_idx && m_info->bboxes[i].ulx < INT_MAX; i++) {
+ TRACE_FIND((stderr, "inside_bbox_match: %d, %d", x, y));
+ TRACE_FIND((stderr, "x: %d, y: %d, x2: %d, y2: %d",
+ (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5),
+ (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5),
+ (int)(m_info->bboxes[i].lrx / (double)currwin.shrinkfactor + 0.5),
+ (int)(m_info->bboxes[i].lry / (double)currwin.shrinkfactor + 0.5)));
+
+ if (x >= (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5)
+ && x <= (int)(m_info->bboxes[i].lrx / (double)currwin.shrinkfactor + 0.5)
+ && y >= (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5)
+ && y <= (int)(m_info->bboxes[i].lry / (double)currwin.shrinkfactor + 0.5)) {
+ TRACE_FIND((stderr, "%d == %d",
+ x - 1, (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5)));
+ TRACE_FIND((stderr, "%d == %d",
+ y - 1, (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5)));
+ if (x - 1 == (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5)
+ && y - 1 == (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5))
+ return 2;
+ else
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+search_draw_inverted_regions(void)
+{
+ if (m_info != NULL) {
+ draw_bboxes(m_info);
+ }
+}
+
+
+/*
+ * shift everything in info down by 1 pages, so that info for page 1 becomes
+ * info for page 0.
+ */
+static void
+shift_info_down(struct search_info *searchinfo, struct word_info *info, struct page_mapping *page_mapping)
+{
+ size_t initial_offset = 0;
+ if (page_mapping[0].offset != -1) { /* remember value */
+ initial_offset = page_mapping[0].offset;
+ }
+
+ if (globals.debug & DBG_FIND) {
+ int i;
+ fprintf(stderr, "current page_mapping:\n");
+ for (i = 0; i < 2; i++) {
+ fprintf(stderr, "%d: %d\n", page_mapping[i].pageno, page_mapping[i].offset);
+ }
+ }
+
+ TRACE_FIND((stderr, "initial offset: %lu", (unsigned long)initial_offset));
+
+ page_mapping[0].offset = page_mapping[1].offset - initial_offset;
+ page_mapping[0].pageno = page_mapping[1].pageno;
+ ASSERT(page_mapping[0].offset >= 0, "new index mustn't be negative!\n");
+ page_mapping[1].offset = page_mapping[1].pageno = -1;
+
+ TRACE_FIND((stderr, "new val at 0: %d; curr_idx: %lu, len: %lu",
+ page_mapping[0].offset,
+ (unsigned long)(info->curr_buf_idx - initial_offset),
+ (unsigned long)(strlen(info->txt_buf + initial_offset))));
+
+ /* move the text buffer down, and update its current index accordingly */
+ ASSERT(info->curr_buf_idx >= initial_offset, "info->curr_buf_idx mustn't become negative!");
+ memmove(info->txt_buf, info->txt_buf + initial_offset, info->curr_buf_idx - initial_offset + 1);
+ info->curr_buf_idx -= initial_offset;
+ TRACE_FIND((stderr, "new index: %lu", (unsigned long)info->curr_buf_idx));
+
+ searchinfo->from_pos -= initial_offset;
+ searchinfo->to_pos -= initial_offset;
+ if (searchinfo->from_pos < 0)
+ searchinfo->from_pos = 0;
+ if (searchinfo->to_pos < 0)
+ searchinfo->to_pos = 0;
+ TRACE_FIND((stderr, "new offsets: from=%d, to=%d", searchinfo->from_pos, searchinfo->to_pos));
+}
+
+/*
+ * shift everything in info up by 1 page, so that info for page 0 becomes info
+ * for page 1.
+ */
+static void
+shift_info_up(struct word_info *info, struct page_mapping *page_mapping)
+{
+ if (globals.debug & DBG_FIND) {
+ int i;
+ fprintf(stderr, "current page_mapping:\n");
+ for (i = 0; i < 2; i++) {
+ fprintf(stderr, "%d: %d\n", page_mapping[i].pageno, page_mapping[i].offset);
+ }
+ }
+
+ ASSERT(page_mapping[0].offset > 0, "info->curr_buf_idx mustn't become negative!");
+ info->curr_buf_idx = page_mapping[0].offset;
+ TRACE_FIND((stderr, "new index: %lu", (unsigned long)info->curr_buf_idx));
+
+ page_mapping[1].offset = page_mapping[0].offset;
+ page_mapping[1].pageno = page_mapping[0].pageno;
+ page_mapping[0].offset = page_mapping[0].pageno = -1;
+
+}
+
+static void
+append_to_info(struct word_info *info, const char *str)
+{
+ size_t len = strlen(str);
+ size_t new_size = info->txt_buf_size;
+ while (len >= new_size) { /* space for trailing 0 */
+ new_size++;
+ }
+ if (new_size > info->txt_buf_size) {
+ info->txt_buf_size = new_size;
+ info->txt_buf = xrealloc(info->txt_buf, sizeof *(info->txt_buf) * info->txt_buf_size);
+ }
+ memcpy(info->txt_buf + info->curr_buf_idx, str, len + 1); /* also copy trailing 0 */
+ info->curr_buf_idx += len;
+}
+
+/* append info2 to info1, enlarging info1 as needed. */
+static void
+append_info(struct word_info *info1, const struct word_info *info2)
+{
+ if (info2->txt_buf_size > 0) {
+ info1->txt_buf = xrealloc(info1->txt_buf, sizeof *(info1->txt_buf)
+ * (info1->txt_buf_size + info2->txt_buf_size));
+ memcpy(info1->txt_buf + info1->curr_buf_idx, info2->txt_buf, info2->txt_buf_size);
+ info1->txt_buf_size += info2->txt_buf_size;
+ info1->curr_buf_idx += info2->curr_buf_idx;
+ }
+}
+
+/* prepend info1 to info2, enlarging info2 as needed. */
+static void
+prepend_info(const struct word_info *info1, struct word_info *info2)
+{
+ if (info1->txt_buf_size > 0) {
+ info2->txt_buf = xrealloc(info2->txt_buf, sizeof *(info2->txt_buf)
+ * (info2->txt_buf_size + info1->txt_buf_size + 1));
+ memmove(info2->txt_buf + info1->curr_buf_idx, info2->txt_buf, info2->curr_buf_idx);
+ info2->txt_buf[info1->curr_buf_idx + info2->curr_buf_idx] = '\0';
+ memcpy(info2->txt_buf, info1->txt_buf, info1->curr_buf_idx);
+ /* TRACE_FIND((stderr, "prepend_info: info2->txt_buf is: |%s|", info2->txt_buf)); */
+ info2->txt_buf_size += info1->txt_buf_size;
+ info2->curr_buf_idx += info1->curr_buf_idx;
+ }
+}
+
+#if HAVE_REGEX_H
+/* convert the encoding part (between the `.' and the `@') of the
+ locale string passed as argument to UTF-8, and return the result
+ in a newly allocated string which the caller is responsible for
+ free()ing.
+*/
+static char *
+locale_to_utf8(const char *locale)
+{
+ char *utf8_locale = xstrdup(locale);
+ char *ptr;
+ if ((ptr = strchr(utf8_locale, '.')) != NULL) {
+ char *ptr2, *rest = "";
+ if ((ptr2 = strchr(utf8_locale, '@')) != NULL)
+ rest = xstrdup(ptr2);
+
+ utf8_locale = xrealloc(utf8_locale,
+ ptr - utf8_locale + strlen(".utf8") + strlen(rest) + 1);
+ *ptr = '\0';
+ utf8_locale = strcat(utf8_locale, ".utf8");
+ if (ptr2 != NULL) {
+ utf8_locale = strcat(utf8_locale, rest);
+ free(rest);
+ }
+ }
+ else {
+ utf8_locale = xstrcat(utf8_locale, ".utf8");
+ }
+ return utf8_locale;
+}
+#endif /* HAVE_REGEX_H */
+
+static Boolean
+is_utf8_ideograph(const unsigned char *p)
+{
+ int len;
+ uint32_t ucs4;
+
+ if ((len = utf8_to_ucs4((const char *)p, &ucs4, strlen((const char*)p))) <= 0)
+ return False;
+
+ return is_ideograph(ucs4);
+}
+
+
+static void
+dump_buffer(const struct word_info *info, size_t offset, FILE *fp, outputFormatT fmt)
+{
+ size_t i = offset, len, tot_len;
+
+ if (info->txt_buf == NULL)
+ return;
+
+ tot_len = strlen(info->txt_buf);
+ while (i < tot_len) {
+ if (fmt == FMT_UTF8) { /* just dump as-is */
+ fputc(info->txt_buf[i++], fp);
+ }
+ else { /* convert to iso-latin1, rendering unknown characters as `?' */
+ uint32_t ucs4;
+ const char *ret;
+
+ /* first apply normalization heurisitcs also used by search */
+ len = utf8_to_ucs4(info->txt_buf + i, &ucs4, strlen(info->txt_buf + i));
+ if ((ret = search_normalize_chars(ucs4)) != NULL)
+ fputs(ret, fp);
+ else if (ucs4 <= 0xff) /* in iso-latin1 range */
+ fputc((unsigned char)ucs4, fp);
+ else
+ fprintf(fp, "\\%.4lX", (unsigned long)ucs4);
+ i += len;
+ }
+ }
+}
+
+static void
+scan_page(FILE *fp, int pageno, struct word_info *w_info)
+{
+ off_t pos_save;
+ static ubyte my_scan_buffer[DVI_BUFFER_LEN];
+ struct drawinf currinf_save;
+ struct scan_info info;
+ ubyte maxchar_save;
+
+ reinit_text_scan(); /* to reset scanning heuristics (linebreaks etc.) */
+ info.data = (void *)w_info;
+ info.geom_special = NULL; /* no procedure here */
+
+ /* Save file position */
+ pos_save = save_file_status(globals.dvi_file.bak_fp, &currinf_save, &maxchar_save);
+
+ lseek(fileno(fp), pageinfo_get_offset(pageno), SEEK_SET);
+ memset((char *)&currinf.data, 0, sizeof currinf.data);
+ currinf.tn_table_len = TNTABLELEN;
+ currinf.tn_table = tn_table;
+ currinf.tn_head = tn_head;
+
+ /* point currinf to our own buffer: */
+ G_dvi_buf_ptr = my_scan_buffer;
+
+ currinf.pos = currinf.end = G_dvi_buf_ptr;
+ currinf.virtual = NULL;
+
+ geom_scan(text_do_char, fp, &info, pageno);
+
+ /* Restore file status. */
+ restore_file_status(globals.dvi_file.bak_fp, currinf_save, maxchar_save, pos_save);
+}
+
+
+static Boolean
+do_scan_page(struct word_info *w_info, struct search_settings *settings,
+ struct page_mapping *page_mapping, int buffer_offset, int pageno,
+ searchDirectionT direction)
+{
+ struct word_info page_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, True, False };
+ page_info.settings = settings;
+ ASSERT(buffer_offset >= 0, "buffer_offset must have been initialized");
+ page_info.buffer_offset = buffer_offset;
+ TRACE_FIND((stderr, "scanning page: %d; from_pos: %d", pageno, settings->searchinfo->from_pos));
+
+ if (read_events(EV_NOWAIT) & EV_GE_FIND_CANCEL) {
+ TRACE_FIND((stderr, "interrupted!!"));
+ return False;
+ }
+
+ scan_page(globals.dvi_file.bak_fp, pageno, &page_info);
+
+ /* TRACE_FIND((stderr, "scanned buffer of length %d on page %d; contents: |%s|", */
+ /* page_info.curr_buf_idx, pageno, page_info.txt_buf)); */
+
+ /* terminate page */
+ append_to_info(&page_info, "\n");
+ if (direction == SEARCH_DOWN) {
+ /* append to existing info */
+ append_info(w_info, &page_info);
+ page_mapping->offset = w_info->curr_buf_idx;
+ }
+ else {
+ prepend_info(&page_info, w_info);
+ /* TRACE_FIND((stderr, "buffer after prepending: |%s|", w_info->txt_buf)); */
+ page_mapping->offset = page_info.curr_buf_idx;
+ }
+ page_mapping->pageno = pageno;
+
+ return True;
+}
+
+#if HAVE_REGEX_H
+static void
+report_regexp_error(int errcode, regex_t *regex, const char *term, int flag)
+{
+ size_t n = regerror(errcode, regex, NULL, 0);
+ char *err_buf = xmalloc(n);
+ regerror(errcode, regex, err_buf, n);
+ XBell(DISP, 0);
+ popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_ERR,
+ NULL,
+ "Could not %s regular expression \"%s\": %s\n",
+ flag == 0 ? "compile" : "execute",
+ term, err_buf);
+ free(err_buf);
+}
+#endif /* HAVE_REGEX_H */
+
+static void
+try_match(const struct word_info *info,
+ const struct search_settings *settings,
+ struct search_info *searchinfo)
+{
+ char *res = NULL;
+ size_t from_pos = 0;
+
+ ASSERT(info->curr_buf_idx == strlen(info->txt_buf), "");
+ TRACE_FIND((stderr, "buffer index: %lu, len: %lu; from: %lu",
+ (unsigned long)info->curr_buf_idx,
+ (unsigned long)strlen(info->txt_buf),
+ (unsigned long)searchinfo->from_pos));
+ if (searchinfo->from_pos != -1)
+ from_pos = searchinfo->from_pos;
+
+ if (settings->direction == SEARCH_DOWN) {
+ TRACE_FIND((stderr, "trying to match |%s| from %lu; total: %lu",
+ settings->utf8_term,
+ (unsigned long)from_pos,
+ (unsigned long)strlen(info->txt_buf)));
+
+ res = strstr(info->txt_buf + from_pos, settings->utf8_term);
+ }
+ else {
+ size_t curr_pos = 0;
+ char *res_bak = NULL;
+
+ TRACE_FIND((stderr, "UP; trying to match |%s| from %lu, %lu",
+ settings->utf8_term,
+ (unsigned long)curr_pos, (unsigned long)from_pos));
+ TRACE_FIND((stderr, "buf: |%s|", info->txt_buf + curr_pos));
+ while (curr_pos <= from_pos) {
+ res_bak = res;
+ res = strstr(info->txt_buf + curr_pos, settings->utf8_term);
+ if (res != NULL) {
+ curr_pos = res - info->txt_buf + strlen(settings->utf8_term);
+ }
+ else {
+ break;
+ }
+ }
+ res = res_bak;
+ }
+ if (res != NULL) {
+ searchinfo->have_match = True;
+ searchinfo->from_pos = res - info->txt_buf;
+ searchinfo->to_pos = searchinfo->from_pos + strlen(settings->utf8_term);
+ }
+ else {
+ searchinfo->have_match = False;
+ }
+}
+
+#if HAVE_REGEX_H
+static Boolean
+try_regexp_match(regex_t *regex,
+ const struct word_info *info,
+ const struct search_settings *settings,
+ struct search_info *searchinfo)
+{
+ int have_match;
+ regmatch_t re_match;
+ size_t from_pos = 0;
+ Boolean retval = True;
+
+#if SWITCH_TO_UTF8
+ /* switch to UTF-8 encoding, as for regcomp() */
+ char *utf8_locale = locale_to_utf8(globals.orig_locale);
+ TRACE_FIND((stderr, "current locale: |%s|, utf8 version: |%s|", globals.orig_locale, utf8_locale));
+ setlocale(LC_ALL, utf8_locale);
+#endif
+
+ re_match.rm_so = re_match.rm_eo = -1;
+
+ if (searchinfo->from_pos != -1)
+ from_pos = searchinfo->from_pos;
+
+ if (settings->direction == SEARCH_DOWN) {
+ Boolean search_again = True;
+
+ while (search_again && from_pos < info->curr_buf_idx) {
+ searchinfo->have_match = False;
+ search_again = False;
+
+/* TRACE_FIND((stderr, "search string: |%s|, from_pos: %d", info->txt_buf + from_pos, from_pos)); */
+ have_match = regexec(regex, info->txt_buf + from_pos, 1, &re_match, 0);
+
+ if (have_match == 0) { /* match */
+ TRACE_FIND((stderr, "match from %d to %d", (int)re_match.rm_so, (int)re_match.rm_eo));
+ if (re_match.rm_so == re_match.rm_eo) { /* skip zero-length matches */
+ from_pos += re_match.rm_so + 1;
+ search_again = True;
+ }
+ else {
+ searchinfo->from_pos = re_match.rm_so + from_pos;
+ searchinfo->to_pos = re_match.rm_eo + from_pos;
+ searchinfo->have_match = True;
+ }
+ }
+ else if (have_match != REG_NOMATCH) { /* error */
+ report_regexp_error(have_match, regex, settings->term, 1);
+ retval = False;
+ break;
+ }
+ }
+ }
+ else { /* searching backwards */
+ size_t curr_pos = 0, prev_pos = 0;
+ regmatch_t re_match_bak;
+ Boolean search_again = True;
+ searchinfo->have_match = False;
+ TRACE_FIND((stderr, "UP; trying to match |%s| from %lu, %lu",
+ settings->utf8_term,
+ (unsigned long)curr_pos, (unsigned long)from_pos));
+
+ re_match_bak.rm_so = re_match_bak.rm_eo = -1;
+
+ while (search_again && curr_pos <= from_pos) {
+ search_again = False;
+
+ /* remember previous match data */
+ re_match_bak.rm_so = prev_pos + re_match.rm_so;
+ re_match_bak.rm_eo = prev_pos + re_match.rm_eo;
+
+ TRACE_FIND((stderr, "backup values: %d, %d; curr_pos: %lu",
+ (int)re_match_bak.rm_so, (int)re_match_bak.rm_eo, (unsigned long)curr_pos));
+
+ /* TRACE_FIND((stderr, "text buf: |%s|", info->txt_buf + curr_pos)); */
+ have_match = regexec(regex, info->txt_buf + curr_pos, 1, &re_match, 0);
+ while (have_match == 0 && re_match.rm_so == re_match.rm_eo) { /* skip zero-length matches */
+ have_match = regexec(regex, info->txt_buf + ++curr_pos, 1, &re_match, 0);
+ }
+
+
+ if (have_match == 0) { /* match */
+ TRACE_FIND((stderr, "match from %d to %d", (int)re_match.rm_so, (int)re_match.rm_eo));
+ TRACE_FIND((stderr, "updating pos: %lu -> %lu; from_pos: %lu",
+ (unsigned long)curr_pos,
+ (unsigned long)(curr_pos + re_match.rm_eo),
+ (unsigned long)from_pos));
+ prev_pos = curr_pos;
+ curr_pos += re_match.rm_eo;
+ search_again = True;
+ }
+ else if (have_match != REG_NOMATCH) { /* error */
+ report_regexp_error(have_match, regex, settings->term, 1);
+ retval = False;
+ break;
+ }
+ }
+ if (retval) {
+ re_match.rm_so = re_match_bak.rm_so;
+ re_match.rm_eo = re_match_bak.rm_eo;
+
+ if (re_match.rm_so != -1) {
+ TRACE_FIND((stderr, "remembering from-to: %d - %d", (int)re_match.rm_so, (int)re_match.rm_eo));
+ searchinfo->from_pos = re_match.rm_so;
+ searchinfo->to_pos = re_match.rm_eo;
+ searchinfo->have_match = True;
+ }
+ }
+ }
+
+#if SWITCH_TO_UTF8
+ /* switch back to original encoding */
+ setlocale(LC_ALL, globals.orig_locale);
+ setlocale(LC_NUMERIC, "C");
+ free(utf8_locale);
+#endif
+
+ return retval;
+}
+#endif /* HAVE_REGEX_H */
+
+/* Erase exising highlighting. TODO: Move this into dvi-draw so that
+ there's no big delay between erasing and drawing the next marker.
+*/
+static void
+erase_match_highlighting(struct word_info *info, Boolean flag)
+{
+ size_t i;
+
+ if (info == NULL || (MAGNIFIER_ACTIVE && !INSIDE_MANE_WIN))
+ return;
+
+ for (i = 0; info->bboxes != NULL && i <= info->bboxes_idx && info->bboxes[i].ulx < INT_MAX; i++) {
+ int x, y, w, h;
+ GET_BBOX(info->bboxes[i], currwin.shrinkfactor, x, y, w, h);
+ if (resource.match_highlight_inverted) {
+ if (flag || m_highlight_region_changed) {
+ clearexpose(&mane, x, y, w, h);
+ }
+ else if (clip_region(&x, &y, &w, &h)) {
+ TRACE_FIND((stderr, "ERASING box: x %d, y %d, w %d, h %d",
+ x, y, w, h));
+ TEST_DELAY("Showing BBOX ............... ");
+ XClearArea(DISP, mane.win, x, y, w, h, False);
+ TEST_DELAY("Clearing BBOX ............... ");
+ }
+ }
+ else if (flag) {
+ /* erase only the existing marks, not the entire bounding box, to avoid flashing of
+ the text inside the bounding box. 1 pixel added to w, h just to make sure in case of
+ rounding errors. */
+ h++;
+ clearexpose(&mane, x - 1, y - 1, 2, h + 2);
+ clearexpose(&mane, x - 1, y - 1, w + 2, 2);
+ clearexpose(&mane, x + w - 1, y - 1, 2, h + 2);
+ clearexpose(&mane, x - 1, y + h - 1, w + 2, 2);
+ }
+ }
+ if (flag) {
+ reset_info(info);
+ info = NULL;
+ }
+ else
+ m_highlight_region_changed = False;
+}
+
+static void
+highlight_match(struct search_settings *settings,
+ const struct word_info *w_info,
+ const struct page_mapping *page_mapping)
+{
+ const int context = 10;
+ int match_page, i, j = 0;
+ static struct word_info curr_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, True, False, False };
+ struct search_info *searchinfo = settings->searchinfo;
+ Boolean match_wrapped = False;
+
+ curr_info.settings = settings;
+ curr_info.page_mapping = page_mapping;
+
+ TRACE_FIND((stderr, "MATCH from pos %d to %d:",
+ searchinfo->from_pos, searchinfo->to_pos));
+
+ if (globals.debug & DBG_FIND) {
+ fprintf(stderr, "current page_mapping:\n");
+ for (i = 0; i < 2; i++) {
+ fprintf(stderr, "%d: %d\n", page_mapping[i].pageno, page_mapping[i].offset);
+ }
+ }
+
+ TRACE_FIND((stderr, "to_pos: %d, %d", searchinfo->to_pos, page_mapping[0].offset));
+ if (searchinfo->from_pos < page_mapping[0].offset) {
+ match_page = page_mapping[0].pageno;
+ if (searchinfo->to_pos > page_mapping[0].offset) {
+ match_wrapped = True;
+ }
+ }
+ else {
+ ASSERT(searchinfo->from_pos < page_mapping[1].offset, "to_pos should be smaller than page_mapping[1].offset!");
+ match_page = page_mapping[1].pageno;
+ if (searchinfo->to_pos > page_mapping[1].offset) {
+ match_wrapped = True;
+ }
+ }
+ if (match_wrapped)
+ statusline_print(STATUS_MEDIUM, "Match from page %d to %d", match_page + 1, match_page + 2);
+ else
+ statusline_print(STATUS_MEDIUM, "Match on page %d", match_page + 1);
+
+ if (globals.debug & DBG_FIND) {
+ fprintf(stderr, "*** match_page: %d, adding: %d\n", match_page, searchinfo->page_offset);
+
+ for (j = searchinfo->from_pos - context; j < searchinfo->from_pos; j++) {
+ if (j >= 0)
+ fputc(w_info->txt_buf[j], stderr);
+ else
+ fputc(' ', stderr);
+ }
+ fputs("\n >>", stderr);
+ for (j = searchinfo->from_pos; j < searchinfo->to_pos; j++) {
+ fputc(w_info->txt_buf[j], stderr);
+ }
+ fputs("<<\n ", stderr);
+ for (j = searchinfo->from_pos; j < searchinfo->to_pos; j++) {
+ fputc(' ', stderr);
+ }
+ for (j = searchinfo->to_pos; j < (int)w_info->curr_buf_idx; j++) {
+ fputc(w_info->txt_buf[j], stderr);
+ if (w_info->txt_buf[j] == '\n')
+ break;
+ }
+ fputc('\n', stderr);
+ }
+
+ if (match_page != current_page) {
+ goto_page(match_page, resource.keep_flag ? NULL : home, False);
+ page_history_insert(match_page);
+/* globals.ev.flags |= EV_NEWPAGE; */
+ }
+ /* don't raise the window - this can obscure the search popup */
+ /* XMapRaised(DISP, XtWindow(globals.widgets.top_level)); */
+
+ /* this erases contents of m_info, so be careful - contents of curr_info
+ will be indirectly erased by this ... */
+ erase_match_highlighting(m_info, True);
+
+ /* now rescan the page to get bounding box info for the match */
+ scan_page(globals.dvi_file.bak_fp, match_page, &curr_info);
+ m_info = &curr_info;
+
+ m_match_page = match_page;
+
+ do_autoscroll = True; /* enable scrolling to match */
+ /* create an expose event so that the region gets highlighted */
+ if (m_info != NULL) {
+ generate_highlight_expose(m_info);
+ }
+}
+
+#if HAVE_REGEX_H
+
+/*
+ * A mapping of Perl-style character classes to POSIX-style character classes.
+ */
+static struct perl2posix_mapping {
+ const char *perl_class;
+ const char *posix_class;
+} perl2posix_map[] = {
+ { "\\w", "[[:alnum:]]" },
+ { "\\W", "[^[:alnum:]]" },
+ { "\\d", "[[:digit:]]" },
+ { "\\D", "[^[:digit:]]" },
+ { "\\s", "[[:space:]]" },
+ { "\\S", "[^[:space:]]" },
+ { NULL, NULL } /* terminate */
+};
+
+/*
+ * Convert `perl_regex', a regexp using Perl-style character classes,
+ * to a regexp using POSIX-style character classes. Return the latter
+ * in freshly allocated memory, which the caller is responsible to free().
+ * Uses the perl2posix_map table.
+ */
+static char *
+perl2posix(const char *perl_regex)
+{
+ char *posix_regex = xstrdup(perl_regex);
+ size_t i;
+
+ for (i = 0; perl2posix_map[i].perl_class != NULL; i++) {
+ const char *ptr;
+ size_t offset = 0;
+ TRACE_FIND((stderr, "searching for |%s| at offset %lu", perl2posix_map[i].perl_class, (unsigned long)offset));
+ while ((ptr = find_format_str(posix_regex + offset, perl2posix_map[i].perl_class)) != NULL) {
+ size_t len1 = ptr - posix_regex; /* length up to match */
+ size_t len2 = strlen(perl2posix_map[i].posix_class);
+ TRACE_FIND((stderr, "Regexp: mapping %s to %s",
+ perl2posix_map[i].perl_class,
+ perl2posix_map[i].posix_class));
+ /* -1 since -2 for perl format string, +1 for trailing '\0' */
+ posix_regex = xrealloc(posix_regex, strlen(posix_regex) + len2 - 1);
+ /* make space for new format string */
+ memmove(posix_regex + len1 + len2, posix_regex + len1 + 2, strlen(posix_regex + len1 + 2) + 1);
+ /* copy in new format string */
+ memcpy(posix_regex + len1, perl2posix_map[i].posix_class, len2);
+ TRACE_FIND((stderr, "Expanded regex: |%s|", posix_regex));
+ offset = len1 + len2;
+ TRACE_FIND((stderr, "searching again for |%s| at offset %lu",
+ perl2posix_map[i].perl_class,
+ (unsigned long)offset));
+ }
+ }
+ return posix_regex;
+}
+
+#endif /* HAVE_REGEX_H */
+
+char *
+get_text_selection(int *len, int ulx, int uly, int lrx, int lry)
+{
+ struct word_info txt_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, False, True };
+ struct bbox text_bbox;
+
+ text_bbox.ulx = ulx;
+ text_bbox.uly = uly;
+ text_bbox.lrx = lrx;
+ text_bbox.lry = lry;
+
+ txt_info.bboxes = &text_bbox;
+
+ /* initialize buffer with empty string */
+ txt_info.txt_buf_size = 1;
+ txt_info.txt_buf = xmalloc(txt_info.txt_buf_size);
+ txt_info.txt_buf[0] = '\0';
+
+ /* this enlarges the buffer as needed */
+ scan_page(globals.dvi_file.bak_fp, current_page, &txt_info);
+
+ *len = txt_info.txt_buf_size;
+ return txt_info.txt_buf;
+
+#if 0
+ /* fprintf(stderr, "========== SELECTION (len %d):\n", txt_info.curr_buf_idx); */
+ /* dump_buffer(&txt_info, 0, stderr, FMT_ISO_8859_1); */
+ /* fprintf(stderr, "==========\n"); */
+
+ buf = xmalloc(4 * txt_info.curr_buf_idx + 1); /* just in case we get many non-printables */
+ while (i < txt_info.curr_buf_idx) {
+ uint32_t ucs4;
+ const char *ret;
+
+ /* first apply normalization heurisitcs also used by search */
+ size_t len = utf8_to_ucs4(txt_info.txt_buf + i, &ucs4, strlen(txt_info.txt_buf + i));
+ if ((ret = search_normalize_chars(ucs4)) != NULL) {
+ size_t len_ret = strlen(ret);
+ memcpy(buf + offset, ret, len_ret);
+ offset += len_ret;
+ }
+ else if (ucs4 <= 0xff) { /* in iso-latin1 range */
+ buf[offset++] = (unsigned char)ucs4;
+ }
+ else {
+ sprintf(buf + offset, "\\%.4lX", ucs4);
+ offset += 4;
+ }
+ i += len;
+ }
+ buf[offset] = '\0';
+ free(txt_info.txt_buf);
+ return buf;
+#endif /* 0 */
+}
+
+Boolean
+search_extract_text(outputFormatT fmt, struct select_pages_info *pinfo)
+{
+ int i;
+ FILE *fp;
+ struct file_info *finfo = pinfo->finfo;
+
+ if ((fp = XFOPEN(finfo->txt_out.fname, "wb")) == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL, "Could not open %s for writing: %s.",
+ finfo->txt_out.fname,
+ strerror(errno));
+ return False;
+ }
+
+ for (i = 0; i < total_pages; i++) {
+ if (pinfo->callback == NULL || pinfo->callback(pinfo, i)) {
+ struct word_info txt_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, False, False };
+ scan_page(globals.dvi_file.bak_fp, i, &txt_info);
+
+ dump_buffer(&txt_info, 0, fp, fmt);
+
+ free(txt_info.txt_buf);
+
+ fputs("\n\n", fp); /* two newlines for page breaks */
+ }
+ }
+
+ fclose(fp);
+ return True;
+}
+
+void
+search_erase_highlighting(Boolean reset)
+{
+ erase_match_highlighting(m_info, reset);
+}
+
+static void
+message_search_ended(XtPointer arg)
+{
+ struct search_settings *settings = (struct search_settings *)arg;
+
+ settings->searchinfo->from_pos = settings->searchinfo->to_pos = -1;
+ TRACE_FIND((stderr, "search ended; current_page: %d", current_page));
+ settings->from_page = current_page;
+ search_signal_page_changed();
+ settings->message_window = 0;
+ /* statusline_append(STATUS_SHORT, " stopped."); */
+ statusline_print(STATUS_SHORT, "Search stopped.");
+}
+
+
+void
+search_restart(XtPointer arg)
+{
+ struct search_settings *settings = (struct search_settings *)arg;
+ Widget popup, textfield;
+ char *searchterm = NULL;
+
+ TRACE_FIND((stderr, "restart search!"));
+
+ /* Update the search term (user might have changed it before
+ hitting `Return' to restart the search). We need to start
+ from the toplevel widget since this method may be called
+ from a different window (e.g. confirmation popup).
+ */
+ if (get_widget_by_name(&popup, globals.widgets.top_level, Xdvi_SEARCH_POPUP_NAME, True)
+ && get_widget_by_name(&textfield, popup, Xdvi_SEARCHBOX_INPUT_NAME, True)) {
+ XtVaGetValues(textfield,
+#ifdef MOTIF
+ XmNvalue,
+#else
+ XtNstring,
+#endif
+ &searchterm, NULL);
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Got NULL searchterm in search_restart()!"));
+ return;
+ }
+ settings->term = searchterm;
+ }
+
+ if (settings->direction == SEARCH_DOWN) {
+ settings->from_page = 0;
+ }
+ else {
+ settings->from_page = total_pages - 1;
+ }
+ if (settings->direction == SEARCH_DOWN)
+ settings->searchinfo->from_pos = settings->searchinfo->to_pos = -1;
+ else
+ settings->searchinfo->from_pos = settings->searchinfo->to_pos = INT_MAX;
+
+ settings->message_window = 0;
+ search_signal_page_changed();
+ search_dvi((XtPointer)settings);
+}
+
+
+static void
+normalize_newline(char *str)
+{
+ size_t i, j;
+ for (i = 0, j = 0; str[i] != '\0'; i++, j++) {
+ if (str[i] == '\\' && str[i + 1] == 'n') {
+ if (i > 0 && str[i - 1] == '\\') {
+ str[j] = 'n';
+ i++;
+ }
+ else {
+ str[j] = '\n';
+ i++;
+ }
+ }
+ else {
+ str[j] = str[i];
+ }
+ }
+ str[j] = str[i]; /* copy terminating '\0' */
+}
+
+
+static Boolean
+reinit_searchterm(struct search_settings *settings, const char *encoding)
+{
+ struct search_info *searchinfo = settings->searchinfo;
+
+ free(settings->utf8_term);
+ settings->utf8_term = NULL;
+
+ if (memicmp(encoding, "iso-8859-1", strlen("iso-8859-1")) == 0
+ || memicmp(encoding, "iso8859-1", strlen("iso8859-1")) == 0) {
+ int conv_len = (strlen(settings->term) + 1) * 2;
+ int ret_len;
+ char *ptr = xmalloc(conv_len);
+ if ((ret_len = str_iso_8859_1_to_utf8(settings->term, ptr, conv_len)) < 0) {
+ XBell(DISP, 0);
+ popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_ERR,
+ NULL,
+ "Shouldn't happen: search term `%s' is too long (> %d)", settings->term, conv_len);
+ searchinfo->locked = False;
+ free(ptr);
+ settings->utf8_term = xstrdup("");
+ return False;
+ }
+ settings->utf8_term = ptr;
+ }
+ else if (memicmp(encoding, "utf-8", strlen("utf-8")) == 0
+ || memicmp(encoding, "utf8", strlen("utf8")) == 0) {
+ settings->utf8_term = xstrdup(settings->term);
+ }
+ else {
+ if ((settings->utf8_term = iconv_convert_string(encoding, "utf-8", settings->term)) == NULL) {
+ return False;
+ }
+ }
+
+ TRACE_FIND((stderr, "UTF-8 search term: |%s|", settings->utf8_term));
+ normalize_newline(settings->utf8_term);
+ TRACE_FIND((stderr, "UTF-8 search term after normalizing newline: |%s|", settings->utf8_term));
+
+#if 0
+ /* lowercasing for regexps is dealt with by REG_ICASE */
+ if (!settings->case_sensitive && !settings->use_regexp) {
+ if (!utf8_lowercase(settings->utf8_term))
+ return False;
+ TRACE_FIND((stderr, "Lowercased UTF-8 search term: |%s|", settings->utf8_term));
+ }
+#else /* always lowercase, since REG_ICASE is broken with UTF-8(?) */
+ if (!settings->case_sensitive && !utf8_lowercase(settings->utf8_term))
+ return False;
+ TRACE_FIND((stderr, "Lowercased UTF-8 search term: |%s|", settings->utf8_term));
+#endif /* 1 */
+
+ /* remove spaces/newlines before/after an ideographic char */
+ {
+ unsigned char *p = (unsigned char *)settings->utf8_term;
+ unsigned char *q;
+ int l, len = strlen((char *)p);
+ uint32_t ucs4;
+ Boolean had_ideograph;
+
+ had_ideograph = False;
+ while (len > 0) {
+ if (*p == ' ' || *p == '\n') {
+ q = p + 1;
+ while (*q == ' ' || *q == '\n')
+ q++;
+ len -= q - p;
+ if (had_ideograph || is_utf8_ideograph(q))
+ memmove(p, q, len + 1); /* remove spaces/newlines */
+ else
+ p = q; /* preserve spaces/newlines */
+ }
+ else {
+ if ((l = utf8_to_ucs4((char *)p, &ucs4, len)) <= 0)
+ break;
+ len -= l;
+ had_ideograph = is_ideograph(ucs4);
+ p += l;
+ }
+ }
+
+ settings->utf8_term = xrealloc(settings->utf8_term, strlen(settings->utf8_term) + 1);
+ }
+
+ return True;
+}
+
+void
+search_reset_info(void)
+{
+ TRACE_FIND((stderr, "resetting info!"));
+ reset_info(m_info);
+ m_info = NULL;
+}
+
+
+#if HAVE_REGEX_H
+static Boolean
+do_recompile_regexp(struct search_settings *settings,
+ regex_t *regex)
+{
+ int re_retval;
+ /* use extended POSIX, and make `.' not match newlines (otherwise it's
+ often too unintuitive because of the greediness of '+'/'*' */
+ int re_flags = REG_EXTENDED | REG_NEWLINE;
+ TRACE_FIND((stderr, "compiling regexp ..."));
+
+ if (settings->posix_term != NULL) {
+ TRACE_FIND((stderr, "freeing old regexp ..."));
+ free(settings->posix_term);
+ regfree(regex);
+ }
+ settings->posix_term = perl2posix(settings->utf8_term);
+
+#if 0 /* this is broken with e.g. german umlauts; maybe it can't deal with UTF-8 encoding? */
+ /* compile regexp from search term */
+ if (!settings->case_sensitive)
+ re_flags |= REG_ICASE;
+#endif
+
+ { /* change the encoding part of the locale to UTF-8 to match encoding
+ of the search string and the search buffer */
+#if SWITCH_TO_UTF8
+ char *utf8_locale = locale_to_utf8(globals.orig_locale);
+ TRACE_FIND((stderr, "current locale: |%s|, utf8 version: |%s|", globals.orig_locale, utf8_locale));
+ setlocale(LC_ALL, utf8_locale);
+#endif
+ re_retval = regcomp(regex, settings->posix_term, re_flags);
+#if SWITCH_TO_UTF8
+ setlocale(LC_ALL, globals.orig_locale);
+ setlocale(LC_NUMERIC, "C");
+ free(utf8_locale);
+#endif
+ }
+
+ if (re_retval != 0) {
+ report_regexp_error(re_retval, regex, settings->term, 0);
+ settings->searchinfo->locked = False;
+ return False;
+ }
+
+ return True;
+}
+
+#else /* HAVE_REGEX_H */
+
+static void
+warn_no_regex(void)
+{
+ XBell(DISP, 0);
+ popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_WARN,
+ NULL,
+ "POSIX regular expression support (regex.h) is not available on this platform; "
+ "using ordinary string matching instead.");
+}
+#endif /* HAVE_REGEX_H */
+
+/*
+ Scan at most two adjacent pages, writing results in to page_mapping.
+ Return False if user cancelled the search, True else.
+*/
+static Boolean
+scan_two_pages(struct search_settings *settings,
+ struct word_info *info,
+ struct page_mapping *page_mapping,
+ int curr_page)
+{
+ Boolean cancelled = False;
+ struct search_info *searchinfo = settings->searchinfo;
+
+ if (curr_page != page_mapping[0].pageno
+ && curr_page != page_mapping[1].pageno) { /* none of 2 pages scanned yet */
+ reset_info(info);
+ if (settings->direction == SEARCH_DOWN) {
+ if (!do_scan_page(info, settings, &(page_mapping[0]),
+ 0, curr_page, settings->direction)
+ || (curr_page + 1 < total_pages &&
+ !do_scan_page(info, settings, &(page_mapping[1]),
+ page_mapping[0].offset, curr_page + 1, settings->direction)))
+ cancelled = True;
+ }
+ else {
+ if (!do_scan_page(info, settings, &(page_mapping[1]),
+ 0, curr_page, settings->direction)
+ || (curr_page > 0 &&
+ !do_scan_page(info, settings, &(page_mapping[0]),
+ page_mapping[1].offset, curr_page - 1, settings->direction)))
+ cancelled = True;
+ else if (page_mapping[0].offset != -1) {
+ page_mapping[1].offset += page_mapping[0].offset;
+ if (searchinfo->from_pos != INT_MAX)
+ searchinfo->from_pos += page_mapping[0].offset;
+ }
+ }
+ }
+ else if (curr_page != page_mapping[0].pageno) { /* current page scanned as page_mapping[1] */
+ if (settings->direction == SEARCH_DOWN && curr_page + 1 < total_pages) {
+ shift_info_down(searchinfo, info, page_mapping);
+ if (!do_scan_page(info, settings, &(page_mapping[1]),
+ page_mapping[0].offset, curr_page + 1, settings->direction))
+ cancelled = True;
+ }
+ else if (curr_page - 1 != page_mapping[0].pageno && curr_page > 0) {
+ if (!do_scan_page(info, settings, &(page_mapping[0]),
+ 0, curr_page - 1, settings->direction))
+ cancelled = True;
+ else {
+ page_mapping[1].offset += page_mapping[0].offset;
+ if (searchinfo->from_pos != INT_MAX)
+ searchinfo->from_pos += page_mapping[0].offset;
+ }
+ }
+ }
+ else if (curr_page != page_mapping[1].pageno) { /* current page scanned as page_mapping[0] */
+ if (settings->direction == SEARCH_UP && curr_page > 0) {
+ shift_info_up(info, page_mapping);
+ if (!do_scan_page(info, settings, &(page_mapping[0]),
+ 0, curr_page - 1, settings->direction))
+ cancelled = True;
+ else {
+ page_mapping[1].offset += page_mapping[0].offset;
+ if (searchinfo->from_pos != INT_MAX) {
+ searchinfo->from_pos += page_mapping[0].offset;
+ searchinfo->to_pos += page_mapping[0].offset;
+ }
+ TRACE_FIND((stderr, "new offsets: from=%d, to=%d", searchinfo->from_pos, searchinfo->to_pos));
+ }
+ }
+ else if (curr_page + 1 != page_mapping[1].pageno && curr_page + 1 < total_pages) {
+ if (!do_scan_page(info, settings, &(page_mapping[1]),
+ page_mapping[0].offset, curr_page + 1, settings->direction))
+ cancelled = True;
+ }
+ }
+
+ return !cancelled;
+}
+
+void
+search_dvi(XtPointer arg)
+{
+ struct search_settings *settings = (struct search_settings *)arg;
+ struct search_info *searchinfo = settings->searchinfo;
+
+#if HAVE_REGEX_H
+ static regex_t regex;
+#endif /* HAVE_REGEX_H */
+
+ /* a mapping of page numbers to index positions in w_info->txt_buf,
+ for the 2 pages that we scanned */
+ static struct page_mapping page_mapping[2] = { { -1, -1 }, { -1, -1 } };
+
+ static struct word_info w_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, False, False };
+
+ static time_t dvi_time_bak = 0;
+ static char *searchterm_bak = NULL;
+
+ static const char *text_encoding = NULL;
+
+ static Boolean case_sensitive_bak = False;
+ static Boolean ignore_hyphens_bak = False;
+ static Boolean ignore_linebreaks_bak = False;
+ static searchDirectionT direction_bak = SEARCH_UNINITIALIZED;
+ /* from_pos_bak is needed to mark the start of the match when switching from
+ search down to search backwards, where we want to jump to the previous match,
+ so we need the start of the current match again (and down search sets
+ searchinfo->from_pos = searchinfo->to_pos) */
+ static int from_pos_bak = -1;
+ int curr_page = settings->from_page;
+
+ Boolean reinit = False;
+ Boolean recompile_regexp = False;
+ Boolean adjust_hyphen_offset = False;
+
+ /* prevent multiple invocations while still busy searching */
+ if (searchinfo->locked) {
+ TRACE_FIND((stderr, "LOCKED"));
+ return;
+ }
+ searchinfo->locked = True;
+
+ if (dvi_time_bak == 0) { /* first invocation */
+ case_sensitive_bak = settings->case_sensitive;
+ ignore_hyphens_bak = settings->ignore_hyphens;
+ ignore_linebreaks_bak = settings->ignore_linebreaks;
+ dvi_time_bak = globals.dvi_file.time;
+ }
+ if (globals.dvi_file.time > dvi_time_bak) {
+ dvi_time_bak = globals.dvi_file.time;
+ reinit = True;
+ }
+
+ m_match_page = -1;
+
+ if (raise_message_windows()) { /* any popups user still needs to deal with? */
+ TRACE_GUI((stderr, "Still open message windows to deal with, returning ..."));
+ searchinfo->locked = False;
+ return;
+ }
+
+ ASSERT(settings->term != NULL, "settings->term mustn't be NULL!");
+ if (strlen(settings->term) == 0) {
+ positioned_popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_ERR,
+ settings->x_pos, settings->y_pos,
+ NULL, "Empty search term");
+ searchinfo->locked = False;
+ return;
+ }
+
+ TRACE_FIND((stderr, "dvi_search: Searching for |%s| from page %d", settings->term, settings->from_page));
+ TRACE_FIND((stderr, " settings: down = %d, re = %d, case = %d",
+ settings->direction, settings->use_regexp, settings->case_sensitive));
+
+ if (m_changed_page) {
+ m_changed_page = False;
+ reinit = True;
+ }
+
+ /* initialize text_encoding */
+ if (text_encoding == NULL) {
+ text_encoding = get_text_encoding();
+ }
+
+ /* first call to this routine, or search term changed:
+ Re-initialize the utf-8 representation and the regexp */
+ if (settings->utf8_term == NULL
+ || searchterm_bak == NULL
+ || strcmp(settings->term, searchterm_bak) != 0) {
+
+ if (!reinit_searchterm(settings, text_encoding)) {
+ searchinfo->locked = False;
+ return;
+ }
+
+ free(searchterm_bak);
+ searchterm_bak = xstrdup(settings->term);
+ recompile_regexp = True;
+ }
+
+ if (strlen(settings->utf8_term) == 0) {
+ positioned_popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_WARN,
+ settings->x_pos, settings->y_pos,
+ NULL, "Search term is empty after UTF-8 conversion!");
+ searchinfo->locked = False;
+ return;
+ }
+
+ if (direction_bak != settings->direction && direction_bak != SEARCH_UNINITIALIZED
+ && searchinfo->from_pos != INT_MAX && searchinfo->from_pos != -1) {
+ TRACE_FIND((stderr, "changed direction! from_pos: %d", searchinfo->from_pos));
+ if (settings->direction == SEARCH_DOWN) {
+ searchinfo->from_pos = searchinfo->to_pos;
+ TRACE_FIND((stderr, "DOWN; new from_pos: %d", searchinfo->from_pos));
+ }
+ else if (settings->direction == SEARCH_UP) {
+ if (from_pos_bak != -1) {
+ searchinfo->from_pos = from_pos_bak;
+ }
+ else {
+ searchinfo->from_pos = 0;
+ }
+ TRACE_FIND((stderr, "UP; new from_pos: %d", searchinfo->from_pos));
+ }
+ }
+ direction_bak = settings->direction;
+
+ /* If one of the settings for case, hyphens ore linebreaks has
+ * changed, we need to rescan the page to undo lowercasing,
+ * hyphenation or linebreak removal in w_info, but preserve
+ * searchinfo->from_pos since user will want to find next match.
+ */
+ if (case_sensitive_bak != settings->case_sensitive
+ || ignore_hyphens_bak != settings->ignore_hyphens
+ || ignore_linebreaks_bak != settings->ignore_linebreaks) {
+
+ if (ignore_hyphens_bak != settings->ignore_hyphens)
+ adjust_hyphen_offset = True;
+ case_sensitive_bak = settings->case_sensitive;
+ ignore_hyphens_bak = settings->ignore_hyphens;
+ ignore_linebreaks_bak = settings->ignore_linebreaks;
+
+ reset_info(&w_info);
+
+ /* adjust from_pos if it's on second page (we'll rescan it as first page) */
+ if (searchinfo->from_pos >= page_mapping[0].offset)
+ searchinfo->from_pos -= page_mapping[0].offset;
+
+ TRACE_FIND((stderr, "from_pos: %d", searchinfo->from_pos));
+ page_mapping[0].offset = page_mapping[1].offset = page_mapping[0].pageno = page_mapping[1].pageno = -1;
+ /* also need to recompile regexp, and undo lowercasing of search term */
+ if (!reinit_searchterm(settings, text_encoding))
+ return;
+ recompile_regexp = True;
+ }
+
+ if (reinit) { /* file changed, or on different page: re-initialize scan info */
+ TRACE_FIND((stderr, "re-initializing scan info!"));
+ page_mapping[0].offset = page_mapping[1].offset = page_mapping[0].pageno = page_mapping[1].pageno = -1;
+
+ /* re-initialize info */
+ reset_info(&w_info);
+ if (settings->direction == SEARCH_DOWN)
+ searchinfo->from_pos = searchinfo->to_pos = 0;
+ else
+ settings->searchinfo->from_pos = settings->searchinfo->to_pos = INT_MAX;
+ }
+
+ TRACE_FIND((stderr, "from_pos initialized with: %d", settings->searchinfo->from_pos));
+
+ if (settings->use_regexp && recompile_regexp) {
+#if HAVE_REGEX_H
+ if (!do_recompile_regexp(settings, &regex))
+ return;
+#else
+ warn_no_regex();
+#endif /* HAVE_REGEX_H */
+ }
+
+ for (;;) { /* scan pages, try to match */
+ statusline_print(STATUS_MEDIUM, "Searching on page %d", curr_page);
+ TRACE_FIND((stderr, "curr_page: %d, pageno 0: %d, pageno1: %d",
+ curr_page, page_mapping[0].pageno, page_mapping[1].pageno));
+
+ settings->hyphen_delta = 0;
+ /* scan_two_pages will return False if user cancelled */
+ if (!scan_two_pages(settings, &w_info, page_mapping, curr_page)
+ || (read_events(EV_NOWAIT) & EV_GE_FIND_CANCEL)) {
+ statusline_append(STATUS_SHORT,
+ "- cancelled.",
+ "- cancelled.");
+ settings->searchinfo->locked = False;
+ return;
+
+ }
+
+ TRACE_FIND((stderr, "page mapping:\n%d: %d\n%d: %d",
+ page_mapping[0].pageno, page_mapping[0].offset,
+ page_mapping[1].pageno, page_mapping[1].offset));
+
+/* dump_buffer(&w_info, 0, stderr, FMT_ISO_8859_1); */
+
+ /* If ignore_hyphens has changed (in which case adjust_hyphen_offset
+ is true), the buffer will contain settings->hyphen_delta fewer
+ or more characters than in the previous pass due to the removal
+ or addition of hyphens; adjust from_pos and to_pos accordingly:
+ */
+ if (adjust_hyphen_offset) {
+ TRACE_FIND((stderr, "adjusting offset by %d", settings->hyphen_delta));
+ if (settings->ignore_hyphens) { /* fewer characters */
+ settings->searchinfo->from_pos -= settings->hyphen_delta;
+ settings->searchinfo->to_pos -= settings->hyphen_delta;
+ }
+ else { /* more characters */
+ settings->searchinfo->from_pos += settings->hyphen_delta;
+ settings->searchinfo->to_pos += settings->hyphen_delta;
+ }
+ TRACE_FIND((stderr, "NEW from_pos: %d; to_pos: %d",
+ settings->searchinfo->from_pos, settings->searchinfo->to_pos));
+ }
+
+
+ /* match the searchstring */
+#if HAVE_REGEX_H
+ if (settings->use_regexp) {
+ if (!try_regexp_match(&regex, &w_info, settings, searchinfo)) /* regexp error */
+ return;
+
+ }
+ else {
+#endif
+ try_match(&w_info, settings, searchinfo);
+#if HAVE_REGEX_H
+ }
+#endif
+
+ /* again, check if user cancelled */
+ if (read_events(EV_NOWAIT) & EV_GE_FIND_CANCEL) { /* user cancelled */
+ statusline_append(STATUS_SHORT,
+ "- cancelled.",
+ "- cancelled.");
+ settings->searchinfo->locked = False;
+ return;
+
+ }
+
+ if (searchinfo->have_match) { /* match, highlight it */
+ highlight_match(settings, &w_info, page_mapping);
+ settings->searchinfo->locked = False;
+ if (settings->direction == SEARCH_DOWN) {
+ from_pos_bak = searchinfo->from_pos;
+ searchinfo->from_pos = searchinfo->to_pos;
+ }
+ break;
+ }
+ else if ((settings->direction == SEARCH_DOWN && curr_page + 1 < total_pages)
+ || (settings->direction == SEARCH_UP && curr_page > 0)) {
+ if (settings->direction == SEARCH_DOWN)
+ curr_page++;
+ else
+ curr_page--;
+ TRACE_FIND((stderr, "continuing on page %d", curr_page));
+ erase_match_highlighting(m_info, True);
+ /* no match, and we have more pages; continue scanning */
+ continue;
+ }
+ else { /* reached end of file */
+ Widget find_popup;
+
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
+ find_popup = globals.widgets.top_level;
+ }
+
+ statusline_append(STATUS_MEDIUM,
+ "... searched to end of file.",
+ "... searched to end of file.");
+ erase_match_highlighting(m_info, True);
+ settings->searchinfo->locked = False;
+
+ settings->message_window =
+ positioned_choice_dialog(find_popup,
+ MSG_QUESTION,
+ settings->x_pos, settings->y_pos,
+ NULL,
+#ifndef MOTIF
+ "do-search-restart",
+#endif
+ NULL, NULL, /* no pre_callbacks */
+ "Yes", search_restart, (XtPointer)settings,
+ "Cancel", message_search_ended, (XtPointer)settings,
+ "Searched %s of file without finding the pattern.\n"
+ "Start again from the %s of the file?",
+ settings->direction == SEARCH_DOWN
+ ? "forward to end" : "backward to beginning",
+ settings->direction == SEARCH_DOWN
+ ? "beginning" : "end");
+ TRACE_GUI((stderr, "message_window: %p\n", (void *)settings->message_window));
+ /* notreached */
+ break;
+ }
+ } /* for(;;) */
+}
diff --git a/Build/source/texk/xdvik/search-internal.h b/Build/source/texk/xdvik/search-internal.h
new file mode 100644
index 00000000000..a3cee01c99d
--- /dev/null
+++ b/Build/source/texk/xdvik/search-internal.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef DVI_SEARCH_H_
+#define DVI_SEARCH_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "search-dialog.h"
+#include "dvisel.h"
+
+/* Widget names that are used in callbacks */
+#define Xdvi_SEARCHBOX_INPUT_NAME "searchbox_input"
+#define Xdvi_SEARCH_POPUP_NAME "find_popup"
+
+/* A sorted dynamic array that maps text buffer (i.e. word)
+ * positions to DVI file offsets.
+ */
+
+struct pos_info {
+ size_t buffer_pos; /* position in text buffer */
+ struct bbox bbox; /* bounding box of this word */
+};
+
+struct page_mapping {
+ int pageno;
+ int offset;
+};
+
+struct word_info {
+ char *txt_buf; /* contains scanned text as whitespace separated strings */
+ size_t txt_buf_size; /* size of above buffer */
+ size_t curr_buf_idx; /* current position in buffer */
+ struct bbox *bboxes; /* dynamic array of position infos */
+ size_t bboxes_size; /* size of above array */
+ size_t bboxes_idx; /* current position in buffer */
+ const struct page_mapping *page_mapping; /* list of page offsets, for bbox_pass */
+ struct search_settings *settings; /* pointer to search settings, for bbox_pass */
+ int buffer_offset; /* offset to start of buffer from text on previous pages */
+ Boolean bbox_pass; /* whether we're scanning for bounding boxes of match */
+ Boolean search_scan_pass; /* whether we're scanning for text in string search */
+ Boolean text_selection_pass; /* whether we're scanning for text selection */
+};
+
+extern void search_dvi(XtPointer settings);
+extern void search_restart(XtPointer settings);
+extern Boolean search_extract_text(outputFormatT fmt, struct select_pages_info *pinfo);
+extern Boolean search_have_match(int pageno);
+extern int search_inside_bbox_match(int x, int y);
+extern void search_draw_inverted_regions(void);
+extern void search_signal_page_changed(void);
+extern void search_reset_info(void);
+extern void search_erase_highlighting(Boolean flag);
+extern void search_putback_expose(void);
+extern char *get_text_selection(int *len, int x, int y, int w, int h);
+
+#if 0
+#define TEST_DELAY(s) \
+ do { \
+ TRACE_FIND((stderr, s)); \
+ int i, j; \
+ XSync(DISP, False); \
+ for (i = 0; i < 10000; i++) \
+ for (j = 0; j < 20000; j++); \
+ } while (0)
+#else
+#define TEST_DELAY(s) /* as nothing */
+#endif
+
+#endif /* DVI_SEARCH_H_ */
+
diff --git a/Build/source/texk/xdvik/special.c b/Build/source/texk/xdvik/special.c
new file mode 100644
index 00000000000..ec770c89983
--- /dev/null
+++ b/Build/source/texk/xdvik/special.c
@@ -0,0 +1,2776 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2004 Paul Vojta
+
+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:
+This module is based on prior work as noted below.
+
+\*========================================================================*/
+
+/*
+ * Support drawing routines for TeXsun and TeX
+ *
+ * Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine
+ * Adapted for xdvi by Jeffrey Lee, U. of Toronto
+ *
+ * At the time these routines are called, the values of hh and vv should
+ * have been updated to the upper left corner of the graph (the position
+ * the \special appears at in the dvi file). Then the coordinates in the
+ * graphics commands are in terms of a virtual page with axes oriented the
+ * same as the Imagen and the SUN normally have:
+ *
+ * 0,0
+ * +-----------> +x
+ * |
+ * |
+ * |
+ * \ /
+ * +y
+ *
+ * Angles are measured in the conventional way, from +x towards +y.
+ * Unfortunately, that reverses the meaning of "counterclockwise"
+ * from what it's normally thought of.
+ *
+ * A lot of floating point arithmetic has been converted to integer
+ * arithmetic for speed. In some places, this is kind-of kludgy, but
+ * it's worth it.
+ */
+
+
+#include <setjmp.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <ctype.h>
+
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+#include "kpathsea/line.h"
+#include "kpathsea/tex-file.h"
+
+#include "special.h"
+#include "hypertex.h"
+#include "dvi.h"
+#include "message-window.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "dvi-draw.h"
+#include "statusline.h"
+#include "util.h"
+#include "image-magick.h"
+#include "pagesel.h"
+#include "my-snprintf.h"
+#include "string-utils.h"
+
+#if PS
+# ifdef PS_DPS
+# include "psdps.h"
+# endif
+# ifdef PS_NEWS
+# include "psnews.h"
+# endif
+# ifdef PS_GS
+# include "psgs.h"
+# endif
+
+/*
+ Code inside BUG_888087_FIXED improve the appearance of pic specials at magstep 1, but
+ _decreases_ it at other magnifications (bug #888087; see
+ http://sourceforge.net/tracker/index.php?func=detail&aid=888087&group_id=23164&atid=377580)
+ Disabled until this is fixed.
+*/
+#define BUG_888087_FIXED 0
+
+
+/*
+ Flag whether this page contains raw PS material;
+ used to warn user about this:
+*/
+Boolean have_raw_postscript = False;
+
+# if PS_GS && GS_PIXMAP_CLEARING_HACK
+/*
+ Flag whether this page contains PS material;
+ used to flush the GS buffer
+*/
+Boolean had_ps_specials = False;
+# endif /* PS_GS && GS_PIXMAP_CLEARING_HACK */
+
+#endif
+
+
+#if COLOR
+
+/*
+ * Color stack used when scanning. These records stay around, to ease
+ * the burden on xmalloc(). The first entry is a dummy entry, giving
+ * the default foreground color (as modified).
+ */
+
+struct colorframe {
+ struct colorframe *next, *prev;
+ struct rgb color;
+};
+
+static Boolean m_have_papersize_special = False;
+
+void reset_papersize_special(void)
+{
+ m_have_papersize_special = False;
+}
+
+Boolean have_papersize_special(void)
+{
+ return m_have_papersize_special;
+}
+
+static struct colorframe scanstack_head;
+static int scanstack_len;
+static struct colorframe *scanstack_current;
+
+/*
+ * Page stack when displaying. Again, the records stay around once
+ * allocated. Bottom entries in the stack (inherited from previous
+ * pages) are stored in an array instead (see comments in xdvi.h).
+ */
+
+static struct colorframe *rcs_head;
+
+static Boolean parse_color (const char *cp0, const char *cp, struct rgb *rgbp, Boolean generic_ps_flag);
+
+#endif /* COLOR */
+
+
+#ifndef S_IRUSR
+# define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+# define S_IWUSR 0200
+#endif
+
+# if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+# endif
+# ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+# endif
+# ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+# endif
+
+#define MAXPOINTS 300 /* Max points in a path */
+#define MAX_PEN_SIZE 7 /* Max pixels of pen width */
+#define TWOPI (3.14159265359 * 2.0)
+
+extern double floor(double);
+#define rint(x) floor((x) + 0.5)
+
+static int xx[MAXPOINTS], yy[MAXPOINTS]; /* Path in milli-inches */
+static int path_len = 0; /* # points in current path */
+static int pen_size = 1; /* Pixel width of lines drawn */
+
+static Boolean whiten = False;
+static Boolean shade = False;
+static Boolean blacken = False;
+
+Boolean psfig_begun = False;
+
+#define CMD(x, y) ((x) << 8 | (y))
+
+
+/*
+ * X drawing routines
+ */
+
+#define toint(x) ((int) ((x) + 0.5))
+#define xconv(x) (toint(tpic_conv*(x))/currwin.shrinkfactor + PXL_H)
+#define yconv(y) (toint(tpic_conv*(y))/currwin.shrinkfactor + PXL_V)
+
+/*
+ * Draw a line from (fx,fy) to (tx,ty).
+ */
+static void
+line_btw(int fx, int fy, int tx, int ty)
+{
+ int fcx = xconv(fx);
+ int tcx = xconv(tx);
+ int fcy = yconv(fy);
+ int tcy = yconv(ty);
+
+ if ((fcx < globals.win_expose.max_x || tcx < globals.win_expose.max_x) && (fcx >= globals.win_expose.min_x || tcx >= globals.win_expose.min_x) &&
+ (fcy < globals.win_expose.max_y || tcy < globals.win_expose.max_y) && (fcy >= globals.win_expose.min_y || tcy >= globals.win_expose.min_y)) {
+#if COLOR
+ if (fg_active != fg_current)
+ do_color_change();
+#endif
+ XDrawLine(DISP, currwin.win, globals.gc.rule,
+ fcx - currwin.base_x, fcy - currwin.base_y,
+ tcx - currwin.base_x, tcy - currwin.base_y);
+ }
+}
+
+/*
+ * Draw a dot at (x,y)
+ */
+static void
+dot_at(int x, int y)
+{
+ int cx = xconv(x);
+ int cy = yconv(y);
+
+ if (cx < globals.win_expose.max_x && cx >= globals.win_expose.min_x && cy < globals.win_expose.max_y && cy >= globals.win_expose.min_y){
+#if COLOR
+ if (fg_active != fg_current)
+ do_color_change();
+#endif
+ XDrawPoint(DISP, currwin.win, globals.gc.rule,
+ cx - currwin.base_x, cy - currwin.base_y);
+ }
+}
+
+/*
+ * Apply the requested attributes to the last path (box) drawn.
+ * Attributes are reset.
+ * (Not currently implemented.)
+ */
+static void
+do_attribute_path(int last_min_x, int last_max_x, int last_min_y, int last_max_y)
+{
+ UNUSED(last_min_x);
+ UNUSED(last_max_x);
+ UNUSED(last_min_y);
+ UNUSED(last_max_y);
+}
+
+/*
+ * Set the size of the virtual pen used to draw in milli-inches
+ */
+static void
+set_pen_size(char *cp)
+{
+ int ps;
+
+ if (sscanf(cp, " %d ", &ps) != 1) {
+ XDVI_WARNING((stderr, "invalid .ps command format: %s", cp));
+ return;
+ }
+ pen_size = (2 * ps * resource.pixels_per_inch / currwin.shrinkfactor + 1000) / 2000;
+ if (pen_size < 1)
+ pen_size = 1;
+ else if (pen_size > MAX_PEN_SIZE)
+ pen_size = MAX_PEN_SIZE;
+
+#if BUG_888087_FIXED
+ if (globals.gc.rule) {
+ XGCValues values;
+ values.line_width = pen_size;
+ XChangeGC(DISP, globals.gc.rule, GCLineWidth, &values);
+ }
+#endif
+}
+
+
+/*
+ * Print the line defined by previous path commands
+ */
+
+static void
+flush_path(void)
+{
+ int i;
+ int last_min_x, last_max_x, last_min_y, last_max_y;
+
+ last_min_x = 30000;
+ last_min_y = 30000;
+ last_max_x = -30000;
+ last_max_y = -30000;
+ for (i = 1; i < path_len; i++) {
+ if (xx[i] > last_max_x)
+ last_max_x = xx[i];
+ if (xx[i] < last_min_x)
+ last_min_x = xx[i];
+ if (yy[i] > last_max_y)
+ last_max_y = yy[i];
+ if (yy[i] < last_min_y)
+ last_min_y = yy[i];
+ line_btw(xx[i], yy[i], xx[i + 1], yy[i + 1]);
+ }
+ if (xx[path_len] > last_max_x)
+ last_max_x = xx[path_len];
+ if (xx[path_len] < last_min_x)
+ last_min_x = xx[path_len];
+ if (yy[path_len] > last_max_y)
+ last_max_y = yy[path_len];
+ if (yy[path_len] < last_min_y)
+ last_min_y = yy[path_len];
+ path_len = 0;
+ do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y);
+}
+
+
+/*
+ * Print a dashed line along the previously defined path, with
+ * the dashes/inch defined.
+ */
+
+static void
+flush_dashed(char *cp, Boolean dotted)
+{
+ int i;
+ int numdots;
+ int lx0, ly0, lx1, ly1;
+ int cx0, cy0, cx1, cy1;
+ float inchesperdash;
+ double d, spacesize, a, b = 0.0, dx, dy, milliperdash;
+
+ if (sscanf(cp, " %f ", &inchesperdash) != 1) {
+ XDVI_WARNING((stderr, "invalid format for dotted/dashed line: %s", cp));
+ return;
+ }
+ if (path_len <= 1 || inchesperdash <= 0.0) {
+ XDVI_WARNING((stderr, "invalid conditions for dotted/dashed line"));
+ return;
+ }
+ milliperdash = inchesperdash * 1000.0;
+ lx0 = xx[1];
+ ly0 = yy[1];
+ lx1 = xx[2];
+ ly1 = yy[2];
+ dx = lx1 - lx0;
+ dy = ly1 - ly0;
+ if (dotted) {
+ numdots = sqrt(dx * dx + dy * dy) / milliperdash + 0.5;
+ if (numdots == 0)
+ numdots = 1;
+ for (i = 0; i <= numdots; i++) {
+ a = (float)i / (float)numdots;
+ cx0 = lx0 + a * dx + 0.5;
+ cy0 = ly0 + a * dy + 0.5;
+ dot_at(cx0, cy0);
+ }
+ }
+ else {
+ d = sqrt(dx * dx + dy * dy);
+ numdots = d / (2.0 * milliperdash) + 1.0;
+ if (numdots <= 1)
+ line_btw(lx0, ly0, lx1, ly1);
+ else {
+ spacesize = (d - numdots * milliperdash) / (numdots - 1);
+ for (i = 0; i < numdots - 1; i++) {
+ a = i * (milliperdash + spacesize) / d;
+ b = a + milliperdash / d;
+ cx0 = lx0 + a * dx + 0.5;
+ cy0 = ly0 + a * dy + 0.5;
+ cx1 = lx0 + b * dx + 0.5;
+ cy1 = ly0 + b * dy + 0.5;
+ line_btw(cx0, cy0, cx1, cy1);
+ b += spacesize / d;
+ }
+ cx0 = lx0 + b * dx + 0.5;
+ cy0 = ly0 + b * dy + 0.5;
+ line_btw(cx0, cy0, lx1, ly1);
+ }
+ }
+ path_len = 0;
+}
+
+
+/*
+ * Add a point to the current path
+ */
+
+static void
+add_path(char *cp)
+{
+ int pathx, pathy;
+
+ if (++path_len >= MAXPOINTS)
+ XDVI_FATAL((stderr, "Too many points"));
+ if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2)
+ XDVI_FATAL((stderr, "Malformed path command"));
+ xx[path_len] = pathx;
+ yy[path_len] = pathy;
+}
+
+
+/*
+ * Draw to a floating point position
+ */
+
+static void
+im_fdraw(double x, double y)
+{
+ if (++path_len >= MAXPOINTS)
+ XDVI_FATAL((stderr, "Too many arc points"));
+ xx[path_len] = x + 0.5;
+ yy[path_len] = y + 0.5;
+}
+
+
+/*
+ * Draw an ellipse with the indicated center and radices.
+ */
+
+static void
+draw_ellipse(int xc, int yc, int xr, int yr)
+{
+ double angle, theta;
+ int n;
+ int px0, py0, px1, py1;
+
+ angle = (xr + yr) / 2.0;
+ theta = sqrt(1.0 / angle);
+ n = TWOPI / theta + 0.5;
+ if (n < 12)
+ n = 12;
+ else if (n > 80)
+ n = 80;
+ n /= 2;
+ theta = TWOPI / n;
+
+ angle = 0.0;
+ px0 = xc + xr; /* cos(0) = 1 */
+ py0 = yc; /* sin(0) = 0 */
+ while ((angle += theta) <= TWOPI) {
+ px1 = xc + xr * cos(angle) + 0.5;
+ py1 = yc + yr * sin(angle) + 0.5;
+ line_btw(px0, py0, px1, py1);
+ px0 = px1;
+ py0 = py1;
+ }
+ line_btw(px0, py0, xc + xr, yc);
+}
+
+/*
+ * Draw an arc
+ */
+
+static void
+arc(char *cp, Boolean invis)
+{
+ int xc, yc, xrad, yrad, n;
+ float start_angle, end_angle, angle, theta, r;
+ double xradius, yradius, xcenter, ycenter;
+
+ n = sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad,
+ &start_angle, &end_angle);
+
+ if (n != 6) {
+ XDVI_WARNING((stderr, "invalid arc specification: %s", cp));
+ return;
+ }
+
+ if (invis)
+ return;
+
+ /* We have a specialized fast way to draw closed circles/ellipses */
+ if (start_angle <= 0.0 && end_angle >= 6.282) {
+ draw_ellipse(xc, yc, xrad, yrad);
+ return;
+ }
+ xcenter = xc;
+ ycenter = yc;
+ xradius = xrad;
+ yradius = yrad;
+ r = (xradius + yradius) / 2.0;
+ theta = sqrt(1.0 / r);
+#if BUG_888087_FIXED
+ n = (pen_size * TWOPI) / (theta * currwin.shrinkfactor) + 0.5;
+#else
+ n = 0.3 * TWOPI / theta + 0.5;
+#endif
+ if (n < 12)
+ n = 12;
+ else if (n > 80)
+ n = 80;
+ n /= 2;
+ theta = TWOPI / n;
+ flush_path();
+ im_fdraw(xcenter + xradius * cos(start_angle),
+ ycenter + yradius * sin(start_angle));
+ angle = start_angle + theta;
+ if (end_angle < start_angle)
+ end_angle += TWOPI;
+ while (angle < end_angle) {
+ im_fdraw(xcenter + xradius * cos(angle),
+ ycenter + yradius * sin(angle));
+ angle += theta;
+ }
+ im_fdraw(xcenter + xradius * cos(end_angle),
+ ycenter + yradius * sin(end_angle));
+ flush_path();
+}
+
+
+/*
+ * APPROXIMATE integer distance between two points
+ */
+
+#define dist(x0, y0, x1, y1) (abs(x0 - x1) + abs(y0 - y1))
+
+
+/*
+ * Draw a spline along the previously defined path
+ */
+
+static void
+flush_spline(void)
+{
+ int xp, yp;
+ int N;
+ int lastx = -1, lasty = -1;
+ Boolean lastvalid = False;
+ int t1, t2, t3;
+ int steps;
+ int j;
+ int i, w;
+
+ N = path_len + 1;
+ xx[0] = xx[1];
+ yy[0] = yy[1];
+ xx[N] = xx[N - 1];
+ yy[N] = yy[N - 1];
+ for (i = 0; i < N - 1; i++) { /* interval */
+ steps = (dist(xx[i], yy[i], xx[i + 1], yy[i + 1]) +
+ dist(xx[i + 1], yy[i + 1], xx[i + 2], yy[i + 2])) / 80;
+ for (j = 0; j < steps; j++) { /* points within */
+ w = (j * 1000 + 500) / steps;
+ t1 = w * w / 20;
+ w -= 500;
+ t2 = (750000 - w * w) / 10;
+ w -= 500;
+ t3 = w * w / 20;
+ xp =
+ (t1 * xx[i + 2] + t2 * xx[i + 1] + t3 * xx[i] + 50000) / 100000;
+ yp =
+ (t1 * yy[i + 2] + t2 * yy[i + 1] + t3 * yy[i] + 50000) / 100000;
+ if (lastvalid)
+ line_btw(lastx, lasty, xp, yp);
+ lastx = xp;
+ lasty = yp;
+ lastvalid = True;
+ }
+ }
+ path_len = 0;
+}
+
+
+/*
+ * Shade the last box, circle, or ellipse
+ */
+
+static void
+shade_last(void)
+{
+ blacken = whiten = False;
+ shade = True;
+}
+
+
+/*
+ * Make the last box, circle, or ellipse, white inside (shade with white)
+ */
+
+static void
+whiten_last(void)
+{
+ whiten = True;
+ blacken = shade = False;
+}
+
+
+/*
+ * Make last box, etc, black inside
+ */
+
+static void
+blacken_last(void)
+{
+ blacken = True;
+ whiten = shade = False;
+}
+
+
+/*
+ * Code for PostScript<tm> specials begins here.
+ */
+
+#if PS
+
+/*
+ * Information on how to search for PS header and figure files.
+ */
+
+static void ps_startup(int, int, const char *);
+static void ps_startup2(void);
+
+/* dummy procedures */
+static void NullProc(void) { }
+static void NullProcInt(int flag) { UNUSED(flag); }
+static void NullProcStr(const char *cp) { UNUSED(cp); }
+
+
+struct psprocs psp = { /* used for lazy startup of the ps machinery */
+ /* toggle */ NullProcInt,
+ /* destroy */ NullProc,
+ /* interrupt */ NullProc,
+ /* endpage */ NullProc,
+ /* drawbegin */ ps_startup,
+ /* drawraw */ NullProcStr,
+ /* drawfile */ NULL,
+ /* drawend */ NullProcStr,
+ /* beginheader */ ps_startup2,
+ /* endheader */ NullProc,
+ /* newdoc */ NullProc
+};
+
+struct psprocs no_ps_procs = { /* used if postscript is unavailable */
+ /* toggle */ NullProcInt,
+ /* destroy */ NullProc,
+ /* interrupt */ NullProc,
+ /* endpage */ NullProc,
+ /* drawbegin */ drawbegin_none,
+ /* drawraw */ NullProcStr,
+ /* drawfile */ NULL,
+ /* drawend */ NullProcStr,
+ /* beginheader */ NullProc,
+ /* endheader */ NullProc,
+ /* newdoc */ NullProc
+};
+
+#endif /* PS */
+
+#ifdef MAGICK
+int bbox_angle;
+Boolean bbox_valid;
+unsigned int bbox_width;
+unsigned int bbox_height;
+int bbox_voffset;
+#else
+static int bbox_angle;
+static Boolean bbox_valid;
+static unsigned int bbox_width;
+static unsigned int bbox_height;
+static int bbox_voffset;
+#endif
+
+/* info on bboxes on this page */
+struct bbox_info {
+ int x;
+ int y;
+ int w;
+ int h;
+ int angle;
+};
+
+static struct bbox_info *g_bbox_info = NULL;
+static size_t g_bbox_info_size = 0;
+static size_t g_bbox_info_max_size = 0;
+
+/*
+ Append the current coordinates to g_bbox_info, unless it already
+ contains these coordinates.
+ */
+
+static void
+append_bbox_info(int x, int y, int w, int h, int angle)
+{
+ Boolean found = False;
+ size_t i;
+ const size_t SIZE_STEP = 16;
+
+ /* is this box already present? */
+ for (i = 0; i < g_bbox_info_size; i++) {
+ if (g_bbox_info[i].x == x
+ && g_bbox_info[i].y == y
+ && g_bbox_info[i].w == w
+ && g_bbox_info[i].h == h
+ && g_bbox_info[i].angle == angle) {
+ found = True;
+ break;
+ }
+ }
+
+ if (!found) {
+ g_bbox_info_size++;
+
+ while (g_bbox_info_size >= g_bbox_info_max_size) {
+ g_bbox_info_max_size += SIZE_STEP;
+ }
+
+ g_bbox_info = xrealloc(g_bbox_info, g_bbox_info_max_size * sizeof *g_bbox_info);
+ g_bbox_info[g_bbox_info_size - 1].x = x;
+ g_bbox_info[g_bbox_info_size - 1].y = y;
+ g_bbox_info[g_bbox_info_size - 1].w = w;
+ g_bbox_info[g_bbox_info_size - 1].h = h;
+ g_bbox_info[g_bbox_info_size - 1].angle = angle;
+ }
+}
+
+static void
+draw_bbox0(int xcorner, int ycorner)
+{
+ if (bbox_valid) {
+#if COLOR
+ if (fg_active != fg_current)
+ do_color_change();
+#endif
+
+ if (bbox_angle == 0) {
+ ycorner -= bbox_voffset;
+ XDrawRectangle(DISP, currwin.win, globals.gc.high, xcorner, ycorner, bbox_width, bbox_height);
+ if (resource.postscript == 0) {
+ if (htex_inside_href) {
+ htex_set_anchorsize(xcorner, ycorner, xcorner + bbox_width, ycorner + bbox_height);
+ htex_set_objecttype(HTEX_IMG);
+ }
+ }
+ }
+ else {
+ float sin_a = sin(bbox_angle * (TWOPI / 360));
+ float cos_a = cos(bbox_angle * (TWOPI / 360));
+ float a, b, c, d;
+
+ a = cos_a * bbox_width;
+ b = -sin_a * bbox_width;
+ c = -sin_a * bbox_height;
+ d = -cos_a * bbox_height;
+
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ xcorner, ycorner,
+ xcorner + (int)rint(a), ycorner + (int)rint(b));
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ xcorner + (int)rint(a), ycorner + (int)rint(b),
+ xcorner + (int)rint(a + c), ycorner + (int)rint(b + d));
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ xcorner + (int)rint(a + c), ycorner + (int)rint(b + d),
+ xcorner + (int)rint(c), ycorner + (int)rint(d));
+ XDrawLine(DISP, currwin.win, globals.gc.high,
+ xcorner + (int)rint(c), ycorner + (int)rint(d),
+ xcorner, ycorner);
+ }
+ bbox_valid = False;
+ }
+}
+
+/*
+ Display the items in bbox_info.
+ Invoked from draw_page() in dvi-draw.c.
+ */
+void
+display_bboxes(void)
+{
+ size_t i;
+
+ for (i = 0; i < g_bbox_info_size; i++) {
+ if (globals.debug & DBG_PS) {
+ fprintf(stderr, "drawing bbox %lu at %d %d, %d x %d, angle %d\n",
+ (unsigned long)i,
+ g_bbox_info[i].x,
+ g_bbox_info[i].y,
+ g_bbox_info[i].w,
+ g_bbox_info[i].h,
+ g_bbox_info[i].angle);
+ }
+#if 0
+ XDrawRectangle(DISP, currwin.win, globals.gc.high,
+ g_bbox_info[i].x,
+ g_bbox_info[i].y,
+ g_bbox_info[i].w,
+ g_bbox_info[i].h);
+#else
+ bbox_valid = True;
+ bbox_width = g_bbox_info[i].w;
+ bbox_height = bbox_voffset = g_bbox_info[i].h;
+ bbox_angle = g_bbox_info[i].angle;
+ draw_bbox0(g_bbox_info[i].x, g_bbox_info[i].y + bbox_height);
+#endif
+ }
+ bbox_angle = 0;
+ bbox_valid = False;
+}
+
+void
+clear_bboxes(void)
+{
+ free(g_bbox_info);
+ g_bbox_info = NULL;
+ g_bbox_info_size = 0;
+ g_bbox_info_max_size = 0;
+}
+
+void
+save_bbox(void)
+{
+ int xcorner, ycorner;
+
+ if (bbox_valid) {
+ xcorner = PXL_H - currwin.base_x;
+ ycorner = PXL_V - currwin.base_y;
+
+ ycorner -= bbox_voffset;
+ append_bbox_info(xcorner, ycorner, bbox_width, bbox_height, bbox_angle);
+
+ /* register boundaries of this box as anchor boundaries */
+ if (htex_inside_href) {
+ htex_set_anchorsize(xcorner, ycorner, xcorner + bbox_width, ycorner + bbox_height);
+ htex_set_objecttype(HTEX_IMG);
+ }
+ }
+}
+
+
+void
+draw_bbox(void)
+{
+ draw_bbox0(PXL_H - currwin.base_x, PXL_V - currwin.base_y);
+}
+
+#if PS
+
+static XIOErrorHandler oldhandler;
+
+static int XDviIOErrorHandler(Display * disp)
+{
+ ps_destroy();
+ return oldhandler(disp);
+}
+
+static void
+actual_startup(int flag)
+{
+ UNUSED(flag);
+ oldhandler = XSetIOErrorHandler(XDviIOErrorHandler);
+
+ /*
+ * Figure out what we want to use to display postscript figures
+ * and set at most one of the following to True:
+ * resource.useGS, resource.useDPS, resource.useNeWS
+ *
+ * Choose DPS then NEWS then Ghostscript if they are available
+ */
+ if (!(
+#ifdef PS_DPS
+ (resource.useDPS && initDPS())
+#if defined(PS_NEWS) || defined(PS_GS)
+ ||
+#endif
+#endif /* PS_DPS */
+#ifdef PS_NEWS
+ (resource.useNeWS && initNeWS())
+#ifdef PS_GS
+ ||
+#endif
+#endif /* PS_NEWS */
+#ifdef PS_GS
+ (resource.useGS && initGS())
+#endif
+ ))
+ psp = no_ps_procs;
+}
+
+static void
+ps_startup(int xul, int yul, const char *cp)
+{
+ if (resource.postscript == 0) {
+ draw_bbox();
+ return;
+ }
+ actual_startup(0);
+ psp.drawbegin(xul, yul, cp);
+}
+
+static void
+ps_startup2(void)
+{
+ actual_startup(0);
+ psp.beginheader();
+}
+
+
+/*
+ * dumb parsing of PostScript - search for rotation H. Zeller 1/97
+ * Returns true if we find a potentially non-supported command that
+ * we want to warn users about.
+ */
+static Boolean
+ps_parseraw(const char *PostScript_cmd)
+{
+ const char *p;
+
+ bbox_angle = 0;
+ p = strstr(PostScript_cmd, "rotate");
+ if (p != NULL) {
+ while (*p != '\0' && !isdigit((int)*p))
+ --p;
+ while (*p != '\0' && isdigit((int)*p))
+ --p;
+ if (*p != '+' && *p != '-')
+ ++p;
+ sscanf(p, "%d neg rotate", &bbox_angle);
+ return True;
+ }
+ if (strstr(PostScript_cmd, " scale ") != NULL)
+ return True;
+ return False;
+}
+
+
+void
+drawbegin_none(int xul, int yul, const char *cp)
+{
+ UNUSED(xul);
+ UNUSED(yul);
+ UNUSED(cp);
+
+ draw_bbox();
+}
+
+
+struct tickrec {
+ struct tickrec *next;
+ int pageno;
+ char *command;
+ char *tempname;
+};
+
+static struct tickrec *tickhead = NULL; /* head of linked list of */
+/* cached information */
+static int nticks = 0; /* number of records total */
+
+#ifndef TICKCACHESIZE
+#define TICKCACHESIZE 3
+#endif
+
+#ifndef TICKTMP
+#define TICKTMP "/tmp"
+#endif
+
+/*
+ * cachetick() - returns:
+ * NULL error;
+ * fp == NULL string was not in cache, fd = file
+ * fp != NULL string was in cache, fp = cached file
+ */
+
+static struct tickrec *
+cachetick(const char *filename, kpse_file_format_type pathinfo, FILE **fp, int *fdp)
+{
+ struct tickrec **linkp;
+ struct tickrec *tikp;
+ struct tickrec **freerecp;
+
+ linkp = &tickhead;
+ freerecp = NULL;
+ for (;;) { /* see if we have it already */
+ tikp = *linkp;
+ if (tikp == NULL) { /* if end of list */
+ int fd;
+
+ if (nticks >= TICKCACHESIZE && freerecp != NULL) {
+ tikp = *freerecp;
+ *freerecp = tikp->next;
+ free(tikp->command);
+ unlink(tikp->tempname);
+ /* reuse tikp and tikp->tempname */
+ }
+ else {
+ tikp = xmalloc(sizeof(struct tickrec));
+ tikp->tempname = NULL;
+ ++nticks;
+ }
+ fd = xdvi_temp_fd(&tikp->tempname);
+ if (fd == -1) {
+ perror("Cannot create temporary file");
+ free(tikp->tempname);
+ free(tikp);
+ return NULL;
+ }
+ tikp->command = xstrdup(filename);
+ *fp = NULL;
+ *fdp = fd;
+ break;
+ }
+ if (strcmp(filename, tikp->command) == 0) { /* found it */
+ *linkp = tikp->next; /* unlink it */
+ *fp = XFOPEN(tikp->tempname, OPEN_MODE);
+ if (*fp == NULL) {
+ perror(tikp->tempname);
+ free(tikp->tempname);
+ free(tikp->command);
+ free(tikp);
+ return NULL;
+ }
+ break;
+ }
+ if (tikp->pageno != current_page)
+ freerecp = linkp;
+ linkp = &tikp->next;
+ }
+ tikp->next = tickhead; /* link it in */
+ tickhead = tikp;
+ tikp->pageno = pathinfo != kpse_tex_ps_header_format ? current_page : -1;
+ return tikp;
+}
+
+void
+ps_clear_cache(void)
+{
+ struct tickrec *tikp;
+
+ while (tickhead != NULL) {
+ tikp = tickhead;
+ tickhead = tickhead->next;
+ free(tikp->command);
+ unlink(tikp->tempname);
+ free((char *)tikp->tempname);
+ free(tikp);
+ }
+ nticks = 0;
+}
+
+#ifndef UNCOMPRESS
+#define UNCOMPRESS "uncompress"
+#endif
+
+#ifndef GUNZIP
+#define GUNZIP "gunzip"
+#endif
+
+#ifndef BUNZIP2
+#define BUNZIP2 "bunzip2"
+#endif
+
+static void send_ps_file(const char *filename, kpse_file_format_type pathinfo);
+
+static void
+enable_specials_send_ps_file(XtPointer data)
+{
+ const char *filename = (const char *)data;
+ resource.allow_shell = True;
+ redraw_page(); /* to erase the bounding box */
+ statusline_print(STATUS_MEDIUM,
+ "Shell specials enabled for this session.",
+ filename);
+ send_ps_file(filename, kpse_pict_format);
+}
+
+static void
+try_open_tempname(int status, struct xchild *this)
+{
+ if (WIFEXITED(status)) { /* child exited normally */
+ if (WEXITSTATUS(status) != 0) {
+ /* default error procedure */
+ handle_child_exit(status, this);
+ }
+ else {
+ struct tickrec *tikp = (struct tickrec *)this->data;
+ FILE *f = XFOPEN(tikp->tempname, OPEN_MODE);
+ fprintf(stderr, "FILE: %s\n", tikp->tempname);
+ if (f == NULL) {
+ perror(tikp->tempname);
+ }
+ else {
+ fprintf(stderr, "sending file: %s, %p\n", tikp->tempname, (void *)f);
+ /* There's no point in invoking
+ psp.drawfile(tikp->tempname, f);
+ here, since usually it will be already too late (draw_part() which
+ had called us via applicationDoSpecial() will already have terminated).
+ So instead, we just close the file and force a redraw of the entire page.
+ */
+ fclose(f);
+ globals.ev.flags |= EV_NEWPAGE;
+ }
+ }
+ }
+ else if (WIFSIGNALED(status)) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ "Process `%s' terminated abnormally with signal %d.", this->name, WTERMSIG(status));
+ }
+ else if (WIFSTOPPED(status)) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ "Process `%s' stopped by signal %d.", this->name, WSTOPSIG(status));
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ "Process `%s' terminated with unknown status.", this->name);
+ }
+}
+
+static void
+send_ps_file(const char *filename, kpse_file_format_type pathinfo)
+{
+ FILE *f;
+ int fd;
+ static const char *argv[] = { NULL, "-c", NULL, NULL };
+ char *bufp = NULL;
+ struct tickrec *volatile tikp;
+ size_t len;
+ char magic1, magic2, magic3;
+ static Boolean warned_about_shellescape = False;
+ static size_t ffline_len = 0;
+ static char *ffline = NULL;
+ const size_t FFLINE_STEP = 128;
+
+ if (psp.drawfile == NULL || resource.postscript == 0) {
+ return;
+ }
+
+ if (filename[0] == '`') {
+ if (!resource.allow_shell) {
+ if (!warned_about_shellescape) {
+ choice_dialog_sized(globals.widgets.top_level,
+ MSG_INFO,
+ SIZE_MEDIUM,
+ /* helptext */
+ "To enable shell specials, use the \"-allowshell\" command "
+ "line option.\n\n"
+ "WARNING: You should NOT use shell specials like\n"
+ "`gunzip -c file.eps.gz\n"
+ "(e.g. via \\DeclareGraphicsRule{...}) "
+ "to uncompress .eps.gz files, even though some obsolete "
+ "LaTeX documentation might suggest it. Current versions "
+ "of xdvi and dvips will handle .eps.gz files just fine without this trick.\n",
+#ifndef MOTIF
+ NULL,
+#endif
+ NULL, NULL, /* no pre_callbacks */
+ /* Cancel label/callback */
+ "Cancel", NULL, (XtPointer)NULL,
+ /* Enable label/callback */
+ "Enable", enable_specials_send_ps_file, (XtPointer)filename,
+ /* msg */
+ "This page contains a shell special \"%s\", but execution of shell specials "
+ "is disabled.\n\nYou can now click "
+ "\"Enable\" to enable shell specials for this session only, "
+ "\"Cancel\" to leave the specials disabled, or \"Help\" for more help "
+ "on this topic.\n\n"
+ "Please note that shell specials are a security risk, since they "
+ "allow execution of arbitrary shell commands from the TeX file. "
+ "You should enable them only for DVI files that you created yourself.",
+ filename);
+ warned_about_shellescape = True;
+ }
+ else {
+ statusline_print(STATUS_MEDIUM,
+ "Info: Shell special \"%s\" disabled.",
+ filename);
+ }
+ draw_bbox();
+ return;
+ }
+
+ tikp = cachetick(filename, pathinfo, &f, &fd);
+ if (tikp == NULL) /* if error */
+ return;
+ if (f == NULL) {
+ char *argv[4];
+ /* if not cached, need to create.
+ Fork so that we can collect the process' error messages. */
+
+ /* FIXME: Insecure - this is a /tmp race; shouldn't close(fd), just re-use it */
+ close(fd);
+
+ len = strlen(filename) + strlen(tikp->tempname) + (4 - 1);
+ if (len > ffline_len) {
+ ffline_len += FFLINE_STEP;
+ ffline = xrealloc(ffline, ffline_len);
+ }
+
+ sprintf(ffline, "%s > %s", filename + 1, tikp->tempname);
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = ffline;
+ argv[3] = NULL;
+ fork_process("/bin/sh", False, globals.dvi_file.dirname, try_open_tempname, tikp, argv);
+ }
+ else {
+ bufp = tikp->tempname;
+ psp.drawfile(bufp, f);
+ }
+ }
+ else {
+ char *expanded_filename = NULL;
+ struct stat statbuf;
+ expanded_filename = find_file(filename, &statbuf, pathinfo);
+ if (expanded_filename == NULL &&
+ (pathinfo == kpse_enc_format || pathinfo == kpse_type1_format)) {
+ /* in this case, we also kpathsea-search in the `old' place for
+ backwards compatibility: kpse_tex_ps_header_format (see comment
+ for load_vector(), dvi-draw.c for details) */
+ expanded_filename = kpse_find_file(filename, kpse_tex_ps_header_format, True);
+ }
+ if (expanded_filename == NULL) { /* still no success, complain */
+ /* FIXME: this warning may be overwritten by warning about raw PS specials,
+ so additinally dump to stderr. TODO: make statusline printing respect
+ more important messages. */
+ XDVI_WARNING((stderr, "Could not find graphics file \"%s\"", filename));
+ statusline_print(STATUS_MEDIUM, "Warning: Could not find graphics file \"%s\"",
+ filename);
+ draw_bbox();
+ return;
+ }
+ if (globals.debug & DBG_OPEN)
+ printf("%s:%d: |%s| expanded to |%s|\n", __FILE__, __LINE__, filename, expanded_filename);
+
+ /* may need to adjust ffline_len, ffline */
+ while (strlen(expanded_filename) + 1 > ffline_len) {
+ ffline_len += FFLINE_STEP;
+ ffline = xrealloc(ffline, ffline_len);
+ }
+ strcpy(ffline, expanded_filename);
+ bufp = ffline;
+ f = XFOPEN(expanded_filename, OPEN_MODE);
+ free(expanded_filename);
+ ASSERT(f != NULL, "Internal error opening file");
+
+ /* check for compressed files */
+ len = strlen(filename);
+ magic1 = '\037';
+ magic3 = '\0';
+ if ((len > 2 && strcmp(filename + len - 2, ".Z") == 0
+ && (argv[0] = UNCOMPRESS, magic2 = '\235', True))
+ || (len > 3 && strcmp(filename + len - 3, ".gz") == 0
+ && (argv[0] = GUNZIP, magic2 = '\213', True))
+ || (len > 4 && strcmp(filename + len - 4, ".bz2") == 0
+ && (argv[0] = BUNZIP2, magic1 = 'B', magic2 = 'Z',
+ magic3 = 'h', True))) {
+ if (getc(f) != magic1 || (char)getc(f) != magic2
+ || (magic3 != '\0' && getc(f) != magic3)) {
+ rewind(f);
+ }
+ else {
+ fclose(f);
+
+ tikp = cachetick(filename, pathinfo, &f, &fd);
+ if (tikp == NULL) /* if error */
+ return;
+ if (f == NULL) { /* if not cached, need to create */
+ pid_t pid;
+ int status;
+
+ argv[2] = bufp;
+ fflush(stderr); /* avoid double flushing */
+ pid = vfork();
+ if (pid == 0) { /* if child */
+ (void)dup2(fd, 1);
+ (void)execvp(argv[0], (char **)argv);
+ XDVI_ERROR((stderr, "Execvp of %s failed: %s", argv[0], strerror(errno)));
+ _exit(EXIT_FAILURE);
+ }
+ (void)close(fd);
+
+ for (;;) {
+#if HAVE_WAITPID
+ if (waitpid(pid, &status, 0) != -1)
+ break;
+#else
+# if HAVE_WAIT4
+ if (wait4(pid, &status, 0, (struct rusage *)NULL)
+ != -1)
+ break;
+# else
+ int retval;
+
+ retval = wait(&status);
+ if (retval == pid)
+ break;
+ if (retval != -1)
+ continue;
+# endif /* HAVE_WAIT4 */
+#endif /* HAVE_WAITPID */
+ if (errno == EINTR)
+ continue;
+ perror("[xdvik] waitpid");
+ return;
+ }
+ f = XFOPEN(tikp->tempname, OPEN_MODE);
+ if (f == NULL) {
+ perror(tikp->tempname);
+ return;
+ }
+ }
+ bufp = tikp->tempname;
+ }
+ }
+ /* Success! */
+ psp.drawfile(bufp, f); /* this is supposed to close the file */
+ }
+}
+
+
+void
+ps_destroy(void)
+{
+ struct tickrec *tikp;
+
+ /* Note: old NeXT systems (at least) lack atexit/on_exit. */
+ psp.destroy();
+ for (tikp = tickhead; tikp != NULL; tikp = tikp->next)
+ if (unlink(tikp->tempname) < 0)
+ perror(tikp->tempname);
+}
+
+#endif /* PS */
+
+
+void
+init_prescan(void)
+{
+#if PS
+ struct tickrec *tikp;
+#endif
+
+ scanned_page = scanned_page_reset = resource.prescan ? -1 : total_pages + 1;
+#if PS
+ scanned_page_ps = scanned_page_ps_bak = scanned_page;
+#if COLOR
+ scanned_page_color = scanned_page;
+#endif /* COLOR */
+#endif /* PS */
+
+ TRACE_FILES((stderr, "init_prescan: scanned_page = %d", scanned_page));
+#if PS
+ if (resource.postscript == 0)
+ scanned_page_ps = total_pages + 1;
+
+ for (tikp = tickhead; tikp != NULL; tikp = tikp->next)
+ tikp->pageno = -1;
+ psp.newdoc();
+#endif
+
+#if COLOR
+ if (!resource.use_color)
+ scanned_page_color = total_pages + 1;
+#endif
+
+ if (ignore_papersize_specials) {
+#if PS && COLOR
+ scanned_page = scanned_page_ps < scanned_page_color ? scanned_page_ps : scanned_page_color;
+#elif PS
+ scanned_page = scanned_page_ps;
+#elif COLOR
+ scanned_page = scanned_page_color;
+#else
+ scanned_page = total_pages + 1;
+#endif
+ }
+}
+
+
+static void
+psfig_special(char *cp)
+{
+ char *filename;
+ int raww, rawh;
+
+ if (strncmp(cp, ":[begin]", 8) == 0) {
+ cp += 8;
+ bbox_valid = False;
+ bbox_angle = 0;
+ if (sscanf(cp, "%d %d\n", &raww, &rawh) >= 2) {
+ bbox_valid = True;
+ bbox_width = pixel_conv(spell_conv(raww));
+ bbox_height = pixel_conv(spell_conv(rawh));
+ bbox_voffset = 0;
+ }
+ if (INSIDE_MANE_WIN) {
+#if PS
+ psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, cp);
+#else
+ draw_bbox();
+#endif
+ }
+ psfig_begun = True;
+ }
+ else if (strncmp(cp, " plotfile ", 10) == 0) {
+ cp += 10;
+ while (isspace((int)*cp))
+ cp++;
+ /* handle "`zcat file". Borrowed from dvipsk... */
+ if (*cp == '"') {
+ cp++;
+ for (filename = cp; *cp && (*cp != '"'); ++cp);
+ }
+ else {
+ for (filename = cp; *cp && !isspace((int)*cp); ++cp);
+ }
+ *cp = '\0';
+#if PS
+ if (INSIDE_MANE_WIN)
+ send_ps_file(filename, kpse_pict_format);
+#endif
+ }
+ else if (strncmp(cp, ":[end]", 6) == 0) {
+ cp += 6;
+#if PS
+ if (INSIDE_MANE_WIN) {
+ psp.drawend(cp);
+ }
+#endif
+ bbox_valid = False;
+ psfig_begun = False;
+ }
+ else if (*cp == ':') {
+ /* I am going to send some raw postscript stuff */
+ ++cp; /* skip the colon */
+#if PS
+ if (ps_parseraw(cp))
+ have_raw_postscript = True;
+ if (INSIDE_MANE_WIN)
+ psp.drawraw(cp);
+#endif
+ }
+ else { /* attempt to parse pstricks color specials */
+#if COLOR
+ struct rgb color;
+ if (parse_color(cp, cp, &color, True)) {
+ /* clear stack */
+ if (rcs_head == NULL) {
+ rcs_head = xmalloc(sizeof *rcs_head);
+ rcs_head->prev = rcs_head->next = NULL;
+ }
+ rcs_top = rcs_head;
+ color_bot_size = 0;
+
+ /* Change top of stack */
+ rcs_top->color = color;
+
+ set_fg_color(&color);
+ }
+#endif
+ /* also raw PostScript, but no extra colon to skip */
+#if PS
+ if (INSIDE_MANE_WIN) {
+ if (ps_parseraw(cp))
+ have_raw_postscript = True;
+
+ if (psfig_begun)
+ psp.drawraw(cp);
+ else {
+ psp.drawbegin(PXL_H - currwin.base_x,
+ PXL_V - currwin.base_y, cp);
+ psp.drawend("");
+ }
+ }
+#endif
+ }
+}
+
+
+/* Keys for epsf specials */
+
+static const char *keytab[] = { "clip",
+ "llx",
+ "lly",
+ "urx",
+ "ury",
+ "rwi",
+ "rhi",
+ "hsize",
+ "vsize",
+ "hoffset",
+ "voffset",
+ "hscale",
+ "vscale",
+ "angle"
+};
+
+#define KEY_LLX keyval[0]
+#define KEY_LLY keyval[1]
+#define KEY_URX keyval[2]
+#define KEY_URY keyval[3]
+#define KEY_RWI keyval[4]
+#define KEY_RHI keyval[5]
+
+#define NKEYS (sizeof keytab /sizeof *keytab)
+#define N_ARGLESS_KEYS 1
+
+static void
+epsf_special(char *cp)
+{
+ char *filename;
+ static char *buffer;
+ static unsigned int buflen = 0;
+ unsigned int len;
+ char *q;
+ int flags = 0;
+ double keyval[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+
+ filename = cp;
+ if (*cp == '\'' || *cp == '"') {
+ do
+ ++cp;
+ while (*cp != '\0' && *cp != *filename);
+ ++filename;
+ }
+ else
+ while (*cp != '\0' && !isspace((int)*cp))
+ ++cp;
+ if (*cp != '\0')
+ *cp++ = '\0';
+ while (isspace((int)*cp))
+ ++cp;
+ len = strlen(cp) + NKEYS + 30;
+ if (buflen < len) {
+ if (buflen != 0)
+ free(buffer);
+ buflen = len;
+ buffer = xmalloc(buflen);
+ }
+ strcpy(buffer, "@beginspecial");
+ q = buffer + strlen(buffer);
+ while (*cp != '\0') {
+ char *p1 = cp;
+ size_t keyno;
+
+ while (*p1 != '=' && !isspace((int)*p1) && *p1 != '\0')
+ ++p1;
+ for (keyno = 0;; ++keyno) {
+ if (keyno >= NKEYS) {
+ if (globals.warn_spec_now)
+ XDVI_WARNING((stderr, "Ignoring unknown keyword (%.*s) in \\special",
+ (int)(p1 - cp), cp));
+ break;
+ }
+ if (memcmp(cp, keytab[keyno], p1 - cp) == 0) {
+ if (keyno >= N_ARGLESS_KEYS) {
+ while (isspace((int)*p1))
+ ++p1;
+ if (*p1 == '=') {
+ ++p1;
+ while (isspace((int)*p1))
+ ++p1;
+ }
+ if (keyno < N_ARGLESS_KEYS + 6) {
+ keyval[keyno - N_ARGLESS_KEYS] = atof(p1);
+ flags |= (1 << (keyno - N_ARGLESS_KEYS));
+ }
+ *q++ = ' ';
+ while (!isspace((int)*p1) && *p1 != '\0')
+ *q++ = *p1++;
+ }
+ *q++ = ' ';
+ *q++ = '@';
+ strcpy(q, keytab[keyno]);
+ q += strlen(q);
+ break;
+ }
+ }
+ cp = p1;
+ while (!isspace((int)*cp) && *cp != '\0')
+ ++cp;
+ while (isspace((int)*cp))
+ ++cp;
+ }
+ strcpy(q, " @setspecial\n");
+
+ bbox_valid = False;
+ /* Validate the case where both rwi and rhi are undefined
+ * (and llx, lly, urx, ury are properly defined) */
+ if (!(flags & 0x30) && (flags & 0xf) == 0xf) {
+ KEY_RWI = (KEY_URX - KEY_LLX) * 10;
+ flags |= 0x10;
+ }
+ if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf)) {
+ bbox_valid = True;
+ bbox_width = 0.1 * ((flags & 0x10) ? KEY_RWI
+ : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY -
+ KEY_LLY)) *
+ dimconv / currwin.shrinkfactor + 0.5;
+ bbox_voffset = bbox_height =
+ 0.1 * ((flags & 0x20) ? KEY_RHI : KEY_RWI * (KEY_URY - KEY_LLY) /
+ (KEY_URX - KEY_LLX))
+ * dimconv / currwin.shrinkfactor + 0.5;
+ }
+
+ if (INSIDE_MANE_WIN) {
+#if PS
+ psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y, buffer);
+ /* talk directly with the DPSHandler here */
+ send_ps_file(filename, kpse_pict_format);
+ psp.drawend(" @endspecial");
+#else
+ draw_bbox();
+#endif
+ }
+ bbox_valid = False;
+}
+
+
+static void
+quote_special(char *cp)
+{
+ bbox_valid = False;
+
+#if PS
+ if (currwin.win == mane.win) {
+ psp.drawbegin(PXL_H - currwin.base_x, PXL_V - currwin.base_y,
+ "@beginspecial @setspecial ");
+ /* talk directly with the DPSHandler here */
+ psp.drawraw(cp + 1);
+ psp.drawend(" @endspecial");
+ }
+#endif
+
+ /* nothing else to do--there's no bbox here */
+}
+
+#if PS
+
+static void
+scan_header(char *cp)
+{
+ char *filename;
+ /* default for .pro files: */
+ kpse_file_format_type our_format;
+
+#if PS_GS
+ if (gs_postpone_prescan)
+ return;
+#endif
+ filename = cp;
+ if (*cp == '\'' || *cp == '"') {
+ do
+ ++cp;
+ while (*cp != '\0' && *cp != *filename);
+ *cp = '\0';
+ ++filename;
+ }
+
+ psp.beginheader();
+ /* check for suffixes other than `.pro' (default PS headers),
+ case-insensitive */
+ if (str_is_suffix(".pfa", filename, False)
+ || str_is_suffix(".pfb", filename, False))
+ our_format = kpse_type1_format;
+ else if (str_is_suffix(".enc", filename, False))
+ our_format = kpse_enc_format;
+ else
+ our_format = kpse_tex_ps_header_format;
+
+ send_ps_file(filename, our_format);
+}
+
+static void
+scan_bang(char *cp)
+{
+ psp.beginheader();
+ psp.drawraw(cp + 1);
+}
+
+#endif /* PS */
+
+#if COLOR
+
+/*
+ * Table of dvips color names. Produced by passing the table in
+ * dvipsk/color.lpro through the following perl script, and then
+ * through sort.
+ *
+ * #! /usr/bin/perl -w
+ *
+ * sub cvpart {
+ * return $_[0] < 1.0 ? 1.0 - $_[0] : 0.0;
+ * }
+ *
+ * $pat = "^\\/(\\w+)\\s*\\{\\s*([0-9.]+)\\s*([0-9.]+)\\s*([0-9.]+)"
+ * . "\\s*([0-9.]+)\\s*setcmykcolor\\s*\\}\\s*DC\\s*\$";
+ * while (<STDIN>) {
+ * chop;
+ * if (/^%%/) {next;}
+ * if (/$pat/o) {
+ * printf "\t\tDVIPSCOLORDESC(%2d, \"%s\", %g, %g, %g),\n",
+ * length($1), $1,
+ * cvpart($2 + $5), cvpart($3 + $5), cvpart($4 + $5);
+ * }
+ * else {
+ * print "Bad line: ", $_, "\n";
+ * }
+ * }
+ */
+
+struct dvipscolor {
+ const char *name;
+ struct rgb color;
+};
+
+static Boolean
+parse_color(const char *cp0, const char *cp,
+ struct rgb *rgbp, Boolean generic_ps_flag)
+{
+ double r, g, b;
+ double k;
+ double hue, sat, bri;
+ char dummy[8];
+
+#define CVPART(x) ((int)((x) * 65535 + 0.5))
+#define COLOR_DESC(name, r, g, b) \
+ {name, {CVPART(r), CVPART(g), CVPART(b)}}
+
+ /* hash table to speed up lookup in following list of color names */
+ static hashTableT colornames_hash;
+ /*
+ Use a prime close to sizof colornames / sizeof colornames[0].
+ You might want to update this when extending the colornames array,
+ and to check the filling factor and average chain length by uncommenting the
+ hash_print(colornames_hash, True);
+ below. I usually go for filling > 50% and avg. chain len < 2.
+
+ The 68-elem array below results in:
+ 79 buckets, 43 nonempty (54%); 68 entries, average chain 1.6.
+ */
+ static const size_t colornames_hash_size = 79;
+
+ static struct dvipscolor colornames[] = {
+ COLOR_DESC("Red", 1, 0, 0),
+ COLOR_DESC("Tan", 0.86, 0.58, 0.44),
+ COLOR_DESC("Blue", 0, 0, 1),
+ COLOR_DESC("Cyan", 0, 1, 1),
+ COLOR_DESC("Gray", 0.5, 0.5, 0.5),
+ COLOR_DESC("Plum", 0.5, 0, 1),
+ COLOR_DESC("Black", 0, 0, 0),
+ COLOR_DESC("Brown", 0.4, 0, 0),
+ COLOR_DESC("Green", 0, 1, 0),
+ COLOR_DESC("Melon", 1, 0.54, 0.5),
+ COLOR_DESC("Peach", 1, 0.5, 0.3),
+ COLOR_DESC("Sepia", 0.3, 0, 0),
+ COLOR_DESC("White", 1, 1, 1),
+ COLOR_DESC("Maroon", 0.68, 0, 0),
+ COLOR_DESC("Orange", 1, 0.39, 0.13),
+ COLOR_DESC("Orchid", 0.68, 0.36, 1),
+ COLOR_DESC("Purple", 0.55, 0.14, 1),
+ COLOR_DESC("Salmon", 1, 0.47, 0.62),
+ COLOR_DESC("Violet", 0.21, 0.12, 1),
+ COLOR_DESC("Yellow", 1, 1, 0),
+ COLOR_DESC("Apricot", 1, 0.68, 0.48),
+ COLOR_DESC("Emerald", 0, 1, 0.5),
+ COLOR_DESC("Fuchsia", 0.45, 0.01, 0.92),
+ COLOR_DESC("Magenta", 1, 0, 1),
+ COLOR_DESC("SkyBlue", 0.38, 1, 0.88),
+ COLOR_DESC("Thistle", 0.88, 0.41, 1),
+ COLOR_DESC("BrickRed", 0.72, 0, 0),
+ COLOR_DESC("Cerulean", 0.06, 0.89, 1),
+ COLOR_DESC("Lavender", 1, 0.52, 1),
+ COLOR_DESC("Mahogany", 0.65, 0, 0),
+ COLOR_DESC("Mulberry", 0.64, 0.08, 0.98),
+ COLOR_DESC("NavyBlue", 0.06, 0.46, 1),
+ COLOR_DESC("SeaGreen", 0.31, 1, 0.5),
+ COLOR_DESC("TealBlue", 0.12, 0.98, 0.64),
+ COLOR_DESC("BlueGreen", 0.15, 1, 0.67),
+ COLOR_DESC("CadetBlue", 0.38, 0.43, 0.77),
+ COLOR_DESC("Dandelion", 1, 0.71, 0.16),
+ COLOR_DESC("Goldenrod", 1, 0.9, 0.16),
+ COLOR_DESC("LimeGreen", 0.5, 1, 0),
+ COLOR_DESC("OrangeRed", 1, 0, 0.5),
+ COLOR_DESC("PineGreen", 0, 0.75, 0.16),
+ COLOR_DESC("RawSienna", 0.55, 0, 0),
+ COLOR_DESC("RedOrange", 1, 0.23, 0.13),
+ COLOR_DESC("RedViolet", 0.59, 0, 0.66),
+ COLOR_DESC("Rhodamine", 1, 0.18, 1),
+ COLOR_DESC("RoyalBlue", 0, 0.5, 1),
+ COLOR_DESC("RubineRed", 1, 0, 0.87),
+ COLOR_DESC("Turquoise", 0.15, 1, 0.8),
+ COLOR_DESC("VioletRed", 1, 0.19, 1),
+ COLOR_DESC("Aquamarine", 0.18, 1, 0.7),
+ COLOR_DESC("BlueViolet", 0.1, 0.05, 0.96),
+ COLOR_DESC("DarkOrchid", 0.6, 0.2, 0.8),
+ COLOR_DESC("OliveGreen", 0, 0.6, 0),
+ COLOR_DESC("Periwinkle", 0.43, 0.45, 1),
+ COLOR_DESC("Bittersweet", 0.76, 0.01, 0),
+ COLOR_DESC("BurntOrange", 1, 0.49, 0),
+ COLOR_DESC("ForestGreen", 0, 0.88, 0),
+ COLOR_DESC("GreenYellow", 0.85, 1, 0.31),
+ COLOR_DESC("JungleGreen", 0.01, 1, 0.48),
+ COLOR_DESC("ProcessBlue", 0.04, 1, 1),
+ COLOR_DESC("RoyalPurple", 0.25, 0.1, 1),
+ COLOR_DESC("SpringGreen", 0.74, 1, 0.24),
+ COLOR_DESC("YellowGreen", 0.56, 1, 0.26),
+ COLOR_DESC("MidnightBlue", 0, 0.44, 0.57),
+ COLOR_DESC("YellowOrange", 1, 0.58, 0),
+ COLOR_DESC("CarnationPink", 1, 0.37, 1),
+ COLOR_DESC("CornflowerBlue", 0.35, 0.87, 1),
+ COLOR_DESC("WildStrawberry", 1, 0.04, 0.61),
+ };
+#undef CVPART
+#undef COLOR_DESC
+
+ UNUSED(cp0);
+
+ while (*cp == ' ') ++cp;
+
+ if (generic_ps_flag) {
+ /*
+ check for pstricks color specials.
+ The dummy buffer is to ensure that there are no other (general PS)
+ commands following (we wouldn't know how to deal with these).
+ */
+ if (sscanf(cp, "%lf %lf %lf setrgbcolor %7s", &r, &g, &b, dummy) == 3
+ && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) {
+ rgbp->r = r * 65535 + 0.5;
+ rgbp->g = g * 65535 + 0.5;
+ rgbp->b = b * 65535 + 0.5;
+ return True;
+ }
+ else if (sscanf(cp, "%lf %lf %lf %lf setcmykcolor %7s", &r, &g, &b, &k, dummy) == 4
+ && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1
+ && k >= 0 && k <= 1) {
+ r = 1.0 - r - k; /* cyan --> red */
+ rgbp->r = (r < 0 ? 0 : r * 65535 + 0.5);
+ g = 1.0 - g - k; /* magenta --> green */
+ rgbp->g = (g < 0 ? 0 : g * 65535 + 0.5);
+ b = 1.0 - b - k; /* yellow --> blue */
+ rgbp->b = (b < 0 ? 0 : b * 65535 + 0.5);
+ return True;
+ }
+ else if (sscanf(cp, "%lf %lf %lf sethsbcolor %7s", &hue, &sat, &bri, dummy) == 3 && hue >= 0
+ && hue <= 1 && sat >= 0 && sat <= 1 && bri >= 0 && bri <= 1) {
+ int h = (int) (6 * hue);
+ double p = bri * (1 - sat);
+ double q = bri * (1 - sat * (6 * hue - h));
+ double t = p - q + bri;
+
+ switch (h) {
+ case 0: r = bri; g = t; b = p; break; /* Red - Yel */
+ case 1: r = q; g = bri; b = p; break; /* Yel - Grn */
+ case 2: r = p; g = bri; b = t; break; /* Grn - Cyn */
+ case 3: r = p; g = q; b = bri; break; /* Cyn - Blu */
+ case 4: r = t; g = p; b = bri; break; /* Blu - Mag */
+ case 5: r = bri; g = p; b = q; break; /* Mag - Red */
+ case 6: r = bri; g = b = p; break; /* Red */
+ }
+ rgbp->r = r * 65535 + 0.5;
+ rgbp->g = g * 65535 + 0.5;
+ rgbp->b = b * 65535 + 0.5;
+ return True;
+ }
+ else if (sscanf(cp, "%lf setgray %7s", &r, dummy) == 1 && r >= 0 && r <= 1) {
+ rgbp->r = rgbp->g = rgbp->b = r * 65535 + 0.5;
+ return True;
+ }
+ else
+ return False;
+ }
+
+ /* no generic PS command; must be a dvips color special */
+
+ if (memicmp(cp, "rgb ", 4) == 0) {
+ if (sscanf(cp + 3, "%lf %lf %lf", &r, &g, &b) == 3
+ && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) {
+ rgbp->r = r * 65535 + 0.5;
+ rgbp->g = g * 65535 + 0.5;
+ rgbp->b = b * 65535 + 0.5;
+ return True;
+ }
+ }
+ else if (memicmp(cp, "gray ", 5) == 0) {
+ if (sscanf(cp + 4, "%lf", &r) == 1 && r >= 0 && r <= 1) {
+ rgbp->r = rgbp->g = rgbp->b = r * 65535 + 0.5;
+ return True;
+ }
+ }
+ else if (memicmp(cp, "cmyk ", 5) == 0) {
+ if (sscanf(cp + 4, "%lf %lf %lf %lf", &r, &g, &b, &k) == 4
+ && r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1
+ && k >= 0 && k <= 1) {
+ r = 1.0 - r - k; /* cyan --> red */
+ rgbp->r = (r < 0 ? 0 : r * 65535 + 0.5);
+ g = 1.0 - g - k; /* magenta --> green */
+ rgbp->g = (g < 0 ? 0 : g * 65535 + 0.5);
+ b = 1.0 - b - k; /* yellow --> blue */
+ rgbp->b = (b < 0 ? 0 : b * 65535 + 0.5);
+ return True;
+ }
+ }
+ else if (memicmp(cp, "hsb ", 4) == 0) {
+ if (sscanf(cp + 3, "%lf %lf %lf", &hue, &sat, &bri) == 3 && hue >= 0
+ && hue <= 1 && sat >= 0 && sat <= 1 && bri >= 0 && bri <= 1) {
+ int h = (int) (6 * hue);
+ double p = bri * (1 - sat);
+ double q = bri * (1 - sat * (6 * hue - h));
+ double t = p - q + bri;
+
+ switch (h) {
+ case 0: r = bri; g = t; b = p; break; /* Red - Yel */
+ case 1: r = q; g = bri; b = p; break; /* Yel - Grn */
+ case 2: r = p; g = bri; b = t; break; /* Grn - Cyn */
+ case 3: r = p; g = q; b = bri; break; /* Cyn - Blu */
+ case 4: r = t; g = p; b = bri; break; /* Blu - Mag */
+ case 5: r = bri; g = p; b = q; break; /* Mag - Red */
+ case 6: r = bri; g = b = p; break; /* Red */
+ }
+ rgbp->r = r * 65535 + 0.5;
+ rgbp->g = g * 65535 + 0.5;
+ rgbp->b = b * 65535 + 0.5;
+ return True;
+ }
+ }
+ else { /* is it a dvips color name? */
+ size_t idx;
+ size_t len = 0;
+ static char *testname = NULL;
+ static size_t testname_len = 0;
+ size_t testname_step = 16;
+
+ if (colornames_hash.size == 0) { /* initialize hash table */
+ size_t i;
+ colornames_hash = hash_create(colornames_hash_size);
+ /* insert color names and array indexes */
+ for (i = 0; i < (sizeof colornames / sizeof colornames[0]); i++) {
+ put_str_int_hash(&colornames_hash, colornames[i].name, i);
+ }
+ }
+ /* uncomment the following to get statistics on hashing: */
+ /* hash_print(colornames_hash, True); */
+
+ /* need to copy to a null-terminated string for hash lookup ... */
+ while (isalpha((int)cp[len])) {
+ ++len; /* get length of color name */
+ }
+ while (len >= testname_len) {
+ testname_len += testname_step;
+ testname = xrealloc(testname, testname_len);
+ }
+ memcpy(testname, cp, len);
+ testname[len] = '\0';
+
+ if (find_str_int_hash(&colornames_hash, testname, &idx)) {
+ *rgbp = colornames[idx].color;
+ return True;
+ }
+ }
+
+ /* not found */
+ XDVI_WARNING((stderr, "Ignoring invalid color name in special `%s'", cp0 == NULL ? "<NULL>" : cp0));
+ return False;
+}
+
+void
+init_page_colors(struct rgb *foreground, struct rgb *background)
+{
+ int i;
+
+ page_colors.size = total_pages;
+ page_colors.stack = xmalloc(page_colors.size * sizeof *page_colors.stack);
+
+ for (i = 0; i <= scanned_page + 1; ++i) {
+ page_colors.stack[i].bg = *background;
+ page_colors.stack[i].colorstack = foreground;
+ page_colors.stack[i].stacksize = 1;
+ }
+ for (; i < total_pages; i++) {
+ page_colors.stack[i].colorstack = NULL;
+ }
+
+ scanstack_head.color = *foreground;
+ scanstack_len = 1; /* nothing yet */
+ scanstack_current = &scanstack_head; /* stack position */
+}
+
+
+static void
+scan_bg_color(const char *cp)
+{
+ if (!resource.use_color)
+ return;
+
+ if (page_colors.stack == NULL)
+ init_page_colors(&fg_initial, &bg_initial);
+
+ ASSERT(scanned_page < (int)page_colors.size, "page_colors.size too small");
+ (void) parse_color(cp, cp + 11, &(page_colors.stack[scanned_page + 1].bg), False);
+}
+
+void
+scan_color(const char *cp)
+{
+ const char *cp1 = cp + 6;
+
+ if (!resource.use_color)
+ return;
+
+ while (*cp1 == ' ') ++cp1;
+
+ if (page_colors.stack == NULL)
+ init_page_colors(&fg_initial, &bg_initial);
+
+ if (memicmp(cp1, "push ", 5) == 0) {
+ if (scanstack_current->next == NULL) { /* if at end */
+ scanstack_current->next = xmalloc(sizeof *scanstack_current);
+ scanstack_current->next->prev = scanstack_current;
+ scanstack_current->next->next = NULL;
+ }
+ scanstack_current = scanstack_current->next;
+ ++scanstack_len;
+ if (!parse_color(cp, cp1 + 5, &scanstack_current->color, False))
+ scanstack_current->color = scanstack_current->prev->color;
+ }
+ else if (memicmp(cp1, "pop", 3) == 0) {
+ if (scanstack_len <= 1) {
+ XDVI_WARNING((stderr, "Color pop occurred with empty color stack."));
+ }
+ else {
+ scanstack_current = scanstack_current->prev;
+ --scanstack_len;
+ }
+ }
+ else {
+ (void) parse_color(cp, cp1, &scanstack_head.color, False);
+ if (scanstack_len > 1) {
+ struct colorframe *cfp;
+
+ XDVI_WARNING((stderr, "Global color change occurred with non-empty color stack!\n"
+ "Trying to recover by setting all stack entries to that color."));
+ for (cfp = scanstack_head.next;; cfp = cfp->next) {
+ cfp->color = scanstack_head.color;
+ if (cfp == scanstack_current) break;
+ }
+ }
+ }
+}
+
+void
+scan_color_eop(void)
+{
+ int i;
+ struct rgb *prev, *p1, *rgbp;
+ struct colorframe *cf;
+
+ if (page_colors.stack == NULL)
+ return;
+
+ /* set background color for next page */
+ if (scanned_page + 1 < total_pages) {
+ ASSERT(scanned_page + 1 < (int)page_colors.size, "page_colors.size too small");
+ page_colors.stack[scanned_page + 1].bg = page_colors.stack[scanned_page].bg;
+ }
+ ASSERT(scanned_page < (int)page_colors.size, "page_colors.size too small");
+ /* save the stack contents */
+ page_colors.stack[scanned_page].stacksize = scanstack_len;
+
+ prev = &fg_initial;
+ i = 1;
+ if (scanned_page > 0) {
+ prev = page_colors.stack[scanned_page - 1].colorstack;
+ i = page_colors.stack[scanned_page - 1].stacksize;
+ }
+ if (scanstack_len <= i) {
+ /* try to reuse the previous array */
+ p1 = prev;
+ cf = &scanstack_head;
+ for (i = 0;;) {
+ if (p1->r != cf->color.r || p1->g != cf->color.g || p1->b != cf->color.b)
+ break;
+ if (++i >= scanstack_len) { /* end loop; reuse memory */
+ page_colors.stack[scanned_page].colorstack = prev;
+ return; /* done */
+ }
+ ++p1;
+ cf = cf->next;
+ }
+ }
+ page_colors.stack[scanned_page].colorstack = rgbp = xmalloc(scanstack_len * sizeof *rgbp);
+ cf = &scanstack_head;
+ for (i = 0; i < scanstack_len; ++i) {
+ *rgbp++ = cf->color;
+ cf = cf->next;
+ }
+}
+
+
+/*
+ * We don't actually do any X calls yet to change colors; that can wait
+ * until a character or rule needs to be drawn.
+ */
+
+void
+set_fg_color(const struct rgb *color)
+{
+ struct fgrec **fgpp;
+
+ if (fg_current != NULL
+ && color->r == fg_current->color.r
+ && color->g == fg_current->color.g
+ && color->b == fg_current->color.b) {
+ return;
+ }
+
+ ASSERT(bg_current != NULL, "Background color not initialized");
+ for (fgpp = &bg_current->fg_head;;) {
+ fg_current = *fgpp;
+ if (fg_current == NULL) { /* if color is not in list */
+ fg_current = *fgpp = xmalloc(sizeof *fg_current);
+ fg_current->next = NULL;
+ fg_current->color = *color;
+ fg_current->pixel_good = False;
+#if GREY
+ fg_current->palette_good = False;
+#endif
+ break;
+ }
+ if (fg_current->color.r == color->r
+ && fg_current->color.g == color->g
+ && fg_current->color.b == color->b)
+ break;
+ fgpp = &fg_current->next;
+ }
+ if (globals.debug & DBG_DVI)
+ printf("Changing fg color to %5d %5d %5d\n",
+ color->r, color->g, color->b);
+}
+
+#if 0
+static void
+show_stack(void) {
+ struct colorframe *ptr;
+ int i;
+ fprintf(stderr, "FG: %d,%d,%d\n", fg_current->color.r, fg_current->color.b, fg_current->color.g);
+ for (i = 0, ptr = rcs_top; ptr != NULL; ptr = ptr->prev, i++) {
+ fprintf(stderr, "stack %d: %d,%d,%d\n", i, ptr->color.r, ptr->color.b, ptr->color.g);
+ }
+}
+#endif
+
+void
+color_special(const char *cp)
+{
+ while (*cp == ' ') ++cp;
+
+ if (memicmp(cp, "push ", 5) == 0) {
+ if (rcs_top == NULL) {
+ if (rcs_head == NULL) {
+ rcs_head = xmalloc(sizeof *rcs_head);
+ rcs_head->prev = rcs_head->next = NULL;
+ }
+ rcs_top = rcs_head;
+ }
+ else {
+ struct colorframe *rcs_next;
+
+ rcs_next = rcs_top->next;
+ if (rcs_next == NULL) {
+ rcs_next = rcs_top->next = xmalloc(sizeof *rcs_next);
+ rcs_next->prev = rcs_top;
+ rcs_next->next = NULL;
+ }
+ rcs_top = rcs_next;
+ }
+ if (!parse_color(NULL, cp + 5, &rcs_top->color, False)) {
+ if (rcs_top->prev != NULL)
+ rcs_top->color = rcs_top->prev->color;
+ else
+ rcs_top->color = color_bottom[color_bot_size - 1];
+ }
+ set_fg_color(&rcs_top->color);
+ }
+ else if (memicmp(cp, "pop", 3) == 0) {
+ /* Pop stack */
+ if (rcs_top != NULL) {
+ if (color_bot_size > 0)
+ rcs_top = rcs_top->prev;
+ else
+ return;
+ }
+ else if (color_bot_size > 1)
+ --color_bot_size;
+ else {
+ if (scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page = scanned_page_color = scanned_page_reset = -1;
+#if PS
+ scanned_page_ps = scanned_page;
+#endif
+/* fprintf(stderr, "forcing redraw!!!\n"); */
+ globals.ev.flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(globals.ev.canit, 1);
+ }
+ return;
+ }
+/* fprintf(stderr, "bot_size: %d\n", color_bot_size); */
+ set_fg_color(rcs_top != NULL ? &rcs_top->color
+ : &color_bottom[color_bot_size - 1]);
+ }
+ else {
+ struct rgb color;
+
+ if (!parse_color(NULL, cp, &color, False))
+ return;
+
+ /* clear stack */
+ if (rcs_head == NULL) {
+ rcs_head = xmalloc(sizeof *rcs_head);
+ rcs_head->prev = rcs_head->next = NULL;
+ }
+ rcs_top = rcs_head;
+ color_bot_size = 0;
+
+ /* Change top of stack */
+ rcs_top->color = color;
+
+ set_fg_color(&color);
+ }
+}
+
+#endif /* COLOR */
+
+static unsigned int
+myatopix(const char **pp)
+{
+#define SCR_LEN 16
+ unsigned int value;
+ const char *cp = *pp;
+ char scr[16];
+ const char *p0, *p1;
+
+ p0 = cp;
+ while ((*cp >= '0' && *cp <= '9') || *cp == '.')
+ ++cp;
+ p1 = cp;
+ while (isspace((int)*cp))
+ ++cp;
+ if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z') {
+ /* if units are present */
+ if (p1 - p0 <= SCR_LEN - 3) {
+ sprintf(scr, "%.*s%c%c", (int)(p1 - p0), p0, *cp, cp[1]);
+ value = atopix(scr, False);
+ }
+ else
+ value = 0;
+ cp += 2;
+ }
+ else
+ value = atopix(p0, False);
+
+ *pp = cp;
+ return value;
+#undef SCR_LEN
+}
+
+static void
+scan_papersize(const char *cp0)
+{
+ const char *cp = cp0;
+ unsigned int w, h;
+ double mag = 1.0;
+
+ if (ignore_papersize_specials)
+ return;
+
+ if (*cp == '*') {
+ do
+ ++cp;
+ while (isspace((int)*cp));
+ mag = magnification * .001;
+ }
+
+ w = myatopix(&cp) * mag + 0.5;
+
+ while (isspace((int)*cp))
+ ++cp;
+ if (*cp == ',')
+ do
+ ++cp;
+ while (isspace((int)*cp));
+
+ h = myatopix(&cp) * mag + 0.5;
+
+ if (w == 0 || h == 0)
+ XDVI_WARNING((stderr, "Invalid papersize special `%s'", cp0));
+ else {
+ /* we have a paper size special; disable xdvirc_geometry:
+ fprintf(stderr, "---------- scanned papersize: %dx%d\n", w, h);
+ resource.xdvirc_geometry = NULL;
+ */
+ pageinfo_set_page_width(scanned_page + 1, w);
+ pageinfo_set_window_width(scanned_page + 1, w);
+ pageinfo_set_page_height(scanned_page + 1, h);
+ pageinfo_set_window_height(scanned_page + 1, h);
+ }
+}
+
+/*
+ * The following copyright message applies to the rest of this file. --PV
+ */
+
+/*
+ * This program is Copyright (C) 1987 by the Board of Trustees of the
+ * University of Illinois, and by the author Dirk Grunwald.
+ *
+ * This program may be freely copied, as long as this copyright
+ * message remaines affixed. It may not be sold, although it may
+ * be distributed with other software which is sold. If the
+ * software is distributed, the source code must be made available.
+ *
+ * No warranty, expressed or implied, is given with this software.
+ * It is presented in the hope that it will prove useful.
+ *
+ * Hacked in ignorance and desperation by jonah@db.toronto.edu
+ */
+
+/*
+ * The code to handle the \specials generated by tpic was modified
+ * by Dirk Grunwald using the code Tim Morgan at Univ. of Calif, Irvine
+ * wrote for TeXsun.
+ */
+
+static char *
+endofcommand(char *cp)
+{
+ while (isspace((int)*cp))
+ ++cp;
+ if (*cp != '=')
+ return NULL;
+ do
+ ++cp;
+ while (isspace((int)*cp));
+ return cp;
+}
+
+#define CMD(x, y) ((x) << 8 | (y))
+
+void
+applicationDoSpecial(char *cp, size_t len)
+{
+ char *p;
+
+ if (globals.debug & DBG_DVI)
+ printf(" `%s'\n", cp);
+
+ while (isspace((int)*cp))
+ ++cp;
+
+ /* Ignore initial "xdvi:" */
+ if (memcmp(cp, "xdvi:", 5) == 0) {
+ cp += 5;
+ while (isspace((int)*cp))
+ ++cp;
+ }
+
+ /* PostScript specials */
+#ifdef MAGICK
+ if (resource.useMAGICK) {
+ if (Magick_parse_special(cp))
+ return;
+ }
+#endif
+
+ if (*cp == '"') {
+ quote_special(cp);
+ return;
+ }
+ if (memicmp(cp, "ps:", 3) == 0) {
+ cp += 3;
+ psfig_special(cp);
+ /* check for hdvips hyperlinks */
+ if (memicmp(cp, "sdict begin ", strlen("sdict begin ")) == 0) {
+ static Boolean warned_hypertex_too_old = False;
+ char *match = NULL;
+ if (warned_hypertex_too_old) /* don't continue evaluating links in this case */
+ return;
+ cp += strlen("sdict begin ");
+ if (memcmp(cp, "H.S", 3) == 0
+ || memcmp(cp, "H.R", 3) == 0
+ || memcmp(cp, "H.B", 3) == 0
+ /* following 2 conditions could be more restrictive: between `begin' and H.A/H.L,
+ there should be a single number (baselineskip in pt) */
+ || (match = strstr(cp, "H.A")) != NULL
+ || (match = strstr(cp, "H.L")) != NULL
+ || (match = strstr(cp, "/Action")) != NULL
+ || (match = strstr(cp, "/Link")) != NULL
+ || (match = strstr(cp, "/View")) != NULL) {
+ if (match != NULL)
+ htex_do_special(match, len - 3 - (match - cp) - strlen("sdict begin "));
+ else
+ htex_do_special(cp, len - strlen("sdict begin "));
+ }
+ else if (!warned_hypertex_too_old && strstr(cp, "HyperStart") != NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN, NULL,
+ "This DVI was created with a too old version of the `dvips' hyperref driver - "
+ "disabling hyperlinks.\n"
+ "To fix this, you should either upgrade to a current version of hyperref "
+ "(see http://www.tug.org/applications/hyperref/), "
+ "or use the `hypertex' package option, like this:\n\\usepackage[hypertex]{hyperref}\n"
+ "(Be aware though that this option won't work for PS->PDF conversion!)");
+ warned_hypertex_too_old = True;
+ }
+ }
+ else {
+ /* When not ignoring SDict entries, the distiller and pagecolor
+ code in lshort.dvi from CTAN:info/lshort/russian/lshrtdvi.zip
+ causes a failed assertion for 'color_bot_size > 0' in dvi-draw.c;
+ there's something wrong with the parsing order/event handling here
+ (see bug #856547).
+ But we also don't want those entries to trigger erasepage_gs(), so
+ it's correct to ignore them here.
+ */
+#if PS_GS && GS_PIXMAP_CLEARING_HACK
+ had_ps_specials = True;
+#endif
+ }
+ return;
+ }
+ if (memicmp(cp, "psfile", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) {
+ epsf_special(p);
+#if PS_GS && GS_PIXMAP_CLEARING_HACK
+ had_ps_specials = True;
+#endif
+ return;
+ }
+ if (memicmp(cp, "html:", 5) == 0) {
+ htex_do_special(cp + 5, len - 5);
+ return;
+ }
+
+#if COLOR
+ if (memicmp(cp, "color ", 6) == 0) {
+/* fprintf(stderr, "------------- color special\n"); */
+ if (resource.use_color)
+ color_special(cp + 6);
+ return;
+ }
+#endif
+
+ /* these should have been scanned */
+ if (*cp == '!'
+ || (memicmp(cp, "header", 6) == 0 && endofcommand(cp + 6) != NULL)) {
+#ifdef PS
+ if (resource.postscript != 0 && scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page = scanned_page_ps = scanned_page_reset = -1;
+# if COLOR
+ scanned_page_color = scanned_page;
+# endif
+ globals.ev.flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(globals.ev.canit, 1);
+ }
+#endif /* PS */
+ return;
+ }
+
+ if (memicmp(cp, "background ", 11) == 0) {
+#if COLOR
+ if (resource.use_color && scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page = scanned_page_color = scanned_page_reset = -1;
+# if PS
+ scanned_page_ps = scanned_page;
+# endif
+/* fprintf(stderr, "forcing redraw!\n"); */
+ globals.ev.flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(globals.ev.canit, 1);
+ }
+#endif /* COLOR */
+ return;
+ }
+
+ if (memcmp(cp, "papersize", 9) == 0 && endofcommand(cp + 9) != NULL) {
+ m_have_papersize_special = True;
+ if (scanned_page_reset >= 0) {
+ /* turn on scanning and redraw the page */
+ scanned_page = scanned_page_reset = -1;
+#if PS
+ scanned_page_ps = scanned_page;
+#endif
+#if COLOR
+ scanned_page_color = scanned_page;
+#endif
+ globals.ev.flags |= EV_NEWPAGE; /* force a redraw */
+ longjmp(globals.ev.canit, 1);
+ }
+ return;
+ }
+
+ /* tpic specials */
+
+ if (*cp >= 'a' && *cp <= 'z' && cp[1] >= 'a' && cp[1] <= 'z' &&
+ (isspace((int)cp[2]) || cp[2] == '\0')) {
+ switch (CMD(*cp, cp[1])) {
+ case CMD('p', 'n'):
+ set_pen_size(cp + 2);
+ return;
+ case CMD('f', 'p'):
+ flush_path();
+ return;
+ case CMD('d', 'a'):
+ flush_dashed(cp + 2, False);
+ return;
+ case CMD('d', 't'):
+ flush_dashed(cp + 2, True);
+ return;
+ case CMD('p', 'a'):
+ add_path(cp + 2);
+ return;
+ case CMD('a', 'r'):
+ arc(cp + 2, False);
+ return;
+ case CMD('i', 'a'):
+ arc(cp + 2, True);
+ return;
+ case CMD('s', 'p'):
+ flush_spline();
+ return;
+ case CMD('s', 'h'):
+ shade_last();
+ return;
+ case CMD('w', 'h'):
+ whiten_last();
+ return;
+ case CMD('b', 'k'):
+ blacken_last();
+ return;
+ case CMD('i', 'p'): /* throw away the path -- jansteen */
+ path_len = 0;
+ return;
+ }
+ }
+
+ if (memcmp(cp, "src:", 4) == 0) {
+ have_src_specials = True;
+ }
+ else if (globals.warn_spec_now)
+ XDVI_WARNING((stderr, "Special \"%s\" not implemented.", cp));
+}
+
+#undef CMD
+
+
+Boolean
+scan_special(char *cp, int cp_len, void *data)
+{
+ char *p;
+ Boolean dummy_ret = True; /* currently unused;
+ FIXME: use return value to avoid redundant calls (instead of longjmp()) */
+ UNUSED(cp_len); /* TODO: could probably utilize this in call to htex_prescan_special() */
+ ASSERT(data != NULL, "Must pass a data pointer when using HTEX");
+
+ if (globals.debug & DBG_PS)
+ printf("Scanning special `%s'.\n", cp);
+
+ while (isspace((int)*cp))
+ ++cp;
+
+ /* Ignore initial "xdvi:" */
+ if (memcmp(cp, "xdvi:", 5) == 0) {
+ cp += 5;
+ while (isspace((int)*cp))
+ ++cp;
+ }
+
+ if (memicmp(cp, "ps:", 3) == 0) {
+ Boolean found;
+ cp += 3;
+ /* check for hdvips hyperlinks */
+ if (memicmp(cp, "sdict begin ", strlen("sdict begin ")) == 0) {
+ static Boolean hypertex_too_old = False;
+ char *match = NULL;
+ cp += strlen("sdict begin ");
+
+ if (strstr(cp, "HyperStart") != NULL)
+ hypertex_too_old = True;
+ if (hypertex_too_old)
+ return False;
+
+ if (memcmp(cp, "H.S", 3) == 0
+ || memcmp(cp, "H.R", 3) == 0
+ || memcmp(cp, "H.B", 3) == 0
+ /* following 2 conditions could be more restrictive: between `begin' and H.A/H.L,
+ there should be a single number (baselineskip in pt) */
+ || (match = strstr(cp, "H.A")) != NULL
+ || (match = strstr(cp, "H.L")) != NULL
+ || (match = strstr(cp, "/Action")) != NULL
+ || (match = strstr(cp, "/Link")) != NULL
+ || (match = strstr(cp, "/View")) != NULL) {
+ if (match != NULL)
+ found = htex_prescan_special(match, cp_len, data);
+ else
+ found = htex_prescan_special(cp, cp_len, data);
+ }
+ }
+
+ }
+ else if (memicmp(cp, "html:", strlen("html:")) == 0) {
+ Boolean found;
+ size_t offset = strlen("html:");
+ found = htex_prescan_special(cp + offset, cp_len - offset, data);
+ /* if searching for a specific string, return as soon as it's found - not yet implemented */
+#if 0
+ if (my_data != NULL && my_data->scan_type == HTEX_ANCHOR_STRING && found) {
+ return True;
+ }
+#endif
+ }
+ /* do the following only if not searching for an anchor string */
+ if (((struct htex_prescan_data *)data)->scan_type != HTEX_ANCHOR_STRING) {
+#if PS
+# if COLOR
+ if (scanned_page_ps <= scanned_page)
+# endif
+ {
+ if (*cp == '!') {
+ scan_bang(cp);
+ return dummy_ret;
+ }
+ else if (memicmp(cp, "header", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) {
+ scan_header(p);
+ return dummy_ret;
+ }
+ }
+#endif /* PS */
+
+#if COLOR
+# if PS
+ if (scanned_page_color <= scanned_page)
+# endif
+ {
+ if (memicmp(cp, "background ", 11) == 0) {
+ scan_bg_color(cp);
+ return dummy_ret;
+ }
+ else if (memicmp(cp, "color ", 6) == 0) {
+ scan_color(cp);
+ return dummy_ret;
+ }
+ }
+#endif /* COLOR */
+ if (memcmp(cp, "papersize", 9) == 0 && (p = endofcommand(cp + 9)) != NULL) {
+ m_have_papersize_special = True;
+ scan_papersize(p);
+ return dummy_ret;
+ }
+ }
+ return dummy_ret;
+}
+
+
+/* #define xspell_conv(n) spell_conv0(n, current_dimconv) */
+#define xpixel_conv(x) ((int) ((x) >> 16))
+#define G_PXL_H xpixel_conv(currinf.data.dvi_h)
+
+/* cp is not const, because of endofcommand(). */
+void
+geom_do_special(struct scan_info *info, char *cp, double current_dimconv)
+{
+ const char *p;
+ struct geom_info *g_info = (struct geom_info *)info->data;
+
+ UNUSED(current_dimconv);
+
+ while (isspace((int)*cp))
+ ++cp;
+
+ /* Ignore initial "xdvi:" */
+ if (memcmp(cp, "xdvi:", 5) == 0) {
+ cp += 5;
+ while (isspace((int)*cp))
+ ++cp;
+ }
+
+ if (memicmp(cp, "psfile", 6) == 0 && (p = endofcommand(cp + 6)) != NULL) {
+ /* compute epsf bounding box */
+ char c;
+ int flags = 0;
+ double keyval[6];
+
+ c = *p;
+ if (c == '\'' || c == '"') {
+ do
+ ++p;
+ while (*p != '\0' && *p != c);
+ }
+ else
+ while (*p != '\0' && !isspace((int)*p))
+ ++p;
+ while (isspace((int)*p))
+ ++p;
+ while (*p != '\0') {
+ const char *p1 = p;
+ size_t keyno;
+
+ while (*p1 != '=' && !isspace((int)*p1) && *p1 != '\0')
+ ++p1;
+ for (keyno = 0; keyno < NKEYS; ++keyno) {
+ if (memcmp(p, keytab[keyno], p1 - p) == 0) {
+ if (keyno >= N_ARGLESS_KEYS) {
+ while (isspace((int)*p1))
+ ++p1;
+ if (*p1 == '=') {
+ ++p1;
+ while (isspace((int)*p1))
+ ++p1;
+ }
+ if (keyno < N_ARGLESS_KEYS + 6) {
+ keyval[keyno - N_ARGLESS_KEYS] = atof(p1);
+ flags |= (1 << (keyno - N_ARGLESS_KEYS));
+ }
+ while (!isspace((int)*p1) && *p1 != '\0')
+ ++p1;
+ }
+ break;
+ }
+ }
+ p = p1;
+ while (!isspace((int)*p) && *p != '\0')
+ ++p;
+ while (isspace((int)*p))
+ ++p;
+ }
+
+ if ((flags & 0x30) == 0x30 || ((flags & 0x30) && (flags & 0xf) == 0xf)) {
+ long x = G_PXL_H;
+ long y = PXL_V;
+ long bbox_w;
+ long bbox_h;
+
+ bbox_w = 0.1 * ((flags & 0x10) ? KEY_RWI
+ : KEY_RHI * (KEY_URX - KEY_LLX) / (KEY_URY -
+ KEY_LLY)) *
+ dimconv + 0.5;
+ bbox_h =
+ 0.1 * ((flags & 0x20) ? KEY_RHI : KEY_RWI *
+ (KEY_URY - KEY_LLY) / (KEY_URX - KEY_LLX))
+ * dimconv + 0.5;
+
+ g_info->geom_box(info, x, y - bbox_h, x + bbox_w, y);
+ }
+ }
+ else if (memicmp(cp, "ps::[begin]", 11) == 0) {
+ /* compute psfig bounding box */
+ long bbox_w, bbox_h;
+
+ if (sscanf(cp + 11, "%ld %ld\n", &bbox_w, &bbox_h) >= 2) {
+ long x = G_PXL_H;
+ long y = PXL_V;
+
+ bbox_w = xpixel_conv(spell_conv(bbox_w));
+ bbox_h = xpixel_conv(spell_conv(bbox_h));
+
+ g_info->geom_box(info, x, y, x + bbox_w, y + bbox_h);
+ }
+ }
+}
diff --git a/Build/source/texk/xdvik/special.h b/Build/source/texk/xdvik/special.h
new file mode 100644
index 00000000000..8b41d313c04
--- /dev/null
+++ b/Build/source/texk/xdvik/special.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef SPECIAL_H_
+#define SPECIAL_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "events.h"
+
+extern Boolean scan_special(char *str, int str_len, void *data);
+
+#if PS
+
+struct psprocs {
+ void (*toggle) (int flag);
+ void (*destroy) (void);
+ void (*interrupt) (void);
+ void (*endpage) (void);
+ void (*drawbegin) (int, int, const char *);
+ void (*drawraw) (const char *);
+ void (*drawfile) (const char *, FILE *);
+ void (*drawend) (const char *);
+ void (*beginheader) (void);
+ void (*endheader) (void);
+ void (*newdoc) (void);
+};
+
+extern void ps_clear_cache(void);
+extern void ps_destroy(void);
+extern void drawbegin_none(int, int, const char *);
+extern void draw_bbox(void);
+extern void display_bboxes(void);
+extern void clear_bboxes(void);
+extern void save_bbox(void);
+
+#endif
+
+extern void applicationDoSpecial(char *str, size_t len);
+extern void geom_do_special(struct scan_info *, char *, double);
+extern void color_special(const char *colorspec);
+
+extern void init_prescan(void);
+
+/*
+ info on whether this DVI file contains papersize specials,
+ and a resetting method.
+*/
+extern void reset_papersize_special(void);
+extern Boolean have_papersize_special(void);
+
+#if COLOR
+extern void init_page_colors(struct rgb *foreground, struct rgb *background);
+extern void scan_color_eop(void);
+extern void scan_color(const char *color);
+struct rgb; /* forward declaration */
+extern void set_fg_color(const struct rgb *);
+#endif
+
+#endif /* SPECIAL_H_ */
diff --git a/Build/source/texk/xdvik/squeeze.c b/Build/source/texk/xdvik/squeeze.c
new file mode 100644
index 00000000000..0f57e1d8615
--- /dev/null
+++ b/Build/source/texk/xdvik/squeeze.c
@@ -0,0 +1,196 @@
+/*========================================================================*\
+
+Copyright (c) 1994-2004 Paul Vojta
+
+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:
+ This routine is adapted from the squeeze.c that comes with dvips;
+ it bears the message:
+ This software is Copyright 1988 by Radical Eye Software.
+ Used with permission.
+
+\*========================================================================*/
+
+/*
+ * This routine squeezes a PostScript file down to its
+ * minimum. We parse and then output it.
+ * Adapted for xdvi 1/94. Writes a C program that contains the PS file
+ * as a constant string.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "kpathsea/c-auto.h"
+#include "kpathsea/c-memstr.h"
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+
+#define LINELENGTH (72)
+#define BUFLENGTH (1000)
+#undef putchar
+#define putchar(a) (void)putc(a, out) ;
+FILE *in, *out;
+static int linepos = 0;
+static int lastspecial = 1;
+static int stringlen = 0;
+/*
+ * This next routine writes out a `special' character. In this case,
+ * we simply put it out, since any special character terminates the
+ * preceding token.
+ */
+static void
+specialout(char c)
+{
+ if (linepos + 1 > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0;
+ }
+ putchar(c);
+ linepos++;
+ lastspecial = 1;
+}
+
+static void
+strout(char *s)
+{
+ if (linepos + strlen(s) > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0;
+ }
+ linepos += strlen(s);
+ while (*s != 0)
+ putchar(*s++);
+ lastspecial = 1;
+}
+
+static void
+cmdout(char *s)
+{
+ int l;
+
+ l = strlen(s);
+ if (linepos + l + 1 > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0;
+ lastspecial = 1;
+ }
+ if (!lastspecial) {
+ putchar(' ');
+ linepos++;
+ }
+ while (*s != 0) {
+ putchar(*s++);
+ }
+ linepos += l;
+ lastspecial = 0;
+}
+
+char buf[BUFLENGTH];
+#ifndef VMS
+int
+#endif
+main(int argc, char *argv[])
+{
+ int c;
+ char *b;
+ char seeking;
+ extern void exit();
+
+ if (argc > 3 || (in = (argc < 2 ? stdin : fopen(argv[1], "r"))) == NULL ||
+ (out = (argc < 3 ? stdout : fopen(argv[2], "w"))) == NULL) {
+ (void)fprintf(stderr, "Usage: squeeze [infile [outfile]]\n");
+ exit(EXIT_FAILURE);
+ }
+ (void)fputs("/*\n"
+ " * DO NOT EDIT THIS FILE!\n"
+ " * It was created by squeeze.c from another file (see the Makefile).\n"
+ " */\n\n"
+ "const char psheader[] = \"\\\n", out);
+ while (1) {
+ c = getc(in);
+ if (c == EOF)
+ break;
+ if (c == '%') {
+ while ((c = getc(in)) != '\n');
+ }
+ if (c <= ' ')
+ continue;
+ switch (c) {
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ specialout(c);
+ break;
+ case '<':
+ case '(':
+ if (c == '(')
+ seeking = ')';
+ else
+ seeking = '>';
+ b = buf;
+ *b++ = c;
+ do {
+ c = getc(in);
+ if (b > buf + BUFLENGTH - 2) {
+ (void)fprintf(stderr, "Overran buffer seeking %c", seeking);
+ exit(EXIT_FAILURE);
+ }
+ *b++ = c;
+ if (c == '\\')
+ *b++ = getc(in);
+ } while (c != seeking);
+ *b++ = 0;
+ strout(buf);
+ break;
+ default:
+ b = buf;
+ while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') || (c == '/') || (c == '@') ||
+ (c == '!') || (c == '"') || (c == '&') || (c == '*')
+ || (c == ':') || (c == ',') || (c == ';') || (c == '?')
+ || (c == '^') || (c == '~') || (c == '-') || (c == '.')
+ || (c == '#') || (c == '|') || (c == '_') || (c == '=')
+ || (c == '$') || (c == '+')) {
+ *b++ = c;
+ c = getc(in);
+ }
+ if (b == buf) {
+ (void)fprintf(stderr, "Oops! Missed a case: %c.\n", c);
+ exit(EXIT_FAILURE);
+ }
+ *b++ = 0;
+ (void)ungetc(c, in);
+ cmdout(buf);
+ }
+ }
+ (void)fprintf(out,
+ "\\n\";\n\n int\tpsheaderlen\t= %d;\n",
+ stringlen + linepos + 1);
+ return 0;
+}
diff --git a/Build/source/texk/xdvik/stamp-auto.in b/Build/source/texk/xdvik/stamp-auto.in
new file mode 100644
index 00000000000..684d91df8ae
--- /dev/null
+++ b/Build/source/texk/xdvik/stamp-auto.in
@@ -0,0 +1 @@
+Mo Aug 22 08:29:17 CEST 2005
diff --git a/Build/source/texk/xdvik/string-utils.c b/Build/source/texk/xdvik/string-utils.c
new file mode 100644
index 00000000000..8ade715ed5d
--- /dev/null
+++ b/Build/source/texk/xdvik/string-utils.c
@@ -0,0 +1,743 @@
+/*
+ * miscellaneous string utility functions
+ *
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * 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.
+*/
+
+/* #define MYDEBUG 1 */
+
+#include <string.h>
+#include <stdio.h>
+#include <locale.h>
+#include <ctype.h>
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "string-utils.h"
+#include "util.h"
+
+/*------------------------------------------------------------
+ * str_is_prefix
+ *
+ * Purpose:
+ * Return True if <str1> is a prefix of <str2>, else False.
+ *
+ * If `case_sensitive' is set to False, it performs matching
+ * in a case-insensitive manner; in that case, str1 should
+ * be lowercase.
+ *------------------------------------------------------------*/
+
+Boolean
+str_is_prefix(const char *str1, const char *str2, Boolean case_sensitive)
+{
+ int i;
+
+ for (i = 0; *str1 != '\0' && *str2 != '\0'; i++) {
+ if ((case_sensitive && *str1 != *str2) ||
+ (!case_sensitive && *str1 != tolower((int)*str2)))
+ return False;
+ str1++;
+ str2++;
+ }
+ return *str1 == '\0';
+}
+
+
+
+/*------------------------------------------------------------
+ * str_is_suffix
+ *
+ * Purpose:
+ * Return True if str1 is a suffix of str2, else False.
+ * E.g. returns true if str1 = ".tex", str2 = "test.tex".
+ *
+ * If `case_sensitive' is set to False, it performs matching
+ * in a case-insensitive manner; in that case, str1 should
+ * be lowercase.
+ *------------------------------------------------------------*/
+
+Boolean
+str_is_suffix(const char *str1, const char *str2, Boolean case_sensitive)
+{
+ int len1 = strlen(str1);
+ int len2 = strlen(str2);
+
+ while (len2 > len1) {
+ str2++;
+ len2--;
+ }
+ if (case_sensitive)
+ return strcmp(str1, str2) == 0;
+ else
+ /* also compare terminating 0; second string
+ is assumed to be all-lowercase! */
+ return memicmp(str2, str1, len1 + 1) == 0;
+}
+
+/*
+ * Like strstr(), but does case-insensitive matching: Brute-force algorithm
+ * to find the first occurrence of subsrtring `needle' (which should be all-lowercase)
+ * in string `haystack', ignoring case in (i.e. lowercasing) haystack. The terminating
+ * '\0' characters are not compared.
+ * Returns a pointer to the beginning of the substring if found, NULL else.
+ *
+ * This code was derived from public domain code (Stristr.c on www.snippets.org).
+ * Currently unused.
+ */
+char *
+my_stristr(const char *haystack, const char *needle)
+{
+ const char *curr;
+
+ for (curr = haystack; *curr != '\0'; curr++) {
+ const char *ptr1, *ptr2;
+ /* search for first character */
+ for (; ((*curr != '\0') && (tolower((int)*curr) != *needle)); curr++) { ; }
+
+ if (*curr == '\0') /* not found */
+ return NULL;
+
+ /* now compare other characters */
+ ptr1 = needle;
+ ptr2 = curr;
+ while (tolower((int)*ptr2) == *ptr1) {
+ ptr2++;
+ ptr1++;
+ /* success if at end of needle */
+ if (*ptr1 == '\0')
+ return (char *)curr;
+ }
+ }
+ return NULL;
+}
+
+/*
+ expand filename to include full path name;
+ returns result in a freshly allocated string.
+*/
+char *
+expand_filename(const char *filename, expandPathTypeT type)
+{
+ char *path_name = NULL;
+
+ if (*filename == '/') /* already an absolute path */
+ return xstrdup(filename);
+
+ if (type == USE_CWD_PATH) {
+ size_t path_name_len = 512;
+ size_t len = strlen(filename) + 1;
+
+ /* append to cwd if it's not already a full path */
+ if (filename[0] != '/') {
+ for (;;) {
+ char *tmp;
+ path_name = xrealloc(path_name, path_name_len);
+ if ((tmp = getcwd(path_name, path_name_len)) == NULL && errno == ERANGE) {
+ path_name_len *= 2;
+ }
+ else {
+ path_name = tmp;
+ break;
+ }
+ }
+ len += strlen(path_name) + 1; /* 1 for '/' */
+ path_name = xrealloc(path_name, len);
+ strcat(path_name, "/");
+ strcat(path_name, filename);
+ }
+
+ TRACE_HTEX((stderr,
+ "Expanding filename |%s| with CWD gives |%s|",
+ filename, path_name == NULL ? "<NULL>" : path_name));
+ return path_name ? path_name : xstrdup(filename);
+ }
+ else {
+ ASSERT(globals.dvi_file.dirname != NULL, "globals.dvi_file.dirname should have been initialized before");
+ path_name = xstrdup(globals.dvi_file.dirname);
+ path_name = xstrcat(path_name, filename);
+ TRACE_HTEX((stderr,
+ "Expanding filename |%s| with globals.dvi_file.dirname |%s| gives |%s|",
+ filename, globals.dvi_file.dirname, path_name));
+ return path_name;
+ }
+}
+
+/* expand filename to include `.dvi' extension and full path name;
+ returns malloc()ed string (caller is responsible for free()ing).
+*/
+char *
+filename_append_dvi(const char *filename)
+{
+ char *expanded_filename = NULL;
+ const char *orig_filename = filename;
+ size_t len;
+ char *p;
+
+ /* skip over `file:' prefix if present */
+ if (str_is_prefix("file:", filename, True)) {
+ filename += strlen("file:");
+ if (str_is_prefix("//", filename + strlen("file:"), True)) { /* is there a hostname following? */
+ char *tmp = strchr(filename+2, '/'); /* skip over host name */
+ if (tmp == NULL) {
+ XDVI_WARNING((stderr, "Malformed hostname part in filename `%s'; not expanding file name",
+ orig_filename));
+ }
+ else {
+ /* deal with multiple `//' after "file://localhost";
+ while the RFC seems to suggest that file://localhost/foo/bar defines a path
+ `foo/bar', most browsers (and actually, also libwww) will treat this path as absolute:
+ `/foo/bar'. So we treat
+ file://localhost//foo/bar
+ and
+ file://localhost/foo/bar
+ as equivalent.
+ */
+ while (*(tmp+1) == '/')
+ tmp++;
+ filename = tmp;
+ }
+ }
+ }
+
+ len = strlen(filename) + 5; /* 5 in case we need to add `.dvi\0' */
+
+ expanded_filename = xmalloc(len);
+
+ strcpy(expanded_filename, filename);
+
+ /* Append ".dvi" extension if no extension is present.
+ Only look at the filename part when trying to find a `.'.
+ */
+ if ((p = strrchr(expanded_filename, '/')) == NULL) {
+ p = expanded_filename;
+ }
+ if ((p = strrchr(p, '.')) == NULL) {
+ TRACE_HTEX((stderr, "appending .dvi extension to filename |%s|", expanded_filename));
+ strcat(expanded_filename, ".dvi");
+ }
+ return expanded_filename;
+}
+
+char *
+expand_filename_append_dvi(const char *filename, expandPathTypeT type, Boolean must_exist)
+{
+ char canonical_path[MAXPATHLEN + 1];
+ char *normalized_fname = filename_append_dvi(filename);
+ char *expanded_fname = expand_filename(normalized_fname, type);
+ if (must_exist) {
+ char *canonical_name = REALPATH(expanded_fname, canonical_path);
+ free(normalized_fname);
+ free(expanded_fname);
+ return xstrdup(canonical_name);
+ }
+ else {
+ free(normalized_fname);
+ return expanded_fname;
+ }
+}
+
+char *
+format_arg(const char *fmt, const char *arg, int *match)
+{
+ char *tmp = xmalloc(strlen(fmt) + strlen(arg) + 1);
+ if (strchr(fmt, '%') != NULL) {
+ sprintf(tmp, fmt, arg);
+ *match = 1;
+ }
+ else {
+ strcpy(tmp, fmt);
+ }
+ return tmp;
+}
+
+/* escape single `%' characters in arg and return newly allocated string */
+char *
+escape_format_arg(const char *arg)
+{
+ char *ret, *ptr;
+ ASSERT(arg != NULL, "");
+ ret = xmalloc(strlen(arg) * 2 + 1); /* more than enuff */
+
+ ptr = ret;
+ while (*arg != '\0') {
+ /* need to escape? */
+ if (*arg == '%' && (ptr == ret
+ || (ptr > ret && *(arg - 1) != '%'))) {
+ *ptr++ = '%';
+ }
+ *ptr++ = *arg++;
+ }
+ *ptr = '\0';
+
+ /* trim return buffer */
+ return xrealloc(ret, strlen(ret) + 1);
+}
+
+char *
+unquote_arg(const char *fmt, const char *arg, int *match, int *len)
+{
+ char *ptr;
+ char c;
+
+ c = fmt[0];
+ fmt++;
+ if ((ptr = strchr(fmt, c)) != NULL) {
+ *ptr++ = '\0';
+ while (*ptr == ' ' || *ptr == '\t') {
+ ptr++;
+ }
+ *len = ptr - fmt;
+ return format_arg(fmt, arg, match);
+ }
+ else {
+ *len = strlen(fmt);
+ XDVI_WARNING((stderr, "Ignoring lonesome quote in string %s", fmt - 1));
+ return format_arg(fmt, arg, match);
+ }
+}
+
+/* Chop `source' into chunks separated by `sep', and save these
+ * to newly allocated return list. The end of the list is indicated
+ * by a NULL element (i.e. the returned list will always contain at
+ * least 1 element). The caller is responsible for free()ing the returned
+ * list.
+ *
+ * If `do_unquote' is True, separators inside the quotes will not be
+ * treated as boundaries; instead, the quotes surrounding the chunk are removed.
+ */
+char **
+get_separated_list(const char *source, const char *sep, Boolean do_unquote)
+{
+ /* allocate at least list of size 1, for NULL termination below */
+ char **chunks = xmalloc(sizeof *chunks);
+ const char *b_ptr, *e_ptr;
+ size_t i = 0;
+
+ b_ptr = source;
+
+ while (*b_ptr != '\0' && strchr(sep, *b_ptr) != NULL)
+ b_ptr++;
+
+ for (i = 0; *b_ptr != '\0'; i++) {
+ char *quote;
+ char quotechar = 0;
+ size_t len, chunk_len, alloc_len = 0;
+
+ if ((len = strcspn(b_ptr, sep)) == 0) /* at end */
+ break;
+
+ /* check for quoted chunk, in which case we don't want to treat
+ spaces as chunk separators */
+ if (do_unquote && (quote = strchr("'\"", *b_ptr)) != NULL) {
+ const char *curr = b_ptr + 1;
+ quotechar = *quote;
+
+ for (;;) { /* find end of quote */
+ char *maybe_end = strchr(curr, quotechar);
+ if (maybe_end != NULL) {
+ if (maybe_end - curr > 0 &&
+ *(maybe_end - 1) == '\\') { /* escaped quote */
+ curr = ++maybe_end;
+ }
+ else { /* found */
+ b_ptr++;
+ len = maybe_end - b_ptr;
+ break;
+ }
+ }
+ else { /* not found end - warn, and forget about this quote */
+ XDVI_WARNING((stderr, "Unmatched quote character in string `%s'", b_ptr));
+ break;
+ }
+ }
+ }
+
+ e_ptr = b_ptr + len;
+ chunk_len = e_ptr - b_ptr;
+ while (i + 1 >= alloc_len) {
+ alloc_len++;
+ }
+ chunks = xrealloc(chunks, alloc_len * sizeof *chunks);
+ chunks[i] = xmalloc(chunk_len + 1);
+ memcpy(chunks[i], b_ptr, chunk_len);
+ chunks[i][chunk_len] = '\0';
+
+ /* skip trailing quotechar and spaces */
+ b_ptr = e_ptr;
+ if (do_unquote && quotechar != 0 && *b_ptr == quotechar)
+ b_ptr++;
+ while (*b_ptr != '\0' && strchr(sep, *b_ptr) != NULL)
+ b_ptr++;
+ }
+ /* terminate list with NULL element */
+ chunks[i] = NULL;
+ return chunks;
+}
+
+const char *
+find_format_str(const char *input, const char *fmt)
+{
+ const char *ptr = input;
+ while ((ptr = strstr(ptr, fmt)) != NULL) {
+ if (ptr > input && *(ptr - 1) == '\\') {
+ ptr++;
+ continue;
+ }
+ else
+ return ptr;
+ }
+ return NULL;
+}
+
+/* return directory component of `path', or NULL if path is a filename only */
+char *
+get_dir_component(const char *path)
+{
+ char *ret = NULL;
+ char *p;
+
+ if ((p = strrchr(path, '/')) != NULL) {
+ /* copy, chop off filename (but not the '/') */
+ ret = xstrdup(path);
+ *(ret + (p - path) + 1) = '\0';
+ TRACE_CLIENT((stderr, "get_dir_component of |%s| is |%s|\n", path, ret));
+ }
+ return ret;
+}
+
+/*
+ If `src' is an absolute path, compare it with `target', ignoring `.tex' extension in
+ both strings. Else, compare the concatenation of `src' with `dvi_path' and `target',
+ in the same way.
+ Since efficiency is a concern here, we don't copy any strings; instead, we loop through
+ `src' and `target' from the end of both strings (which makes expanding `../' easier, and
+ will terminate earlier for non-equal files), replacing `src' with `dvi_path' when
+ dropping off the beginning of `src'.
+*/
+Boolean
+src_compare(const char *src, int src_len, const char *target, const char *dvi_path, size_t dvi_path_len)
+{
+ int i, j;
+ Boolean matched = True;
+
+ /* This macro sets the `src' pointer to `dvi_path' after having
+ dropped off the beginning of src, or returns False if dvi_path
+ is NULL (which either means that `src' was an absolute path, or
+ that the dvi_path has been used up already).
+ */
+#define CHK_USE_DIR(i) \
+ if (i == -1) { \
+ if (dvi_path == NULL) /* already done */ \
+ return False; \
+ src = dvi_path; \
+ dvi_path = NULL; \
+ i = dvi_path_len - 1; \
+ MYTRACE((stderr, "swapped, now using: |%s| of len %d", src, i)); \
+ }
+
+ /* ignore path in both filenames if one of them does not contain a path */
+ {
+ char *src_p = strrchr(src, '/');
+ char *target_p = strrchr(target, '/');
+
+ if (src_p == NULL) {
+ dvi_path = NULL;
+ if (target_p != NULL)
+ target = target_p + 1;
+ }
+
+ if (target_p == NULL) {
+ dvi_path = NULL;
+ if (src_p != NULL)
+ src = src_p + 1;
+ }
+ }
+
+ /* don't prepend dvi_path if src is absolute */
+ if (*src == '/') {
+ dvi_path = NULL;
+ }
+
+ /* skip `.tex' suffix in strings if present */
+ i = src_len;
+ MYTRACE((stderr, "len of |%s| %d", src, i));
+ if (i >= 4 && strcmp(src + (i - 4), ".tex") == 0) {
+ MYTRACE((stderr, "src |%s| has .tex suffix!", src));
+ i -= 4;
+ }
+
+ j = strlen(target);
+ MYTRACE((stderr, "len of |%s| %d", target, j));
+ if (j >= 4 && strcmp(target + (j - 4), ".tex") == 0) {
+ MYTRACE((stderr, "target |%s| has .tex suffix!", target));
+ j -= 4;
+ }
+
+ /* start with index of last char */
+ i--;
+ j--;
+
+ while (i >= 0 && j >= 0) {
+ int skip_dirs = 0;
+/* fprintf(stderr, "check: %d[%c]\n", i, src[i]); */
+ while (src[i] == '.' && src[i + 1] == '/') { /* normalize `../' and `./' */
+ MYTRACE((stderr, "check2: %d[%c]", i, src[i]));
+
+ if (i >= 2 && src[i - 1] == '.' && src[i - 2] == '/') {
+ MYTRACE((stderr, "case /.."));
+ i -= 3;
+ skip_dirs++;
+ }
+ else if (i == 1) { /* `../' or `/./' at start of src */
+ if (src[0] == '.') { /* `../' */
+ MYTRACE((stderr, "../ at start"));
+ i -= 2;
+ skip_dirs++;
+ }
+ else if (src[0] == '/') { /* `/./' */
+ MYTRACE((stderr, "/./ at start"));
+ i -= 1;
+ }
+ else /* something else */
+ break;
+ }
+ else if (i == 0 || (i > 1 && src[i - 1] == '/')) { /* ./ at start, or /./ somewhere */
+ i -= 1;
+ }
+ else /* might be `abc./' or `abc../' (strange but legal) */
+ break;
+
+ CHK_USE_DIR(i);
+ while (i >= 0 && src[i] == '/') i--;
+ CHK_USE_DIR(i);
+
+ while (src[i] != '.' && skip_dirs-- > 0) { /* unless there are subsequent `../' */
+ /* skip directories backwards */
+ while (i >= 0 && src[i] != '/') {
+ MYTRACE((stderr, "non-slash: %d,%c", i, src[i]));
+ i--;
+ }
+ CHK_USE_DIR(i);
+ while (i >= 0 && src[i] == '/') {
+ MYTRACE((stderr, "slash: %d,%c", i, src[i]));
+ i--;
+ }
+ CHK_USE_DIR(i);
+ MYTRACE((stderr, "skipped backwards: %d,%c", i, src[i]));
+ }
+ }
+
+ /* skip multiple '/'. No need to fall off the beginning of src and use
+ CHK_USE_DIR() here, since with (multiple) '/' at the beginning, src
+ must be an absolute path. */
+ while (i > 0 && src[i] == '/' && src[i - 1] == '/') {
+ i--;
+ }
+
+ MYTRACE((stderr, "comparing: %d[%c] - %d[%c]", i, src[i], j, target[j]));
+ if (src[i] != target[j]) {
+ matched = False;
+ break;
+ }
+ if (i == 0 && j == 0) /* at start of both strings */
+ break;
+ i--;
+ j--;
+ CHK_USE_DIR(i);
+ }
+
+ if (i != 0 || j != 0) /* not at start of both strings, no match */
+ return False;
+ else
+ return matched;
+#undef CHK_USE_DIR
+}
+
+
+/*
+ Contributed by ZLB: Return a canonicalized version of path (with `../'
+ and `./' resolved and `//' reduced to '/') in a freshly malloc()ed
+ buffer, which the caller is responsible for free()ing. Cannot fail.
+*/
+char *
+canonicalize_path(const char *path)
+{
+ char *p, *q, *start;
+ char c;
+ size_t len = strlen(path);
+
+ assert(path != NULL);
+ assert(*path == '/');
+
+ start = q = p = xstrdup(path);
+
+ /* len is the length of string */
+ while (p < start + len) {
+ if ((c = p[1]) == '/') {
+ /* remove multiple '/' in pathname */
+ memmove(p + 1, p + 2, len - (p + 2 - start) + 1);
+ len--;
+ continue;
+ }
+ else if (c == '.') {
+ if ((c = p[2]) == '/') {
+ /* p = '/.' in pathname */
+ memmove(p + 1, p + 3, len - (p + 3 - start) + 1);
+ len -= 2;
+ continue;
+ }
+ else if (c == '.' && ((c = p[3]) == '/' || c == '\0')) {
+ /* p == "/.." */
+ memmove(q, p + 3, len - (p + 3 - start) + 1);
+ len -= (p - q) + 3;
+ p = q;
+ /* check if the new dirname at p is "//" or './' or '../' */
+ if ((c = p[1]) == '/')
+ continue;
+ else if (c == '.') {
+ if ((c = p[2]) == '/')
+ continue;
+ else if (c == '.' && ((c = p[3]) == '/' || c == '\0')) {
+ while (--q >= start && *q != '/');
+ if (q < start)
+ q = start;
+ continue;
+ }
+ }
+ }
+ }
+
+ /* search next '/' */
+ q = p;
+ while (++p <= start + len && *p != '/');
+ }
+
+ return start;
+}
+
+/* Escape all of the following characters in str:
+ ` \ ; ( )
+ making it safe to pass str to a shell. Return result in a newly
+ allocated string, which the caller is responsible to free() after use.
+*/
+char *
+shell_escape_string(const char *str)
+{
+ size_t len = strlen(str);
+ char *new_str = xmalloc(len * 2 + 1); /* safe amount, since each char will be doubled at most */
+
+ const char *src_ptr = str;
+ char *target_ptr = new_str;
+ while (*src_ptr != '\0') {
+ if (*src_ptr == '\\'
+ || *src_ptr == '`'
+ || *src_ptr == '('
+ || *src_ptr == ')'
+ || *src_ptr == ';') {
+#if 0
+ /* only if not yet escaped? */
+ && (src_ptr == str || (src_ptr > str && *(src_ptr - 1) != '\\'))) {
+#endif
+ *target_ptr++ = '\\';
+ }
+ *target_ptr++ = *src_ptr++;
+ }
+ *target_ptr = '\0'; /* terminate */
+ return new_str;
+}
+
+void
+replace_extension(const char *fname, const char *extension,
+ char *buf, size_t buf_len)
+{
+ char *sep;
+ if ((sep = strrchr(fname, '.')) != NULL) {
+ size_t len = strlen(extension);
+ if (len + (sep - fname) > buf_len)
+ return;
+ strncpy(buf, fname, sep - fname);
+ strcpy(buf + (sep - fname), extension);
+ }
+ return;
+}
+
+#if 0
+/*
+ * Estimate the string length needed for %p conversion. Currently unused,
+ * since we use the more general VSNPRINTF() approach.
+ */
+#define PTR_CONVERSION_LEN_GUESS sizeof(void *) * CHAR_BIT
+#endif
+
+
+/*
+ * Return a formatted string in newly allocated memory.
+ */
+char *
+get_string_va(const char *fmt, ...)
+{
+ char *buf = NULL;
+ XDVI_GET_STRING_ARGP(buf, fmt);
+ return buf;
+}
+
+/* Wrapper for atof() for strtod()-like error checking,
+ * with an XDVI_WARNING if the conversion of <str> wasn't complete.
+ */
+double
+my_atof(const char *str)
+{
+ char *ptr;
+ double f;
+
+ f = strtod(str, (char **)&ptr);
+ if (*ptr != '\0') {
+ XDVI_WARNING((stderr, "strtod: incomplete conversion of %s to %f", str, f));
+ }
+ return f;
+}
+
+/* return length of a string representation of the integer n */
+int
+length_of_int(int n)
+{
+ int ret = 1;
+
+ if (n < 0) {
+ ret++;
+ n *= -1;
+ }
+ while (n >= 10) {
+ n /= 10;
+ ret++;
+ }
+
+ return ret;
+}
+
+Boolean
+is_spaces_only(const char *ptr)
+{
+ for (; *ptr; ptr++) {
+ if (!isspace((int)*ptr))
+ return False;
+ }
+ return True;
+}
diff --git a/Build/source/texk/xdvik/string-utils.h b/Build/source/texk/xdvik/string-utils.h
new file mode 100644
index 00000000000..91909bcf42d
--- /dev/null
+++ b/Build/source/texk/xdvik/string-utils.h
@@ -0,0 +1,81 @@
+#ifndef STRING_UTILS_H_
+#define STRING_UTILS_H_
+
+#include "xdvi-config.h"
+#include "kpathsea/c-vararg.h"
+#include "my-vsnprintf.h"
+
+extern Boolean str_is_prefix(const char *, const char *, Boolean case_sensitive);
+extern Boolean str_is_suffix(const char *, const char *, Boolean case_sensitive);
+extern Boolean is_spaces_only(const char *);
+
+extern char *my_stristr(const char *haystack, const char *needle);
+
+typedef enum { USE_DVI_PATH, USE_CWD_PATH } expandPathTypeT;
+
+/* remove `file:[//localhost/]' prefix from filename, and append `.dvi'
+ extension if no extension is present */
+extern char *filename_append_dvi(const char *fname);
+/* prepend a path of type `type' (either CVW, or directory of dvi file)
+ to `fname' */
+extern char *expand_filename(const char *fname, expandPathTypeT type);
+
+/* do both of the above */
+extern char *expand_filename_append_dvi(const char *fname, expandPathTypeT type, Boolean must_exist);
+
+/* normalize `../' `./' `//' from path */
+extern char *canonicalize_path(const char *path);
+
+extern char *format_arg(const char *fmt, const char *arg, int *match);
+extern char *escape_format_arg(const char *arg);
+extern char *unquote_arg(const char *fmt, const char *arg, int *match, int *len);
+extern char *get_dir_component(const char *path);
+extern char **get_separated_list(const char *source, const char *sep, Boolean do_unquote);
+extern const char *find_format_str(const char *input, const char *fmt);
+extern Boolean src_compare(const char *src, int src_len, const char *target, const char *path, size_t path_len);
+extern char *shell_escape_string(const char *str);
+extern void replace_extension(const char *fname, const char *extension, char *buf, size_t name_len);
+extern int length_of_int(int n);
+
+extern char *get_string_va(const char *fmt, ...);
+extern double my_atof(const char *str);
+
+/*
+ * Print `fmt' to a dynamically allocated string `buf'. Uses VSNPRINTF
+ * in a way that should work with all of glibc <= 2.0.6, >= 2.1, and
+ * the implementation in my-vsnprintf.c. We cannot invoke va_start()/va_end()
+ * in a wrapper function since we may need to invoke vsnprintf() several
+ * times, and each call invalidates argp; that's why this is a macro ...
+ */
+#define XDVI_GET_STRING_ARGP(buf, fmt) \
+ do { \
+ va_list argp; \
+ int CHUNK_LEN = 128; \
+ int curr_len = CHUNK_LEN, need_len; \
+ \
+ buf = NULL; \
+ \
+ for (;;) { \
+ /* see man page for vsnprintf: for glibc 2.0, <need_len> is */ \
+ /* -1 if <buf> had been trucated to <curr_len>; for glibc 2.1, */ \
+ /* it's the total length of <fmt>; so the following works */ \
+ /* with both versions: */ \
+ buf = xrealloc(buf, curr_len); \
+ \
+ va_start(argp, fmt); \
+ need_len = VSNPRINTF(buf, curr_len, fmt, argp); \
+ va_end(argp); \
+ \
+ if (need_len > -1 && need_len < curr_len) { /* <curr_len> was large enough */ \
+ break; \
+ } \
+ if (need_len > -1) { /* now need_len + 1 is the exact space needed */ \
+ curr_len = need_len + 1; \
+ } \
+ else { /* try again with larger <len> */ \
+ curr_len += CHUNK_LEN; \
+ } \
+ } \
+ } while (0) \
+
+#endif /* STRING_UTILS_H_ */
diff --git a/Build/source/texk/xdvik/t1mapper b/Build/source/texk/xdvik/t1mapper
new file mode 100755
index 00000000000..7562e090131
--- /dev/null
+++ b/Build/source/texk/xdvik/t1mapper
@@ -0,0 +1,433 @@
+#!/usr/bin/perl -w
+#
+# This program maps full PS font names to abreviated TeX style names
+# and puts font files or links to font files in a file hierarchy
+# suitable for texk.
+#
+# Mapping example: Times-Roman.{gsf,pfa,pfb} becomes ptmr.{pfa,pfb}
+#
+
+use File::Path;
+
+# These are the fontname map files to read
+
+# This is for the fontname distribution in teTeX 0.4:
+# @fonts=qw(adobe apple bitstrea dtc linotype monotype skey1250 skey1555
+# softkey urw);
+
+# This is for fontname 2.2, get it from ftp.tug.org:/tex/fontname-2.2
+# The linotype map in teTeX 1.0 is terebly corrupted. Removed from the list.
+
+@fonts=qw(adobe apple bitstrea dtc monotype softkey-1250
+ softkey-1555 urw wolfram yandy);
+
+$logname="t1mapper.log";
+
+# How much to read from font files to figure out the font name
+$fontdatalen=1024*10;
+
+# use $TMPDIR if set by user
+if (defined($ENV{TMPDIR})) {
+ $tempdir=$ENV{TMPDIR};
+}
+else {
+ $tempdir="/tmp";
+}
+
+# HERE BE DRAGONS
+
+usage() if $#ARGV==0;
+
+# By default copy files
+$method=1;
+
+while ($_=shift(@ARGV)) {
+ /^-cp$/ && do { $method=1; next; };
+ /^-ln$/ && do { $method=2; next; };
+ /^-lns$/ && do { $method=3; next; };
+ /^-lnlns$/ && do { $method=4; next; };
+ /^-lncp$/ && do { $method=5; next; };
+ /^-gs$/ && do {
+ $gsmap = shift(@ARGV) or usage();
+ $gsdir = shift(@ARGV) or usage();
+ next;
+ };
+ unshift(@ARGV,$_);
+ last;
+}
+
+$texdir = shift(@ARGV) or usage();
+
+if (! -d $texdir) {
+ print "Making directory $texdir\n";
+ mkpath($texdir) or die "Could not make directory: $texdir: $!\n";
+}
+
+if (!open(LOG,">$logname")) {
+ $logname="$tempdir/$logname";
+ open(LOG,">$logname") ||
+ die "Could not open file $logname for writing: $!\n";
+}
+
+# What major mode of operation?
+
+# Establish fonts based on ghostscript map?
+if ($gsmap) {
+ process_gsfonts();
+ print "Log in $logname\n";
+ exit 0;
+}
+
+# Ok, loop examine fonts to figure out the font name and copy/link to $texdir
+
+process_fontname_maps();
+process_fonts();
+print "Log in $logname\n";
+
+exit 0;
+
+# ############################### MOVE_FONT ################################
+
+sub move_font {
+ # Move font to destination directory, according to specified $method
+ my($from)=shift;
+ my($to)=shift;
+ my($relok)=shift;
+
+ my($other); # Same font, other format
+ my($type); # Other type
+
+ die "I need absolute paths please\n"
+ if !$relok && substr($from,0,1) ne '/';
+
+ logmsg("$from -> $to\n");
+
+ # Remove the old font to replace with this
+ unlink($to) if -f $to;
+
+ # Also remove the old font in the other format:
+ $other=$to;
+ $type='.pfb' if substr($to,-4) eq '.pfa';
+ $type='.pfa' if !$type && substr($to,-4) eq '.pfb';
+ substr($other,-4)=$type;
+
+ unlink($other) if -f $other;
+
+ if ($method==1) {
+ # cp
+ system "cp $from $to 2>/dev/null" and # Shell exit value
+ warn "Copying $from to $to failed\n";
+ } elsif ($method==2) {
+ # ln
+ link($from,$to) or
+ die "Linking of $to to $from failed: $!\n";
+ } elsif ($method==3) {
+ # lns
+ symlink($from,$to) or
+ die "Symlinking $to to $from failed: $!\n";
+ } elsif ($method==4) {
+ # lnlns
+ link($from,$to) ||
+ symlink($from,$to) ||
+ die "Both linking and symlinking $to to $from failed: $!\n";
+ } elsif ($method==5) {
+ # lncp. Let cp give the error-message
+ link($from,$to) || system "cp $from $to";
+ } else {
+ die "Internal error: Unknown font copy/link method\n";
+ }
+}
+
+# ############################# PROCESS_FONTS ##############################
+
+sub process_fonts {
+ # Loop over ARGV, examine each (font?) file to see if it is a
+ # type1 font, binary or text format, and figure out it's name
+ my($type,$font);
+
+ foreach $filename (@ARGV) {
+ ($type,$font)=examine_font($filename);
+
+ next if !defined($font);
+
+ if (!exists($file{$font})) {
+ logmsg("TeX name of $font ($filename) unknown\n");
+ next;
+ }
+
+ $file=$file{$font};
+ move_font($filename,"$texdir/$file$type",0);
+ }
+}
+
+# ############################## EXAMINE_FONT ##############################
+
+sub examine_font {
+ # Examine font to determine name and type
+ #
+ # The method for finding the font name is based on an awk script
+ # written years ago by Kjetil T. Homme and me (mostly him).
+ #
+ my($filename)=shift;
+ my($type);
+
+ my($size)=-s $filename;
+
+ if ($size==0) {
+ logmsg("Zero size file skipped: $filename\n");
+ return (undef,undef);
+ }
+
+ if (!open(FONT,"< $filename")) {
+ logmsg("Unable to open $filename for reading: $!\n");
+ return (undef,undef);
+ }
+
+ sysread FONT, $fontdata, $fontdatalen, 0;
+
+ # Determine type based on magic number
+ $type='.pfa' if substr($fontdata,0,16) eq '%!PS-AdobeFont-1';
+ $type='.pfa' if !$type && substr($fontdata,0,13) eq '%!FontType1-1';
+ $type='.pfb' if !$type && substr($fontdata,6,16) eq '%!PS-AdobeFont-1';
+
+ if (!$type) {
+ # This is where we end up if the file does not match the magic
+ # numbers. The file is most probably not a type1 file.
+
+ if ((index($fontdata,'%!PS-AdobeFont-1')==-1) &&
+ (index($fontdata,'%!FontType1-1')==-1)) {
+ # If the string '%!PS-AdobeFont-1.0' or '%!FontType1-1.0'
+ # does not appear at all this is NOT a type1 font of any
+ # kind.
+ logmsg("$filename is not a type1 file\n");
+ return (undef,undef);
+ }
+
+ logmsg("Odd magic in $filename\n");
+
+ # Try to determine type based on filename extention
+ $type='.pfa' if substr($filename,-4) eq '.pfa';
+ $type='.pfb' if !$type && substr($filename,-4) eq '.pfb';
+
+ if (!$type) {
+ # No extention? Fall back to perls -T (text) test operator.
+ $type='.pfb';
+ $type='.pfa' if -T $filename;
+ }
+ }
+
+ # The font type has now been determined. I wonder what the font's
+ # name is.
+
+ # What we look for is lines like this:
+ #
+ # %!PS-AdobeFont-1.0: URWGothicL-Demi 001.005
+ #
+ # or this:
+ #
+ # /FontName /URWGothicL-Demi def
+
+ $fontname='';
+
+ if ($fontdata =~ m~/FontName /([\S]+) def~) {
+ # The /FontName line is the most reliable source
+ $fontname = $1;
+ } elsif ($fontdata =~ m/%\!PS-AdobeFont-1.0: ([\S]+)/) {
+ # The magic line is not always fully formed and can only be
+ # used as fallback --- in case the /FontName entry is not in
+ # the file. True, this would be a rather dubious font.
+ $fontname = $1;
+ } elsif ($fontdata =~ m/%\!FontType1-1.0: ([\S]+)/) {
+ # The magic line is not always fully (or correctly) formed and
+ # can only be used as fallback --- in case the /FontName entry
+ # is not in the file. True, this would be a rather dubious
+ # font (actually, a lot of type1 versions of tex fonts fall
+ # into this category).
+ $fontname = $1;
+ }
+
+ return ($type,$fontname);
+}
+
+# ######################### PROCESS_FONTNAME_MAPS ##########################
+
+sub process_fontname_maps {
+ # Read the fontname maps
+
+ while ($foundry=shift(@fonts)) {
+ $map=findfile($foundry.".map");
+ next unless $map;
+ print "Reading (fontname/$foundry) $map\n";
+ open(FILE,"<$map") || die "Could not open $map: $!\n";
+ while (<FILE>) {
+ chomp;
+ s/@.*//;
+ next if $_ eq '';
+ ($file,$font,undef)=split(/\s+/,$_,3);
+ # Remove known encoding codes:
+ $file =~ s/(8a|8r|8t)$//;
+ # 8a = StandardEncoding 8a.enc
+ # 8r = TeXBase1Encoding 8r.enc
+ # 8t = CorkEncoding cork.enc
+ # Any filenames with numbers left are 'unknown encodings'
+ if ($file =~ /\d/) {
+ # print "Unknown encoding: $file - $font\n";
+ next;
+ }
+ $file{$font}=$file;
+ }
+ close(FILE);
+ }
+}
+
+# ########################### PROCESS_GSFONTS #############################
+
+sub read_gsmap {
+ # Read gs map file to obtain Font-Name -> filename mappings, and
+ # aliases so we can use GS' Times-Roman replacement as Times-Roman
+ # ourselves. Not everyone has oodles of type1 fonts on disk.
+
+ my($gsmap)=shift;
+
+ open(FILE,"<$gsmap") or die "Could not open $gsmap: $!\n";
+
+ print "Reading (gsmap) $gsmap\n";
+
+ %gsalias=();
+ %gsfile=();
+
+ while (<FILE>) {
+ chomp;
+ s/%.*//;
+ s/\s+$//;
+ next if $_ eq '';
+
+ ($font,$file,undef)=split(/\s+/,$_,3);
+
+ $font =~ s~^/~~;
+
+ if (!exists($file{$font})) {
+ logmsg("TeX name of $font unknown\n");
+ next;
+ }
+
+ if ($file =~ m~\((.*)\)~) {
+ $file = $1;
+ $gsfile{$font}=$file;
+ } else {
+ $file =~ s~^/~~;
+ # The aliases(sp?) cannot be resolved until the whole file is
+ # read
+ $gsalias{$font}=$file;
+ }
+
+ }
+
+ close(FILE);
+}
+
+
+sub process_gsfonts {
+ # Do the Work based on a ghostscript map file.
+
+ process_fontname_maps();
+ read_gsmap($gsmap);
+
+ chdir($gsdir) or die "Could not chdir to $gsdir: $!\n";
+
+ print "Moving fonts\n";
+
+ foreach $font (keys %gsfile) {
+ $gsfile=$gsfile{$font};
+ # GSF files are not propper t1 fonts I understand, so ignore them
+ next if $gsfile =~ /\.gsf$/;
+ $file=$file{$font};
+ $type='';
+
+ if (-f $gsfile) {
+
+ # Crude font type guessing. First based on existing extention:
+ $type='pfa' if substr($gsfile,-4) eq '.pfa';
+ $type='pfb' if !$type && substr($gsfile,-4) eq '.pfb';
+
+ # If existing extention fails use perls -T (text) test
+ if (!$type) {
+ # print "Fallback typing: $gsfile\n";
+ $type='pfb';
+ $type='pfa' if -T $gsfile;
+ }
+
+ # Use for alias resolving
+ $texname{$font}="$file.$type";
+
+ if (substr($gsfile,0,1) eq '/') {
+ move_font("$gsfile","$texdir/".$texname{$font},0);
+ } else {
+ move_font("$gsdir/$gsfile","$texdir/".$texname{$font},0);
+ }
+
+ } else {
+ logmsg("$file not found\n");
+ }
+ }
+
+ chdir($texdir) or die "Could not chdir to $texdir\n";
+
+ foreach $font (keys %gsalias) {
+ $alias = $gsalias{$font};
+ $falias = $texname{$alias};
+ next unless $falias;
+
+ $type='pfa' if substr($gsfile,-4) eq '.pfa';
+ $type='pfb' if !$type && substr($gsfile,-4) eq '.pfb';
+
+ $file=$file{$font};
+
+ # Symlink the aliases
+ logmsg("$falias -> $file.$type\n");
+ $method=3;
+ move_font($falias,"$file.$type",1);
+ }
+}
+
+
+# ############################ JUNK PROCEDURES ###########################
+
+sub findfile {
+ # Find file, use kpsewhich to access texmf database and search rules
+
+ my($file)=shift;
+ $fileloc=`kpsewhich $file`;
+
+ # Check errors
+ return undef if ($? != 0);
+ chomp($fileloc);
+ return undef if $fileloc eq '';
+
+ # It worked
+ return $fileloc;
+}
+
+sub usage {
+ # Abuse the user
+ print
+"Usage: t1mapper [-cp|-ln|-lns|-lnlns|-lncp] \\
+ -gs /path/to/gs/Fontmap /path/to/gs/fonts \\
+ /path/to/target/tex/directory
+
+ t1mapper [-cp|-ln|-lns|-lnlns|-lncp] \\
+ /path/to/target/tex/directory \\
+ <font-file-list>
+
+See t1mapper(1) for more documentation
+
+";
+ exit 1;
+}
+
+sub logmsg {
+ my($string)=shift;
+
+ print STDERR "$string";
+ print LOG "$string";
+}
diff --git a/Build/source/texk/xdvik/t1mapper.1 b/Build/source/texk/xdvik/t1mapper.1
new file mode 100644
index 00000000000..624cf1c55f5
--- /dev/null
+++ b/Build/source/texk/xdvik/t1mapper.1
@@ -0,0 +1,146 @@
+.TH t1mapper "1" "15 October 2001"
+.SH NAME
+t1mapper \- A tool to help xdvi use all your t1 fonts
+.SH SYNOPSIS
+.B t1mapper
+[\fIOPTIONS\fR] \fITeX-fontdir Type1-font-file-spec\fR
+.PP
+.B t1mapper
+[\fIOPTIONS\fR] -gs \fIGS-fontmap GS-fontdir TeX-fontdir\fR
+.SH DESCRIPTION
+.B T1mapper
+is a utility script written in Perl. It assists you in making
+new Postscript<tm> Type1 fonts available for use with
+.BR xdvi .
+.PP
+\fINOTE: \fBRunning this utility is only required if your TeX installation
+doesn't already contain the neccessary .pfb files somewhere in the
+texmf/ directory hierarchy.\fR
+.PP
+The first invocation shown above makes any Type1 font you may have floating around
+on your system available to
+.BR xdvi .
+The second invocation is for hi-jacking fonts from your Ghostscript
+installation, which will supply
+.B xdvi
+with all the standard Type1 fonts it needs.
+.PP
+.B T1mapper
+relies on a installed and working
+.B texk
+system to be present. In
+particular it uses
+.B kpsewhich
+to locate the
+.B fontname
+package .map files which maps between Postscript<tm> font names and TeX
+font names.
+.B teTeX
+is one such
+.B texk
+system.
+.PP
+When invoked without the
+.B -gs
+option, t1mapper will examine each of the fonts specified. It will
+attempt to determine the Postscript name of the font by looking inside
+the font file, and if that name has a TeX equivalent it will copy,
+link or symlink your the file into the TeX font directory you named
+first on the command line. The name in the TeX font directory will be
+according to the TeX/KB-fontname scheme, so that the font names used
+in
+.B .dvi
+files matches the names found in the TeX font directories.
+.PP
+When invoked with the
+.B -gs
+option
+.B t1mapper
+will read the named GS Fontmap file to determine which GS font files
+correspond to which standard Postscript fonts (GS' version of
+Times-Roman is not called \fITimes-Roman\fR, it's actually called
+\fINimbusRomNo9L-Regu\fR), and then proceed to copy or link the files
+in the named GS font directory into the named TeX font directory.
+.PP
+The program's diagnostic output is also written to a logfile
+.IR t1map.log ,
+which is created either in the current working directory or in
+.BR /tmp .
+.SH OPTIONS
+All options except
+.B -gs
+have to do with how the font files are copied or linked into the TeX
+font directories:
+.TP
+.B -cp
+Copy the files from the \fIGS-fontdir\fR or matching the
+\fIType1-font-file-spec\fR into the \fITeX-fontdir\fR. This is the
+default and will always work.
+.TP
+.B -ln
+Hard link the files. This requires the fonts to reside on the same
+disk, but it will save space, and the files will not disappear from
+the \fITeX-fontdir\fR if they are removed from the source directory.
+.TP
+.B -lns
+Symlink the files. This saves space, but if the original files are
+removed the symlinks will be broken.
+.TP
+.B -lnlns
+Attempt hard-link first, if it fails make symlink.
+.TP
+.B -lncp
+Attempt hard-link first, if that fails, copy the font.
+.SH EXAMPLES
+If your Ghostscript is installed in
+.B /usr/local/share/ghostscript
+and your TeX
+lives in
+.B /usr/local/teTeX
+then this command will make your GS fonts available to xdvi:
+.PP
+.Vb 4
+\&t1mapper -lns -gs \e
+\& /usr/local/share/ghostscript/5.50/Fontmap \e
+\& /usr/local/share/ghostscript/fonts \e
+\& /usr/local/teTeX/share/texmf/fonts/type1/gs
+.Ve
+.PP
+The first argument here is the full path to the GS Fontmap. The
+second is the GS font directory, note the lack of wildcards here (as
+opposed to the next example). The third argument is the TeX font
+directory. If it does not exist it will be created. Texk and teTeX uses
+quite finely structured font directories, and the above reflects this.
+.PP
+If you have a Solaris machine with Display Postscript fonts then this
+command will make them available to xdvi:
+.PP
+.Vb 4
+\&t1mapper -lns \e
+\& /usr/local/teTeX/share/texmf/fonts/type1/gs \e
+\& /usr/openwin/lib/X11/fonts/Type1/*.pfa
+.Ve
+.PP
+Here the first argument is the TeX font directory and thereafter comes
+a wildcard that specifies which fonts to examine for copying/linking
+into the TeX font directory.
+.SH FILES
+.B fontname
+Postscript to TeX name mapping files from
+.B http://tug.org/fontname/,
+these are included in teTeX.
+.PP
+.B Ghostscript
+fonts from
+.B http://sourceforge.net/projects/ghostscript/
+or
+.B http://www.gnu.org/software/ghostscript/ghostscript.html
+.SH SEE ALSO
+.BR kpsewhich (1),
+.BR xdvi (1),
+.BR ln (1),
+.B README.t1fonts
+in the source distribution
+.SH AUTHOR
+Nicolai Langfeldt for the xdvik project at SourceForge (see
+.BR http://sourceforge.net/projects/xdvi/ ).
diff --git a/Build/source/texk/xdvik/texmf-alt/README b/Build/source/texk/xdvik/texmf-alt/README
new file mode 100644
index 00000000000..069c4e988c9
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/README
@@ -0,0 +1,31 @@
+
+README for the texmf-alt (`alternative') directory:
+
+This directory contains xdvi.cfg and *.map files for users of
+older versions of teTeX (< 1.0) or non-teTeX distributions.
+
+Users of teTeX >= 1.0 or TeXLive >= 6b should use the files
+in ../texmf/ instead.
+
+Installation:
+
+The `make install' target doesn't install these files, so you'll
+need to install them manually. Copy all files into the directory
+ TEXMFMAIN/xdvi
+where TEXMF is your main texmf tree. Use e.g.:
+
+ kpsewhich --expand-path='$TEXMFMAIN'
+
+to locate this directory. Make sure the XDVIINPUTS variable
+(set either in the xdvi shell wrapper or in your shell)
+contains this directory, e.g. by setting:
+
+ export XDVIINPUTS='.;$TEXMF/{xdvi,dvips//}'
+
+Some map files might also be located in the directory
+TEXMFMAIN/dvips/config; setting XDVIINPUTS like above should
+find these as well.
+
+Please consult the file README.t1fonts if you experience problems
+with your Type1 font setup.
+
diff --git a/Build/source/texk/xdvik/texmf-alt/charter2.map b/Build/source/texk/xdvik/texmf-alt/charter2.map
new file mode 100644
index 00000000000..40cf1e6707f
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/charter2.map
@@ -0,0 +1,5 @@
+% Thomas Esser, 1998, public domain.
+% Updated for xdvi by Nicolai Langfeldt 1998, public domain.
+
+bchbo8r CharterBT-Bold ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <bchb
+bchro8r CharterBT-Roman ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <bchr
diff --git a/Build/source/texk/xdvik/texmf-alt/lucida.map b/Build/source/texk/xdvik/texmf-alt/lucida.map
new file mode 100644
index 00000000000..18040dd069a
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/lucida.map
@@ -0,0 +1,110 @@
+% lucida.map
+% Mappings of lucida fonts for xdvi.
+%
+% I have not looked at this file in disgust - janl 21/2/1999
+%
+% If t1mapper has been used on the lucida fonts then most of these are
+% quite redundant.
+
+hlcbot8r LucidaTypewriterBoldOblique "TeXBase1Encoding ReEncodeFont" <8r.enc <lbtbo.pfb
+hlcbt8r LucidaTypewriterBold "TeXBase1Encoding ReEncodeFont" <8r.enc <lbtb.pfb
+
+hlcda LucidaNewMath-Arrows-Demi <lbmad.pfb
+hlcdim LucidaNewMath-DemiItalic <lbmdi.pfb
+hlcdima LucidaNewMath-AltDemiItalic <lbmdo.pfb
+hlcdm LucidaNewMath-Demibold <lbmd.pfb
+hlcdy LucidaNewMath-Symbol-Demi <lbmsd.pfb
+hlcra LucidaNewMath-Arrows <lbma.pfb
+hlcrf8r LucidaBlackletter "TeXBase1Encoding ReEncodeFont" <8r.enc <lbl.pfb
+hlcrie8r LucidaCalligraphy-Italic "TeXBase1Encoding ReEncodeFont" <8r.enc <lbc.pfb
+
+hlcbot8rn LucidaTypewriterBoldOblique ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbtbo.pfb
+hlcbt8rn LucidaTypewriterBold ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbtb.pfb
+
+hlcrim LucidaNewMath-Italic <lbmi.pfb
+hlcrima LucidaNewMath-AltItalic <lbmo.pfb
+hlcrin8r LucidaCasual-Italic "TeXBase1Encoding ReEncodeFont" <8r.enc <lbki.pfb
+hlcriw8r LucidaHandwriting-Italic "TeXBase1Encoding ReEncodeFont" <8r.enc <lbh.pfb
+hlcrm LucidaNewMath-Roman <lbmr.pfb
+hlcrn8r LucidaCasual "TeXBase1Encoding ReEncodeFont" <8r.enc <lbkr.pfb
+hlcrof8r LucidaBlackletter ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbl.pfb
+hlcron8r LucidaCasual ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbkr.pfb
+hlcrot8r LucidaTypewriterOblique "TeXBase1Encoding ReEncodeFont" <8r.enc <lbto.pfb
+hlcrot8rn LucidaTypewriterOblique ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbto.pfb
+hlcrt8r LucidaTypewriter "TeXBase1Encoding ReEncodeFont" <8r.enc <lbtr.pfb
+hlcrt8rn LucidaTypewriter ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbtr.pfb
+hlcrv LucidaNewMath-Extension <lbme.pfb
+hlcry LucidaNewMath-Symbol <lbms.pfb
+hlhb8r LucidaBright-Demi "TeXBase1Encoding ReEncodeFont" <8r.enc <lbd.pfb
+hlhbc8r LucidaBrightSmallcaps-Demi "TeXBase1Encoding ReEncodeFont" <8r.enc <lbdsc.pfb
+hlhbi8r LucidaBright-DemiItalic "TeXBase1Encoding ReEncodeFont" <8r.enc <lbdi.pfb
+hlhbo8r LucidaBright-Demi ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lbd.pfb
+hlhr8r LucidaBright "TeXBase1Encoding ReEncodeFont" <8r.enc <lbr.pfb
+hlhrc8r LucidaBrightSmallcaps "TeXBase1Encoding ReEncodeFont" <8r.enc <lbrsc.pfb
+hlhri8r LucidaBright-Italic "TeXBase1Encoding ReEncodeFont" <8r.enc <lbi.pfb
+hlhro8r LucidaBright-Oblique "TeXBase1Encoding ReEncodeFont" <8r.enc <lbsl.pfb
+hlsb8r LucidaSans-Demi "TeXBase1Encoding ReEncodeFont" <8r.enc <lsd.pfb
+hlsbi8r LucidaSans-DemiItalic "TeXBase1Encoding ReEncodeFont" <8r.enc <lsdi.pfb
+hlsbot8r LucidaSans-TypewriterBoldOblique "TeXBase1Encoding ReEncodeFont" <8r.enc <lstbo.pfb
+hlsbot8rn LucidaSans-TypewriterBoldOblique ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lstbo.pfb
+hlsbt8r LucidaSans-TypewriterBold "TeXBase1Encoding ReEncodeFont" <8r.enc <lstb.pfb
+hlsbt8rn LucidaSans-TypewriterBold ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lstb.pfb
+hlsr8r LucidaSans "TeXBase1Encoding ReEncodeFont" <8r.enc <lsr.pfb
+hlsri8r LucidaSans-Italic "TeXBase1Encoding ReEncodeFont" <8r.enc <lsi.pfb
+hlsro8r LucidaSans ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lsr.pfb
+hlsrot8r LucidaSans-TypewriterOblique "TeXBase1Encoding ReEncodeFont" <8r.enc <lsto.pfb
+hlsrot8rn LucidaSans-TypewriterOblique ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lsto.pfb
+hlsrt8r LucidaSans-Typewriter "TeXBase1Encoding ReEncodeFont" <8r.enc <lstr.pfb
+hlsrt8rn LucidaSans-Typewriter ".850 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <lstr.pfb
+hlsu8r LucidaSans-Bold "TeXBase1Encoding ReEncodeFont" <8r.enc <lsb.pfb
+hlsui8r LucidaSans-BoldItalic "TeXBase1Encoding ReEncodeFont" <8r.enc <lsbi.pfb
+hlsuo8r LucidaSans-Bold ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lsb.pfb
+hlxb8r LucidaFax-Demi "TeXBase1Encoding ReEncodeFont" <8r.enc <lfd.pfb
+hlxbi8r LucidaFax-DemiItalic "TeXBase1Encoding ReEncodeFont" <8r.enc <lfdi.pfb
+hlxbo8r LucidaFax-Demi ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lfd.pfb
+hlxr8r LucidaFax "TeXBase1Encoding ReEncodeFont" <8r.enc <lfr.pfb
+hlxri8r LucidaFax-Italic "TeXBase1Encoding ReEncodeFont" <8r.enc <lfi.pfb
+hlxro8r LucidaFax ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <lfr.pfb
+
+lbkr LucidaCasual "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbkr.pfb
+lbl LucidaBlackletter "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbl.pfb
+lbma LucidaNewMath-Arrows <lbma.pfb
+lbmad LucidaNewMath-Arrows-Demi <lbmad.pfb
+lbmd LucidaNewMath-Demibold <lbmd.pfb
+lbmdi LucidaNewMath-DemiItalic <lbmdi.pfb
+lbmdo LucidaNewMath-AltDemiItalic <lbmdo.pfb
+lbme LucidaNewMath-Extension <lbme.pfb
+lbmi LucidaNewMath-Italic <lbmi.pfb
+lbmo LucidaNewMath-AltItalic <lbmo.pfb
+lbmr LucidaNewMath-Roman <lbmr.pfb
+lbms LucidaNewMath-Symbol <lbms.pfb
+lbmsd LucidaNewMath-Symbol-Demi <lbmsd.pfb
+lbr LucidaBright "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbr.pfb
+lbrsc LucidaBrightSmallcaps "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbrsc.pfb
+lbsl LucidaBright-Oblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbsl.pfb
+lbtb LucidaTypewriterBold "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbtb.pfb
+lbtbo LucidaTypewriterBoldOblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbtbo.pfb
+lbto LucidaTypewriterOblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbto.pfb
+lbtr LucidaTypewriter "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbtr.pfb
+lfd LucidaFax-Demi "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lfd.pfb
+lfdi LucidaFax-DemiItalic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lfdi.pfb
+lfi LucidaFax-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lfi.pfb
+lfr LucidaFax "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lfr.pfb
+lsb LucidaSans-Bold "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsb.pfb
+lsbi LucidaSans-BoldItalic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsbi.pfb
+lsd LucidaSans-Demi "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsd.pfb
+lsdi LucidaSans-DemiItalic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsdi.pfb
+lsi LucidaSans-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsi.pfb
+lsr LucidaSans "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsr.pfb
+lstb LucidaSans-TypewriterBold "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lstb.pfb
+lstbo LucidaSans-TypewriterBoldOblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lstbo.pfb
+lsto LucidaSans-TypewriterOblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lsto.pfb
+lstr LucidaSans-Typewriter "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lstr.pfb
+
+lbc LucidaCalligraphy-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbc.pfb
+lbd LucidaBright-Demi "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbd.pfb
+lbdi LucidaBright-DemiItalic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbdi.pfb
+lbdsc LucidaBrightSmallcaps-Demi "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbdsc.pfb
+lbh LucidaHandwriting-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbh.pfb
+lbi LucidaBright-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbi.pfb
+lbki LucidaCasual-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <lbki.pfb
diff --git a/Build/source/texk/xdvik/texmf-alt/marvosym.map b/Build/source/texk/xdvik/texmf-alt/marvosym.map
new file mode 100644
index 00000000000..d63aaca8407
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/marvosym.map
@@ -0,0 +1,2 @@
+fmvr8x Martin_Vogels_Symbole <marvosym.pfb
+fmvri8x Martin_Vogels_Symbole " .167 SlantFont" <marvosym.pfb
diff --git a/Build/source/texk/xdvik/texmf-alt/xdvi.cfg b/Build/source/texk/xdvik/texmf-alt/xdvi.cfg
new file mode 100644
index 00000000000..51966e747fc
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/xdvi.cfg
@@ -0,0 +1,90 @@
+% original xdvi.cfg -- Configuration file for the Type1 rendering module of xdvi.
+% (If you change or delete `original' in the first line of this file,
+% new xdvik installations won't overwrite this file.)
+%
+% Lines starting with `%' are comments.
+%
+% Version 1.0 for xdvik-22.x and teTeX < 1.0 or non-teTeX installations,
+% 2003/02/28
+%
+% Original version by Nicolai Langfeldt 2001/06/05
+
+% NOTE TO TETEX USERS: For teTeX >= v1.0, use the file texmf/xdvi.cfg
+% instead. That file uses ps2pk.map which will automatically be updated
+% by teTeX's `updmap' script; by contrast, the map files listed in Section 2
+% below need to be maintained manually.
+
+
+% =============== Section 1: Encodings ===============
+%
+% Here we list all the encodings we want xdvi to recognize as an
+% "implied" encoding. This means that ptmr8r will be recognized as
+% ptmr encoded with 8r and ptmr8y as ptmr encoded with 8y. If the font file
+% we want to encode with 8r is named ptmr8a, however, this must be listed in
+% the map file entry.
+
+% NOTE: the enc files used by xdvi are similar to those used by dvips,
+% whith the important exception that xdvi _cannot_ parse postscript,
+% so the vectors mustn't require postscript execution.
+
+% Suffix Encoding name Defined by this file
+enc 8r TeXBase1Encoding 8r.enc
+enc 8c CorkEncoding cork.enc
+enc 8y TeXnANSIEncoding texnansi.enc
+
+
+
+% =============== Section 2: Map files ===============
+%
+% A font map file is a mapping of TeX font names (and encodings) to
+% Postscript Type1 font names, similar to dvips' psfonts.map. See the
+% dvips documentation for more information about the font map file
+% format, and the file `README.t1fonts' in the xdvik source
+% distribution for information on the differences between dvips and
+% xdvik font maps.
+%
+% Multiple map files are allowed. If a font entry is found in several
+% files, later entries will override earlier ones (and a warning
+% will be printed to stderr).
+%
+% The .map files listed below here are ones found in teTeX <= 1.0.
+
+% xdvifont.map is a edited digest of psfonts.map for use with xdvi
+dvipsmap xdvifont.map
+
+% Users of teTeX-1.0 should use the following combination of map files:
+%dvipsmap psfonts.map
+%dvipsmap ps2pk.map
+
+% Otherwise, you can add any of the following maps, depending on
+% whether you have the respective fonts.
+
+% We can use these un-modified:
+dvipsmap marvosym.map
+dvipsmap xypic.map
+
+% If you applied t1mapper to the Charter fonts (they are in gs)
+% you want this:
+dvipsmap charter2.map
+% otherwise you want this:
+% dvipsmap charter.map
+
+% Lucida fonts. Possibly unsuitabe. Much of these are wrong if
+% t1mapper was applied to the fonts. Some of the lines describing
+% fonts with modified slant or width will need editing if t1mapper was
+% applied. If t1mapper was not applied they are both needed:
+% dvipsmap lucidabr.map
+% dvipsmap utopia.map
+
+% "real" bakoma instead of interpolated bsr
+% dvipsmap bakomaextra.map
+% this one *or* the previous one. Not both!
+% dvipsmap bsr-missing-interpolated.map
+
+% Various symbol/calligraphic fonts
+% dvipsmap hoekwater.map
+
+% The following files are never needed: mathtime.map (partly trivial,
+% partly unsuitable, the rest is in xdvifont.map); acrobat.map,
+% lw35extra.map (t1mapper should have taken care of this); psfonts.map
+% (see above); cs.map, omega.map, bsr.map (no map files needed for these).
diff --git a/Build/source/texk/xdvik/texmf-alt/xdvifont.map b/Build/source/texk/xdvik/texmf-alt/xdvifont.map
new file mode 100644
index 00000000000..6c58606aa55
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/xdvifont.map
@@ -0,0 +1,56 @@
+% xdvifont.map.
+%
+% Derived from psfonts.map in teTeX 0.9 in this way:
+%
+% - Remove mappings which are also available in files we can use unmodified
+% - Remove all trivial mappings
+% - Lucida is a mess - put in separate file: lucida.map
+% - Add input file names for the standard fonts left
+%
+% NOTE: xdvi does not care about the font-file extention, but dvips does.
+%
+% Nicolai Langfeldt 21/2/1999.
+
+ppi020 MathematicalPi-Two <mh2.pfb
+ppi025 MathematicalPi-Six <mh6.pfb
+
+% So, non KB names for standard fonts:
+
+cob Courier-Bold "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <pcrb
+cobo Courier-BoldOblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <pcrbo
+com Courier "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <pcrr
+coo Courier-Oblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <pcrro
+
+pcrr8rn Courier ".85 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <pcrr
+
+hv Helvetica "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <phvr
+hvb Helvetica-Bold "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <phvb
+hvbo Helvetica-BoldOblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <phvbo
+hvo Helvetica-Oblique "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <phvro
+
+% This _should've_ been HelveticaNarrow, if you own Helvetica narrow
+% you want to comment these out:
+
+phvb8rn Helvetica-Bold ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <phvb
+phvbo8rn Helvetica-BoldOblique ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <phvbo
+phvr8rn Helvetica ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <phvr
+phvro8rn Helvetica-Oblique ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <phvro
+
+pplr8rn Palatino-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <pplr
+pplrr8re Palatino-Roman "1.2 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <pplr
+pplru8r Palatino-Italic "-.1763 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <pplri
+
+psyro Symbol ".167 SlantFont" <psyr
+
+ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <ptmr
+ptmrr8re Times-Roman "1.2 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <ptmr
+
+tib Times-Bold "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <ptmb
+tibi Times-BoldItalic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <ptmbi
+tibo Times-Bold ".167 SlantFont TeXnANSIEncoding ReEncodeFont" <texnansi.enc <ptmb
+tii Times-Italic "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <ptmri
+tio Times-Roman ".167 SlantFont TeXnANSIEncoding ReEncodeFont" <texnansi.enc <ptmr
+tir Times-Roman "TeXnANSIEncoding ReEncodeFont" <texnansi.enc <ptmr
+
+zd ZapfDingbats <pzdr
+
diff --git a/Build/source/texk/xdvik/texmf-alt/xypic.map b/Build/source/texk/xdvik/texmf-alt/xypic.map
new file mode 100644
index 00000000000..bd47b3ccaa1
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf-alt/xypic.map
@@ -0,0 +1,18 @@
+% Thomas Esser, 1998, public domain.
+xyatip10 XYATIP10 <xyatip10.pfb
+xybsql10 XYBSQL10 <xybsql10.pfb
+xybtip10 XYBTIP10 <xybtip10.pfb
+xycirc10 XYCIRC10 <xycirc10.pfb
+xycmat10 XYCMAT10 <xycmat10.pfb
+xycmat11 XYCMAT10 "1.1 ExtendFont" <xycmat10.pfb
+xycmat12 XYCMAT10 "1.2 ExtendFont" <xycmat10.pfb
+xycmbt10 XYCMBT10 <xycmbt10.pfb
+xycmbt11 XYCMBT10 "1.1 ExtendFont" <xycmbt10.pfb
+xycmbt12 XYCMBT10 "1.2 ExtendFont" <xycmbt10.pfb
+xydash10 XYDASH10 <xydash10.pfb
+xyeuat10 XYEUAT10 <xyeuat10.pfb
+xyeuat11 XYEUAT10 "1.1 ExtendFont" <xyeuat10.pfb
+xyeuat12 XYEUAT10 "1.2 ExtendFont" <xyeuat10.pfb
+xyeubt10 XYEUBT10 <xyeubt10.pfb
+xyeubt11 XYEUBT10 "1.1 ExtendFont" <xyeubt10.pfb
+xyeubt12 XYEUBT10 "1.2 ExtendFont" <xyeubt10.pfb
diff --git a/Build/source/texk/xdvik/texmf/XDvi b/Build/source/texk/xdvik/texmf/XDvi
new file mode 100644
index 00000000000..027df469453
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf/XDvi
@@ -0,0 +1,370 @@
+!!! Global application defaults for XDvik
+!!! Install this file into $TEXMF/xdvi/XDvi
+!!! (use kpsewhich --expand-path '$TEXMF' to determine the location of
+!!! $TEXMF on you system).
+!!!
+!!! Lines commented out (starting with `!') are examples of
+!!! how to customize Xdvi for your personal needs.
+!!! To use these settings, copy them into your $HOME/.Xdefaults file
+!!! (remove the comments), prefix each line with `xdvi', and activate
+!!! them with:
+!!! $ xrdb -merge $HOME/.Xdefaults
+
+!!!------------------------------------------------------------------------------
+!!!------------------------ useful global settings ------------------------------
+!!!------------------------------------------------------------------------------
+
+!!! Use `logical' (TeX) pages instead of physical pages for the `g' keystroke:
+*useTeXPages: True
+
+!!! A fairly high resolution, which usually gives better results for anti-aliasing
+!!! and greater flexibility for shrink values. Generating MF fonts shouldn't be an
+!!! issue when using T1lib.
+!*mfMode: ljfour
+!*paper: a4
+
+!!! This should be the best choice for modern displays with large color depth.
+*thorough: true
+
+!!!------------------------------------------------------------------------------
+!!!------------------------------ Motif toolbar ---------------------------------
+!!!------------------------------------------------------------------------------
+
+!!! filename of the XPM file used for the toolbar pixmaps:
+*toolbarPixmapFile: toolbar.xpm
+
+!!! Use toolbar buttons that are non-raised by default and only appear raised
+!!! when the mouse is over a button, as in e.g. Netscape 4.x:
+*toolbarButtonsRaised: False
+
+!!! don't draw a border around armed buttons:
+*button*highlightThickness: 0
+
+!!! no extra margin above/below buttons
+*toolBar.marginHeight:0
+
+!!! some spacing around button icons and button edges
+*toolBar*button*marginHeight: 2
+*toolBar*button*marginWidth: 2
+
+
+!!! don't draw the small grey rectangle inside the armed button:
+*button*fillOnArm: false
+
+!!! Or, for a more traditional Motif look, use something like:
+!*toolbarButtonsRaised: True
+!*button*fillOnArm: True
+!*button*shadowThickness: 1
+!*toolBar.marginHeight: 0
+!*toolBarFrame.marginWidth: 0
+!*button*highlightThickness: 2
+
+!!!------------------------------------------------------------------------------
+!!!-------------------------------- Motif widgets -------------------------------
+!!!------------------------------------------------------------------------------
+!!! small shadows like in netscape 4.x
+*menuBar.shadowThickness: 1
+*button*shadowThickness: 2
+*toolBar.shadowThickness: 1
+*toolBarFrame.shadowThickness: 1
+*helppanel.shadowThickness: 1
+*toolBarFrame.marginWidth: 2
+*statusline*shadowThickness: 1
+
+!!! prevent the Motif file selector widget from resizing itself, and start with a reasonable default:
+*resizePolicy: XmRESIZE_NONE
+*textColumns: 50
+
+!!! make all text/entry fields white, for better contrasts:
+*file_text.background: white
+*searchbox_input.background: white
+*print_text.background: white
+*dvips_options_text.background: white
+*from_page.background: white
+*to_page.background: white
+*topics_list.background: white
+*help_text.background: white
+*FilterText.background: white
+*DirList.background: white
+*ItemsList.background: white
+*file.Text.background: white
+
+!!! adjust position of header in help window
+*help_window*right_form.topOffset: 10
+
+!!!------------------------------------------------------------------------------
+!!!----------------------------- Preferences window -----------------------------
+!!!------------------------------------------------------------------------------
+
+*XmComboBox*List*background: white
+*XmComboBox*Text*background: white
+*XmComboBox*Text*borderWidth: 2
+*XmComboBox*Text*borderColor: black
+
+!!!------------------------------------------------------------------------------
+!!!--------------------------------- Help window --------------------------------
+!!!------------------------------------------------------------------------------
+!!! (See also the fontList entries for TOPIC_LABEL and TOPIC_HEADING)
+!!!
+!!! Set this to something that fits to your font size:
+*help_text.rows: 23
+*help_text.columns: 56
+
+!!! fg/bg for help topics label
+*help_label*shadowThickness: 2
+!!! ... if you want a more colorful label:
+!*help_label*foreground: blue4
+!*help_label*background: grey90
+
+
+!!! help topics label for Xaw
+*help_label.font: -*-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*
+
+!!!------------------------------------------------------------------------------
+!!!-------------------------------- Motif tooltips ------------------------------
+!!!------------------------------------------------------------------------------
+!!! background color and font:
+*tipShell.background: cornsilk
+*tipShell.fontSet: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*
+
+!!! time the mouse needs to stay on a button until tooltips pop up,
+!!! in milliseconds; set to a negative value to disable:
+*tipShell.waitPeriod: 800
+
+
+!!!------------------------------------------------------------------------------
+!!!------------------------------ Fonts and colors ------------------------------
+!!!------------------------------------------------------------------------------
+*font: -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*
+!!! Use a smaller font for the statusline in the Xaw version:
+*statusline.font: -*-helvetica-medium-r-*-*-10-*-*-*-*-*-*
+
+!!! Motif fonts. Meaning of the tags is:
+!!! NORMAL: Ordinary text, labels etc.
+!!! UNMARKED: Unmarked entries in page list
+!!! MARKED: Marked entries in page list, emphasized entries in other lists
+!!! TOPIC_LABEL: Label for topics list in help window
+!!! TOPIC_HEADING: Heading for help text in help window
+!!!
+*fontList: \
+-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*=NORMAL,\
+-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*=UNMARKED,\
+-*-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*=MARKED,\
+-*-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*=TOPIC_LABEL,\
+-*-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*=TOPIC_HEADING
+
+
+!!! Color used for page border, image bounding boxes and the ruler in `Ruler mode'.
+*highlight: red
+
+!!! Color used for the magnifier and its rulers:
+*rulecolor: blue
+
+!!!------------------------------------------------------------------------------
+!!!---------------------------------- hyperlinks -------------------------------
+!!!------------------------------------------------------------------------------
+
+!!! Colors for unvisited and visited hyperlinks (can be any valid X color spec,
+!!! also in hex format):
+*linkColor: Blue2
+*visitedLinkColor: Purple4
+
+!!! Link style:
+!!! 0: no highlighting at all
+!!! 1: underline with linkColor
+!!! 2: no underlining, text with linkColor
+!!! 3: underlining and text with linkColor
+*linkStyle: 3
+
+!!!------------------------------------------------------------------------------
+!!!------------------------------ helper applications ---------------------------
+!!!------------------------------------------------------------------------------
+
+!!! the editor used for `forward search'; can also be set via $EDITOR, $VISUAL
+!!! or $XEDITOR. Setting the X resource will override the environment variables.
+!!! The format strings `%l' and `%f' are optional.
+!!! You could use this for older emacsen that come with emacsclient:
+!*editor: emacsclient --no-wait +%l %f
+!!! and this for current emacs or xemacs that come with gnuclient (which is much better):
+!*editor: gnuclient -q +%l %f
+
+!!!------------------------------------------------------------------------------
+!!!------------------------------ Xaw buttons and helptexts ---------------------
+!!!------------------------------------------------------------------------------
+
+!!! The following sections are of a more esoteric nature, giving
+!!! examples for customizing the Xaw buttons and the help texts.
+!!! Maybe these are useful for i18n.
+
+!!!------------------------------
+!!! This is the default Xaw button configuration:
+!!!------------------------------
+! *buttonTranslations: \
+! File_Open ...:select-dvi-file()\n\
+! File_Reload:reread-dvi-file()\n\
+! File_Back Hyperref:htex-back()\n\
+! File_Quit:quit()\n\
+! Page_First page:goto-page(1)\n\
+! Page_Page-10:back-page(10)\n\
+! Page_Page-5:back-page(10)\n\
+! Page_Prev:back-page(1)\n\
+! Page_Next:forward-page(1)\n\
+! Page_Page+5:forward-page(5)\n\
+! Page_Page+10:forward-page(10)\n\
+! Page_Last page:goto-page()\n\
+! Zoom_Full size:set-shrink-factor(1)\n\
+! Zoom_$%%:shrink-to-dpi(150)\n\
+! Zoom_$%%:shrink-to-dpi(100)\n\
+! Zoom_$%%:shrink-to-dpi(50)\n\
+! Zoom_Fit in window:set-shrink-factor()\n\
+! Options_View PS:set-ps(toggle)\n\
+! Options_Keep position:set-keep-flag()\n\
+! Help_About ...:popup-help(helpGeneral)\n\
+! Help_Page Motion ...:popup-help(helpPagemotion)\n\
+! Help_Other Commands ...:popup-help(helpOthercommands)\n\
+! Help_HyperTeX commands ...:popup-help(helpHypertex)\n\
+! Help_Source specials ...:popup-help(helpSourcespecials)\n
+
+!!!------------------------------
+!!! help texts
+!!!------------------------------
+
+!!!------------------------------
+!!! about/general
+!!!------------------------------
+! *.helpGeneral: \
+! \n\
+! This is xdvik, CVS version.\n\
+! \n\
+! The xdvik project homepage is located at\n\
+! http://sourceforge.net/projects/xdvi,\n\
+! where you can find updates, report bugs and submit feature requests.\n\
+! \n\
+! Getting help and exiting xdvi\n\
+! \n\
+! h or ? or `Help' button\n\
+! Displays this help text.\n\
+! \n\
+! q or Control-C or Control-D or Cancel or Stop or Control-Z (VAX VMS)\n\
+! Quits the program.\n
+!
+
+!!!------------------------------
+!!! other commands
+!!!------------------------------
+! *helpOthercommands: \
+! \n\
+! Other Commands\n\
+! \n\
+! \n\
+! Control-F\n\
+! Find another DVI file.\n\
+! \n\
+! Control-L or Clear\n\
+! Redisplays the current page.\n\
+! \n\
+! Control-P\n\
+! Prints bitmap unit, bit order, and byte order.\n\
+! \n\
+! ^ or Home\n\
+! Move to the ``home'' position of the page. This is\n\
+! normally the upper left-hand corner of the page,\n\
+! depending on the margins as described in the -margins\n\
+! option, above.\n\
+! \n\
+! c Moves the page so that the point currently beneath the\n\
+! cursor is moved to the middle of the window. It also\n\
+! (gasp!) warps the cursor to the same place.\n\
+! \n\
+! G This key toggles the use of greyscale anti-aliasing for\n\
+! displaying shrunken bitmaps. In addition, the key\n\
+! sequences `0G' and `1G' clear and set this flag,\n\
+! respectively. See also the -nogrey option.\n\
+! \n\
+! k Normally when xdvi switches pages, it moves to the home\n\
+! position as well. The `k' keystroke toggles a `keep-\n\
+! position' flag which, when set, will keep the same\n\
+! position when moving between pages. Also `0k' and `1k'\n\
+! clear and set this flag, respectively. See also the\n\
+! -keep option.\n\
+! \n\
+! M Sets the margins so that the point currently under the\n\
+! cursor is the upper left-hand corner of the text in the\n\
+! page. Note that this command itself does not move the\n\
+! image at all. For details on how the margins are used,\n\
+! see the -margins option.\n\
+! \n\
+! P ``This is page number n.'' This can be used to make\n\
+! the `g' keystroke refer to actual page numbers instead\n\
+! of absolute page numbers.\n\
+! \n\
+! R Forces the dvi file to be reread. This allows you to\n\
+! preview many versions of the same file while running\n\
+! xdvi only once.\n\
+! \n\
+! s Changes the shrink factor to the given number. If no\n\
+! number is given, the smallest factor that makes the\n\
+! entire page fit in the window will be used. (Margins\n\
+! are ignored in this computation.)\n\
+! \n\
+! S Sets the density factor to be used when shrinking\n\
+! bitmaps. This should be a number between 0 and 100;\n\
+! higher numbers produce lighter characters.\n\
+! \n\
+! t Toggles to the next unit in a sorted list of TeX dimension\n\
+! units for the popup magnifier ruler.\n\
+! \n\
+! V Toggles Ghostscript anti-aliasing. Also `0V' and `1V' clear\n\
+! and enables this mode, respectively. See also the the\n\
+! -gsalpha option.\n\
+! \n\
+! x Toggles expert mode (in which the buttons do not appear).\n\
+! `1x' toggles display of the statusline at the bottom of\n\
+! the window.\n
+
+!!!------------------------------
+!!! page motion
+!!!------------------------------
+! *helpPagemotion: \
+! \n\
+! Moving around in the document\n\
+! \n\
+! \n\
+! \n\
+! n or f or Space or Return or LineFeed or PgDn\n\
+! Moves to the next page (or to the nth next page if a\n\
+! number is given).\n\
+! \n\
+! p or b or Control-H or BackSpace or DELete or PgUp\n\
+! Moves to the previous page (or back n pages).\n\
+! \n\
+! u or Up-arrow\n\
+! Moves up two thirds of a window-full.\n\
+! \n\
+! d or Down-arrow\n\
+! Moves down two thirds of a window-full.\n\
+! \n\
+! l or Left-arrow\n\
+! Moves left two thirds of a window-full.\n\
+! \n\
+! r or Right-arrow\n\
+! Moves right two thirds of a window-full.\n\
+! \n\
+! g or j or End\n\
+! Moves to the page with the given number. Initially,\n\
+! the first page is assumed to be page number 1, but this\n\
+! can be changed with the `P' keystroke, below. If no\n\
+! page number is given, then it goes to the last page.\n\
+! \n\
+! < Move to first page in document.\n\
+! > Move to last page in document.\n
+
+!!!------------------------------
+!!! end of helptexts
+!!!------------------------------
+
+
+!!!------------------------------------------------------------------------------
+!!!-------------- used for internal checking - DO NOT CHANGE THIS! --------------
+!!!------------------------------------------------------------------------------
+*appDefaultsFileVersion: 20030303
diff --git a/Build/source/texk/xdvik/texmf/xdvi.cfg b/Build/source/texk/xdvik/texmf/xdvi.cfg
new file mode 100644
index 00000000000..f058b6e2b62
--- /dev/null
+++ b/Build/source/texk/xdvik/texmf/xdvi.cfg
@@ -0,0 +1,61 @@
+% original xdvi.cfg -- Configuration file for the Type1 rendering module of xdvi.
+% (If you change or delete `original' in the first line of this file,
+% new xdvik installations won't overwrite the file.)
+%
+% Lines starting with `%' are comments.
+%
+% This file is not suitable for teTeX versions before 1.0. Users of
+% such or non-teTeX installations should have a look at the following
+% files instead:
+%
+% ../texmf-alt/xdvi.cfg
+% ../README.t1fonts
+%
+% For using this file with teTeX-1.0.x, please uncomment the line with
+% `psfonts.map' (preserving the order of the lines).
+%
+% For any later version of teTeX, no modification is needed.
+%
+
+% File version 1.2
+% Original version by Nicolai Langfeldt 2001/06/05
+% Changes by Thomas Esser for teTeX, Sat Nov 3 23:33:54 CET 2001.
+
+% =============== Section 1: Encodings ===============
+%
+% Here we list all the encodings we want xdvi to recognize as an
+% "implied" encoding. This means that a font named `ptmr8r' will
+% be treated as font `ptmr' encoded with `8r', and `ptmr8y' as
+% `ptmr' encoded with `8y'. Fonts that don not follow this convention
+% must have an explicit encoding entry in the map file.
+%
+% The encoding files used by xdvi are similar to those used by dvips,
+% whith the important exception that xdvi _cannot_ parse postscript,
+% so the vectors mustn't require postscript execution.
+
+%Keyword Suffix Encoding name Defined by this file
+enc 8r TeXBase1Encoding 8r.enc
+enc 8c CorkEncoding cork.enc
+enc 8y TeXnANSIEncoding texnansi.enc
+
+
+
+% =============== Section 2: Map files ===============
+%
+% A font map file is a mapping of TeX font names (and encodings) to
+% Postscript Type1 font names, similar to dvips' psfonts.map. See the
+% dvips documentation for more information about the font map file
+% format, and the file `README.t1fonts' in the xdvik source
+% distribution for information on the differences between dvips and
+% xdvik font maps.
+%
+% Multiple map files are allowed. If a font entry is found in several
+% files, later entries will override earlier ones (and a warning
+% will be printed to stderr).
+%
+% ps2pk has no "built-in" fonts, just like xdvik, so its map file is used
+% for xdvik too. For teTeX-1.0, psfonts.map is needed in addition.
+
+% dvipsmap psfonts.map
+dvipsmap ps2pk.map
+
diff --git a/Build/source/texk/xdvik/tfmload.c b/Build/source/texk/xdvik/tfmload.c
new file mode 100644
index 00000000000..4b904b2576e
--- /dev/null
+++ b/Build/source/texk/xdvik/tfmload.c
@@ -0,0 +1,120 @@
+/* This code was stolen from dvips for xdvi use. The file itself did
+ * not carry any licensing info. According to other filed the code
+ * either public domain, or, in the worst case, GPL.
+ *
+ * Loads a tfm file. It marks the characters as undefined.
+ *
+ * Modified for use by xdvi/t1 by Nicolai Langfeldt */
+
+#include <stdio.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "util.h"
+#include "tfmload.h"
+
+#ifdef T1LIB
+
+#include "kpathsea/tex-file.h"
+
+int fallbacktfm = 0;
+
+Boolean
+tfmload(const char *name, long *design, long *widths, long *fontdimen2)
+{
+ int i;
+ int li;
+ int nw, hd;
+ int bc, ec;
+ int f_param_off, f_param_num;
+ long wtab[256];
+ unsigned short chardat[256];
+ char *filename;
+ FILE *curfnt;
+
+ fallbacktfm = 0;
+
+ filename = kpse_find_tfm(name);
+
+ if (filename == NULL) {
+ filename = kpse_find_tfm("cmr10.tfm");
+ if (fallbacktfm == 0)
+ fallbacktfm = 1;
+ }
+
+ if (filename == NULL)
+ return False;
+
+ curfnt = XFOPEN(filename, "r");
+
+ if (curfnt == NULL)
+ return False;
+
+ /* Next, we read the font data from the tfm file, and store it in
+ * our own array. */
+
+ /* Lengths section, 16 bit unsigned quanities */
+ li = get_bytes(curfnt, 2); /* lf = length of file, in words(4 bytes) */
+ hd = get_bytes(curfnt, 2); /* lh = length of header data, in words */
+ bc = get_bytes(curfnt, 2); /* bc = lowest charcode */
+ ec = get_bytes(curfnt, 2); /* ec = largest charcode */
+ nw = get_bytes(curfnt, 2); /* nw = number of width words */
+ f_param_off = get_bytes(curfnt, 2); /* nh = number of height words */
+ f_param_off += get_bytes(curfnt, 2); /* nd = number of depth words */
+ f_param_off += get_bytes(curfnt, 2); /* ni = number of italic words */
+ f_param_off += get_bytes(curfnt, 2); /* nl = number of words in lig/kern table */
+ f_param_off += get_bytes(curfnt, 2); /* nk = number of words in the kern table */
+ f_param_off += get_bytes(curfnt, 2); /* ne = number of words in the extensible char tab */
+ f_param_num = get_bytes(curfnt, 2); /* np = number of font parameter words */
+
+ /* Header, 32 bit signed quantities */
+ get_bytes(curfnt, 4); /* header[0]: checksum */
+ *design = get_bytes(curfnt, 4); /* header[1]: design size */
+
+ /* Skip the rest: header[2..(hd-1)] */
+ for (i = 2; i < hd; i++)
+ li = get_bytes(curfnt, 4);
+
+ /* Initialize to undef value */
+ for (i = 0; i < 256; i++) {
+ chardat[i] = 256;
+ widths[i] = 0;
+ }
+
+ /* The charinfo array: */
+ for (i = bc; i <= ec; i++) {
+ chardat[i] = get_byte(curfnt); /* 8 bits of width index */
+ get_byte(curfnt); /* skip */
+ get_bytes(curfnt, 2); /* skip, jump */
+ }
+
+ /* The (compressed!) width table */
+ for (i = 0; i < nw; i++)
+ wtab[i] = get_bytes(curfnt, 4);
+
+ /* skip to font parameter words */
+ for (i = 0; i < f_param_off; i++)
+ get_bytes(curfnt, 4);
+
+ /* read fontdimen2 (width of space) */
+ for (i = 0; i < f_param_num; i++) {
+ long l = get_bytes(curfnt, 4);
+ if (i == 1) {
+ *fontdimen2 = l;
+ if (globals.debug & DBG_T1)
+ fprintf(stderr, "fontdimen2 of %s: %ld\n", filename, *fontdimen2);
+ }
+
+ }
+ (void)fclose(curfnt);
+
+ /* Now we have the table and the indexes. Expand into a directly
+ mapped width array */
+ for (i = bc; i <= ec; i++)
+ if (chardat[i] != 256)
+ widths[i] = wtab[chardat[i]];
+
+ return True;
+}
+
+#endif /* T1LIB */
diff --git a/Build/source/texk/xdvik/tfmload.h b/Build/source/texk/xdvik/tfmload.h
new file mode 100644
index 00000000000..35b9f7c853f
--- /dev/null
+++ b/Build/source/texk/xdvik/tfmload.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef TFMLOAD_H_
+#define TFMLOAD_H_
+#ifdef T1LIB
+
+extern int fallbacktfm;
+extern Boolean tfmload(const char *, long *, long *, long *);
+
+#endif
+#endif /* TFMLOAD_H_ */
diff --git a/Build/source/texk/xdvik/translations.h b/Build/source/texk/xdvik/translations.h
new file mode 100644
index 00000000000..c811e540766
--- /dev/null
+++ b/Build/source/texk/xdvik/translations.h
@@ -0,0 +1,398 @@
+/* key translations */
+#include "c-auto.h"
+#include "xdvi.h"
+#include "version.h"
+
+static const char base_key_translations[] =
+/* note: more specific key bindings must always come first
+ (i.e. `alt ctrl' before `ctrl' before unmodified)
+ `:' at start of description means that case matters
+*/
+ "Ctrl<Key>]: pagehistory-delete-forward()\n"
+ "Ctrl<Key>[: pagehistory-delete-backward()\n"
+/* it seems the following is needed for compatibility with german, french,
+ italian, spanish and other keyboards that have [, ] on right Alt key? */
+ "Ctrl Mod2<Key>]: pagehistory-delete-forward()\n"
+ "Ctrl Mod2<Key>[: pagehistory-delete-backward()\n"
+ "Mod2<Key>]: pagehistory-forward()\n"
+ "Mod2<Key>[: pagehistory-back()\n"
+ "<Key>]: pagehistory-forward()\n"
+ "<Key>[: pagehistory-back()\n"
+ "Alt Ctrl<Key>+: change-density(10)\n" /* case insensitive, otherwise too hard to type */
+ ":Alt Ctrl<Key>-: change-density(-10)\n"
+ "Ctrl<Key>+: set-shrink-factor(+)\n" /* case insensitive, otherwise too hard to type */
+ ":Ctrl<Key>-: set-shrink-factor(-)\n"
+ ":<Key>-: minus()\n"
+ ":<Key>?: help()\n"
+ ":<Key>>: goto-page()\n"
+ ":<Key><: goto-page(1)\n"
+ ":<Key>^: home()\n"
+ "<Key>space: unpause-or-next()\n"
+ ":<Key>B: htex-back()\n"
+ ":<Key>b: back-page()\n"
+/* removed, redundant and gets in the way
+ ":Ctrl<Key>c: quit()\n" */
+#if COLOR
+ ":<Key>C: set-color()\n"
+#endif
+ ":<Key>c: center()\n"
+/* removed, redundant and gets in the way
+ ":Ctrl<Key>d: quit()\n" */
+ ":<Key>d: down()\n"
+ "Ctrl<Key>f: find()\n"
+ ":<Key>F: htex-forward()\n"
+ ":~Alt<Key>f: forward-page()\n"
+ "Ctrl<Key>g: find-next()\n"
+#ifdef GREY
+ ":<Key>G: set-greyscaling()\n"
+#endif
+ ":<Key>g: goto-page()\n"
+ "Ctrl<Key>h: back-page()\n"
+ ":~Alt<Key>h: help()\n"
+ ":<Key>i: htex-anchorinfo()\n"
+ "Ctrl<Key>j: forward-page()\n"
+ ":<Key>k: set-keep-flag()\n"
+ "Ctrl<Key>l: fullscreen()\n"
+ ":<Key>l: left()\n"
+ "Ctrl<Key>m: switch-mode()\n"
+ ":<Key>M: set-margins()\n"
+ ":~Alt<Key>m: toggle-mark()\n"
+ "~Alt Ctrl<Key>n: toggle-mark()forward-page()\n"
+ ":~Alt<Key>n: forward-page()\n"
+ "Ctrl<Key>o: select-dvi-file()\n"
+ ":~Alt<Key>o: ruler-snap-origin()\n"
+ /* this used to be show-display-attributes() - use the output of `-debug PK' instead */
+ "Ctrl<Key>p: print()\n"
+ ":<Key>P: declare-page-number()\n"
+ ":<Key>p: back-page()\n"
+ ":<Key>q: quit()\n"
+ "Ctrl<Key>r: forward-page(0)\n" /* redraw page */
+ ":<Key>R: reread-dvi-file()\n"
+ ":<Key>r: right()\n"
+ "Ctrl<Key>s: save()\n"
+ ":<Key>S: set-density()\n"
+ ":<Key>s: set-shrink-factor()\n"
+ ":<Key>T: use-tex-pages(toggle)\n"
+ ":<Key>t: switch-magnifier-units()\n"
+ "Ctrl<Key>u: back-page()toggle-mark()\n"
+ ":<Key>u: up()\n"
+ "Ctrl<Key>v: show-source-specials()\n"
+#ifdef PS_GS
+ ":<Key>V: set-gs-alpha()\n"
+#endif /* PS_GS */
+#ifdef PS
+ ":<Key>v: set-ps()\n"
+#endif
+ "Ctrl<Key>x: source-what-special()\n"
+ ":<Key>x: set-expert-mode()\n"
+#ifdef VMS
+ "~Alt Ctrl<Key>z: quit()\n"
+#endif
+ "<Key>Return: forward-page()\n"
+ "<Key>Delete: up-or-previous()\n"
+ "<Key>BackSpace: back-page()\n"
+#ifdef MOTIF
+ "<Key>osfDelete: up-or-previous()\n"
+ "<Key>osfBackSpace: back-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"
+ "<Key>osfLeft: left(0.015)\n"
+ "<Key>osfUp: up(0.015)\n"
+ "<Key>osfRight: right(0.015)\n"
+ "<Key>osfDown: down(0.015)\n"
+ "<Key>osfPageUp: back-page()\n"
+ "<Key>osfPageDown: forward-page()\n"
+ "<Key>osfCancel: discard-number()\n"
+#else
+ "Ctrl<Key>Home: goto-page(1)\n"
+ "Ctrl<Key>End: goto-page()\n"
+ "<Key>Home: home-or-top()\n"
+ "<Key>End: end-or-bottom()\n"
+ "<Key>Left: left(0.015)\n"
+ "<Key>Up: up(0.015)\n"
+ "<Key>Right: right(0.015)\n"
+ "<Key>Down: down(0.015)\n"
+ "<Key>Prior: back-page()\n"
+ "<Key>Next: forward-page()\n"
+ "<Key>Escape: discard-number()\n"
+#endif
+#ifdef XK_KP_Left
+ "<Key>KP_Home: home()\n"
+ "<Key>KP_Left: left()\n"
+ "<Key>KP_Up: up()\n"
+ "<Key>KP_Right: right()\n"
+ "<Key>KP_Down: down()\n"
+ "<Key>KP_Prior: back-page()\n"
+ "<Key>KP_Next: forward-page()\n"
+ "<Key>KP_Delete: up-or-previous()\n"
+ "<Key>KP_Enter: forward-page()\n"
+#endif
+ "";
+
+
+static const char base_mouse_translations[] =
+ "Shift<Btn1Down>: drag(+)\n"
+ "Shift<Btn2Down>: drag(|)\n"
+ "Shift<Btn3Down>: drag(-)\n"
+ "Ctrl<Btn1Down>: source-special()\n"
+ "<Btn1Down>: do-href()magnifier(*1)\n"
+ "<Btn2Down>: do-href-newwindow()magnifier(*2)\n"
+ "<Btn3Down>: magnifier(*3)\n"
+ "<Btn4Down>: magnifier(*4)\n"
+ "<Btn5Down>: magnifier(*5)\n"
+ "";
+
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+static const char default_menu_config[] =
+/*
+ BNF-like Syntax of the entries:
+
+ entry ::= entry-line `\n' ( entry )*
+ entry-line ::= menu-spec `:' button-type `:' mnemonic `:' action
+ menu-spec ::= menu-name ( `>' menu-name )*
+ menu-name ::= menu-title `|' accelerator
+
+ menu-title ::= String
+ mnemonic ::= <empty> | String
+ action ::= <empty> | String
+ accelerator ::= `A'|`B'|`C'|...|`a'|`b'|`c'|...
+ button-type ::= `PUSH' | `RADIO' | `CHECK' | `SEP'
+
+ Notes:
+ - In entry-line, every occurrence of `:' that's not a separator needs to be escaped
+ like this: `\:'; similar for `>' in menu-spec and `|' in menu-title.
+ - Every `>' in menu-spec creates a submenu for the corresponding menu.
+ - mnemonic is the key binding for the action, displayed as mnemonic string in
+ the Motif menus (not yet in the Xaw version, since Xaw doesn't provide for
+ such mnemonics by default).
+ - accelerator is the Motif menu accelerator key.
+ */
+ "File|F > Open ...|O :PUSH :Ctrl-o :select-dvi-file()\n"
+ "File|F > Open Recent |R :PUSH : :recent-files()\n"
+ "File|F > Reload|R :PUSH :R :reread-dvi-file()\n"
+ "File|F > Find ...|F :PUSH :Ctrl-f :find()\n"
+ "File|F > Find next ...|N :PUSH :Ctrl-g :find-next()\n"
+ "File|F > Print ...|P :PUSH :Ctrl-p :print()\n"
+ "File|F > Save as ...|S :PUSH :Ctrl-s :save()\n"
+ "File|F > Quit|Q :PUSH :q :quit()\n"
+/* ========== */
+ "Navigate|N > Page-10| :PUSH :10 p :back-page(10)\n"
+ "Navigate|N > Page-5| :PUSH :5 p :back-page(5)\n"
+ "Navigate|N > Prev|P :PUSH :p :back-page(1)\n"
+ "Navigate|N > Next|N :PUSH :n :forward-page(1)\n"
+ "Navigate|N > Page+5| :PUSH :5 n :forward-page(5)\n"
+ "Navigate|N > Page+10| :PUSH :10 n :forward-page(10)\n"
+ "Navigate|N :SEP ::\n"
+ "Navigate|N > First Page|F :PUSH :1 g :goto-page(1)\n"
+ "Navigate|N > Last Page|L :PUSH :g :goto-page()\n"
+ "Navigate|N :SEP ::\n"
+ "Navigate|N > Page History Back| :PUSH :[ :pagehistory-back()\n"
+ "Navigate|N > Page History Forward| :PUSH :] :pagehistory-forward()\n"
+/* "Navigate|N :SEP ::\n" */
+/* "Navigate|N > Clear Page History| :PUSH : :pagehistory-clear()\n" */
+ "Navigate|N :SEP ::\n"
+ "Navigate|N > Back Hyperlink|B :PUSH :B :htex-back()\n"
+ "Navigate|N > Forward Hyperlink|F :PUSH :F :htex-forward()\n"
+/* ========== */
+ "Zoom|Z > Shrink by 1|1 :RADIO :1 s :set-shrink-factor(1)\n"
+ "Zoom|Z > Shrink by 2|2 :RADIO :2 s :set-shrink-factor(2)\n"
+ "Zoom|Z > Shrink by 3|3 :RADIO :3 s :set-shrink-factor(3)\n"
+ "Zoom|Z > Shrink by 4|4 :RADIO :4 s :set-shrink-factor(4)\n"
+ "Zoom|Z > Shrink by 5|5 :RADIO :5 s :set-shrink-factor(5)\n"
+ "Zoom|Z > Shrink by 6|6 :RADIO :6 s :set-shrink-factor(6)\n"
+ "Zoom|Z > Shrink by 7|7 :RADIO :7 s :set-shrink-factor(7)\n"
+ "Zoom|Z > Shrink by 8|8 :RADIO :8 s :set-shrink-factor(8)\n"
+ "Zoom|Z > Shrink by 9|9 :RADIO :9 s :set-shrink-factor(9)\n"
+ "Zoom|Z :SEP ::\n"
+ "Zoom|Z > Fit in Window|F :PUSH :s :set-shrink-factor(a)\n"
+ "Zoom|Z :SEP ::\n"
+ "Zoom|Z > Zoom In|I :PUSH :Ctrl-+ :set-shrink-factor(+)\n"
+ "Zoom|Z > Zoom Out|O :PUSH :Ctrl-- :set-shrink-factor(-)\n"
+/* ========== */
+ "Mark|M > Mark All Pages|M :PUSH :-1 m :toggle-mark(-1)\n"
+ "Mark|M > Unmark All Pages|U :PUSH :0 m :toggle-mark(0)\n"
+ "Mark|M :SEP ::\n"
+ "Mark|M > Toggle Odd Pages|O :PUSH :1 m :toggle-mark(1)\n"
+ "Mark|M > Toggle Even Pages|E :PUSH :2 m :toggle-mark(2)\n"
+ "Mark|M > Toggle Current Page|C :PUSH :m :toggle-mark()\n"
+/* ========== */
+ "Options|O > Keep Position|K :CHECK :k :set-keep-flag(toggle)\n"
+ "Options|O > Use TeX Page Numbers|T :CHECK :T :use-tex-pages(toggle)\n"
+ "Options|O :SEP ::\n"
+/* removed this one, since it only duplicates the toolbar and is too awkward to use */
+/* "Options|O > Fonts|F > Fonts Darker|D :PUSH :Alt-Ctrl-+ :change-density(5)\n" */
+/* "Options|O > Fonts|F > Fonts Lighter|L :PUSH :Alt-Ctrl-- :change-density(-5)\n" */
+/* ---------- */
+#if 0
+/* TODO: implement setting paper size at runtime */
+ "Options|O > Paper|a > US|U :RADIO : :set-papersize(us)\n"
+ "Options|O > Paper|a > Legal|L :RADIO : :set-papersize(legal)\n"
+ "Options|O > Paper|a > Foolscap|F :RADIO : :set-papersize(foolscap)\n"
+ "Options|O > Paper|a > A1|1 :RADIO : :set-papersize(a1)\n"
+ "Options|O > Paper|a > A2|2 :RADIO : :set-papersize(a2)\n"
+ "Options|O > Paper|a > A3|3 :RADIO : :set-papersize(a3)\n"
+ "Options|O > Paper|a > A4|4 :RADIO : :set-papersize(a4)\n"
+ "Options|O > Paper|a > A5|5 :RADIO : :set-papersize(a5)\n"
+ "Options|O > Paper|a > A6|5 :RADIO : :set-papersize(a6)\n"
+ "Options|O > Paper|a > A7|7 :RADIO : :set-papersize(a7)\n"
+ /* Note: the b* and c* DIN sizes are too rarely used to be exposed here;
+ people can still customize the Menu if they really need them. */
+ "Options|O > Paper|a :SEP ::\n"
+ "Options|O > Paper|a > Landscape|L :CHECK : :set-paper-landscape(toggle)\n"
+#endif /* 0 */
+/* ---------- */
+# if PS
+ "Options|O > Postscript|o > Show PS|S :RADIO :1 v :set-ps(1)\n"
+ "Options|O > Postscript|o > Show PS and Bounding Boxes|B :RADIO :2 v :set-ps(2)\n"
+ "Options|O > Postscript|o > Show Bounding Boxes Only|O :RADIO :0 v :set-ps(0)\n"
+ "Options|O > Postscript|o :SEP ::\n"
+ "Options|O > Postscript|o > Use PS Anti-Aliasing|A :CHECK :V :set-gs-alpha(toggle)\n"
+# endif
+/* ---------- */
+/* removed, since it was redundant to Preferences */
+/* # ifdef MOTIF */
+/* "Options|O > Window Configuration|W > Show Statusline|S :CHECK :1x :set-expert-mode(1)\n" */
+/* "Options|O > Window Configuration|W > Show Scrollbars|c :CHECK :2x :set-expert-mode(2)\n" */
+/* "Options|O > Window Configuration|W > Show Pagelist|P :CHECK :3x :set-expert-mode(3)\n" */
+/* "Options|O > Window Configuration|W > Show Toolbar|T :CHECK :4x :set-expert-mode(4)\n" */
+/* # endif */
+/* ---------- */
+ "Options|O > Mouse Mode|M > Magnifier|M :RADIO :0 Ctrl-m :switch-mode(0)\n"
+ "Options|O > Mouse Mode|M > Text Selection|T :RADIO :1 Ctrl-m :switch-mode(1)\n"
+ "Options|O > Mouse Mode|M > Ruler|R :RADIO :2 Ctrl-m :switch-mode(2)\n"
+ "Options|O :SEP ::\n"
+ "Options|O > Preferences ...|P :PUSH : :prefs-dialog()\n"
+/* ========== */
+ "Help|H > Introduction ...|I :PUSH : :help(Introduction)\n"
+ "Help|H > Page Motion ...|P :PUSH : :help(Page Motion)\n"
+ "Help|H > Other Commands ...|O :PUSH : :help(Other Commands)\n"
+ "Help|H > Hyperlinks ...|H :PUSH : :help(Hyperlinks)\n"
+ "Help|H > Mouse Buttons ...|M :PUSH : :help(Mouse Buttons)\n"
+ "Help|H > Mouse Modes ...|d :PUSH : :help(Mouse Modes)\n"
+ "Help|H > String Search ...|e :PUSH : :help(String Search)\n"
+ "Help|H > Printing and Saving ...|S :PUSH : :help(Printing and Saving)\n"
+ "Help|H > Source Specials ...|r :PUSH : :help(Source Specials)\n"
+ "Help|H :SEP ::\n"
+ "Help|H > New Features in this Version|F:PUSH::load-url(http\\://xdvi.sourceforge.net/releases.html#" XDVI_VERSION ")\n"
+ "Help|H > Submit a Bug Report|B :PUSH ::load-url(http\\://sourceforge.net/tracker/?func=add&group_id=23164&atid=377580)\n"
+ "";
+#else /* NEW_MENU_CREATION */
+/* TODO:
+ - describe this in manpage
+ - use in the Motif version as well
+*/
+static const char default_menu_config[] =
+/* menu: submenu: accelerator: action */
+ "File: Open ...: Ctrl-o: select-dvi-file()\n"
+ "File: Open Recent: : recent-files()\n"
+ "File: Find ...: Ctrl-f: find()\n"
+ "File: Find next ...: Ctrl-g: find-next()\n"
+ "File: Reload: R: reread-dvi-file()\n"
+ "File: Save as ...: Ctrl-s: save()\n"
+ "File: Print ...: Ctrl-p: print()\n"
+ "File: Quit: q: quit()\n"
+ "Navigate: First: 1 g: goto-page(1)\n"
+ "Navigate: Page-10: 10 p: back-page(10)\n"
+ "Navigate: Page-5: 5 p: back-page(10)\n"
+ "Navigate: Prev: p: back-page(1)\n"
+ "Navigate: SEP\n"
+ "Navigate: Next: n: forward-page(1)\n"
+ "Navigate: Page+5: 5 n: forward-page(5)\n"
+ "Navigate: Page+10: 10 n: forward-page(10)\n"
+ "Navigate: Last: g: goto-page()\n"
+ "Navigate: SEP\n"
+ "Navigate: Back Hyperlink: B: htex-back()\n"
+ "Navigate: Forward Hyperlink: F: htex-forward()\n"
+ "Zoom: Zoom In: Ctrl-+: set-shrink-factor(+)\n"
+ "Zoom: Zoom Out: Ctrl--: set-shrink-factor(-)\n"
+ "Zoom: SEP\n"
+/* "Zoom:Full size (1 s):set-shrink-factor(1)\n" */
+ "Zoom: Fit in Window: s: set-shrink-factor(a)\n"
+ "Zoom: SEP\n"
+ "Zoom: $#: 1 s: set-shrink-factor(1)\n"
+ "Zoom: $#: 2 s: set-shrink-factor(2)\n"
+ "Zoom: $#: 3 s: set-shrink-factor(3)\n"
+ "Zoom: $#: 4 s: set-shrink-factor(4)\n"
+ "Zoom: $#: 5 s: set-shrink-factor(5)\n"
+ "Zoom: $#: 6 s: set-shrink-factor(6)\n"
+ "Zoom: $#: 7 s: set-shrink-factor(7)\n"
+ "Zoom: $#: 8 s: set-shrink-factor(8)\n"
+ "Zoom: $#: 9 s: set-shrink-factor(9)\n"
+/* "Zoom:$%%:shrink-to-dpi(150)\n" */
+/* "Zoom:$%%:shrink-to-dpi(100)\n" */
+/* "Zoom:$%%:shrink-to-dpi(50)\n" */
+ "Mark: Mark All Pages: -1 m: toggle-mark(-1)\n"
+ "Mark: Unmark All Pages: 0 m: toggle-mark(0)\n"
+ "Mark: SEP\n"
+ "Mark: Toggle Odd Pages: 1 m: toggle-mark(1)\n"
+ "Mark: Toggle Even Pages: 2 m: toggle-mark(2)\n"
+ "Mark: Toggle Current Page: m: toggle-mark()\n"
+ "Modes: Magnifier: Ctrl-m: switch-mode(0)\n"
+ "Modes: Text Selection: Ctrl-m: switch-mode(1)\n"
+ "Modes: Ruler: Ctrl-m: switch-mode(2)\n"
+# if PS
+ "Options: Show PS: 1 v: set-ps(1)\n"
+ "Options: Show PS and Bounding Boxes: 2 v: set-ps(2)\n"
+ "Options: Show Bounding Boxes Only: 0 v: set-ps(0)\n"
+ "Options: SEP\n"
+ "Options: Use PS Anti-Aliasing: V: set-gs-alpha(toggle)\n"
+# endif
+ "Options: SEP\n"
+/* "Options:Keep position:set-keep-flag(1)\n" */
+/* "Options:Don't keep position:set-keep-flag(0)\n" */
+ "Options: Keep Position: k: set-keep-flag(toggle)\n"
+ "Options: Use TeX Pages: T: use-tex-pages(toggle)\n"
+/* hmm, this probably is better kept in a `preferences' window: */
+/* "Options:SEP\n" */
+/* "Options:Show statusline:1 x:set-expert-mode(1)\n" */
+ "Options: SEP\n"
+ "Options: Fonts Darker: Alt-Ctrl-+: change-density(5)\n"
+ "Options: Fonts Lighter: Alt-Ctrl--: change-density(-5)\n"
+ "Help: Introduction ...: : help(Introduction)\n"
+ "Help: Page Motion ...: : help(Page Motion)\n"
+ "Help: Other Commands ...: : help(Other Commands)\n"
+ "Help: Hyperlinks ...: : help(Hyperlinks)\n"
+ "Help: Mouse Buttons ...: : help(Mouse Buttons)\n"
+ "Help: Mouse Modes ...: : help(Mouse Modes)\n"
+ "Help: String Search ...: : help(String Search)\n"
+ "Help: Printing and Saving ...:: help(Printing and Saving)\n"
+ "Help: Source Specials ...: : help(Source Specials)\n"
+ "Help:SEP\n"
+ "Help: New Features in this Version:: load-url(http\\://xdvi.sourceforge.net/releases.html#" XDVI_VERSION ")\n"
+ "Help: Send a Bug Report: : load-url(http\\://sourceforge.net/tracker/?func=add&group_id=23164&atid=377580)\n"
+ "";
+#endif /* NEW_MENU_CREATION */
+
+static const char default_toolbar_translations[] =
+/* index statusline-text tooltip action */
+ "SPACER(5)\n"
+ "0: Open a new file (Key\\: Ctrl-o): Open file: select-dvi-file()\n"
+ "SPACER(10)\n"
+ "1: Reload this file (Key\\: R): Reload file: reread-dvi-file()\n"
+ "SPACER(10)\n"
+ "2: Go to the first page of this file (Key\\: 1g): First page: goto-page(1)\n"
+ "3: Go to the previous page of this file (Key\\: p): Previous page: back-page(1)\n"
+ "4: Go to the next page of this file (Key\\: n): Next page: forward-page(1)\n"
+ "5: Go to the last page of this file (Key\\: g): Last page: goto-page(e)\n"
+ "SPACER(10)\n"
+ "8: Back to previous page in history (Key\\: [): Page History back: pagehistory-back()\n"
+ "9: Forward to next page in history (Key\\: ]): Page History forward: pagehistory-forward()\n"
+ "SPACER(10)\n"
+ "6: Zoom in (Key\\: Ctrl-+): Zoom in: set-shrink-factor(+)\n"
+ "7: Zoom out (Key\\: Ctrl--): Zoom out: set-shrink-factor(-)\n"
+ "SPACER(10)\n"
+ "11:Print this DVI file:Print:print()\n"
+ "SPACER(10)\n"
+ "16:Find in DVI file (Key\\: Ctrl-f): Find in file: find()\n"
+ "SPACER(10)\n"
+ "12:Toggle marks of odd pages (Key\\: 1m): Toggle odd pages: toggle-mark(1)\n"
+ "13:Toggle marks of even pages (Key\\: 2m): Toggle even pages: toggle-mark(2)\n"
+ "14:Toggle mark of current page (Key\\: 2m): Toggle current page: toggle-mark()\n"
+ "15:Unmark all pages (Key\\: 0m): Unmark all pages: toggle-mark(0)\n"
+ "SPACER(10)\n"
+ "19:Display fonts darker (Key\\: Alt-Ctrl-+): Fonts darker: change-density(5)\n"
+ "20:Display fonts lighter (Key\\: Alt-Ctrl--): Fonts lighter: change-density(-5)\n"
+ "";
diff --git a/Build/source/texk/xdvik/util.c b/Build/source/texk/xdvik/util.c
new file mode 100644
index 00000000000..d34ef137387
--- /dev/null
+++ b/Build/source/texk/xdvik/util.c
@@ -0,0 +1,1839 @@
+/*========================================================================*\
+
+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
+ in xdvi.c.
+
+\*========================================================================*/
+
+#include "xdvi-config.h"
+
+#include <sys/types.h> /* ZLB: must be before sys/socket.h for IRIX 5.3 */
+#include <sys/socket.h>
+#include <sys/file.h> /* this defines FASYNC */
+#include <sys/ioctl.h> /* this defines SIOCSPGRP and FIOASYNC */
+#include <sys/wait.h> /* this defines WIFEXITED and WEXITSTATUS */
+
+#include "xdvi.h"
+#include "hypertex.h"
+#include "dvi-init.h"
+#include "special.h"
+#include "string-utils.h"
+
+#include "kpathsea/tex-file.h"
+
+#include "events.h"
+#include "util.h"
+#include "x_util.h"
+#include "message-window.h"
+#include "search-internal.h"
+#include "encodings.h"
+#include "filehist.h"
+#include "xm_prefs.h" /* for preferences_changed() */
+
+#include <errno.h>
+
+#ifndef HAVE_MEMICMP
+#include <ctype.h>
+#endif
+
+#ifdef VMS
+#include <rmsdef.h>
+#endif /* VMS */
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+extern void *malloc();
+extern void *realloc();
+#endif
+
+
+#ifdef DOPRNT /* define this if vfprintf gives you trouble */
+#define vfprintf(stream, message, args) _doprnt(message, args, stream)
+#endif
+
+#ifdef VMS
+#include <rmsdef.h>
+#endif /* VMS */
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+extern void *malloc();
+extern void *realloc();
+#endif
+
+
+/* if POSIX O_NONBLOCK is not available, use O_NDELAY */
+#if !defined O_NONBLOCK && defined O_NDELAY
+# define O_NONBLOCK O_NDELAY
+#endif
+
+/* Linux prefers O_ASYNC over FASYNC; SGI IRIX does the opposite. */
+#if !defined(FASYNC) && defined(O_ASYNC)
+# define FASYNC O_ASYNC
+#endif
+
+#if !defined(FLAKY_SIGPOLL) && !HAVE_STREAMS && !defined(FASYNC)
+# if !defined(SIOCSPGRP) || !defined(FIOASYNC)
+# define FLAKY_SIGPOLL 1
+# endif
+#endif
+
+#if !FLAKY_SIGPOLL && HAVE_STREAMS
+# include <stropts.h>
+
+# ifndef S_RDNORM
+# define S_RDNORM S_INPUT
+# endif
+
+# ifndef S_RDBAND
+# define S_RDBAND 0
+# endif
+
+# ifndef S_HANGUP
+# define S_HANGUP 0
+# endif
+
+# ifndef S_WRNORM
+# define S_WRNORM S_OUTPUT
+# endif
+
+#endif /* not FLAKY_SIGPOLL && HAVE_STREAMS */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <errno.h>
+
+#ifndef MAXSYMLINKS /* Workaround for Linux libc 4.x/5.x */
+#define MAXSYMLINKS 5
+#endif
+
+#if HAVE_ICONV_H
+#include <iconv.h>
+#endif
+
+#include <locale.h>
+
+#if USE_LANGINFO
+#include <langinfo.h>
+#endif
+
+#define BUF_SIZE 1024
+
+/*
+ Insert item to the list and return the result.
+*/
+struct dl_list *
+dl_list_insert(struct dl_list *list, void *item)
+{
+ struct dl_list *new_elem = xmalloc(sizeof *new_elem);
+ new_elem->item = item;
+ new_elem->next = NULL;
+ new_elem->prev = NULL;
+
+ if (list == NULL) {
+ list = new_elem;
+ }
+ else {
+ /* append after current position */
+ struct dl_list *ptr = list;
+
+ new_elem->next = ptr->next;
+ new_elem->prev = ptr;
+
+ if (ptr->next != NULL)
+ ptr->next->prev = new_elem;
+
+ ptr->next = new_elem;
+ }
+ return new_elem;
+}
+
+/*
+ Return head of the list.
+*/
+struct dl_list *
+dl_list_head(struct dl_list *list)
+{
+ for (; list != NULL && list->prev != NULL; list = list->prev) { ; }
+ return list;
+}
+
+/*
+ Put a new item at the front of the list (current front is passed in first argument)
+ and return its position.
+*/
+struct dl_list *
+dl_list_push_front(struct dl_list *list, void *item)
+{
+ struct dl_list *new_elem = xmalloc(sizeof *new_elem);
+ new_elem->item = item;
+ new_elem->next = NULL;
+ new_elem->prev = NULL;
+
+ if (list != NULL) { /* prepend to current position */
+ new_elem->next = list;
+ list->prev = new_elem;
+ }
+ return new_elem;
+}
+
+/*
+ Truncate list so that current pointer is the last element.
+*/
+struct dl_list *
+dl_list_truncate(struct dl_list *list)
+{
+ struct dl_list *ptr = list->next;
+ struct dl_list *save;
+
+ list->next = NULL;
+
+ while (ptr != NULL) {
+ save = ptr->next;
+ free(ptr);
+ ptr = save;
+ }
+ return list;
+}
+
+/*
+ Truncate list at the head (i.e. remove the first element from it - head must be passed to this list),
+ and return the result.
+*/
+struct dl_list *
+dl_list_truncate_head(struct dl_list *list)
+{
+ struct dl_list *ptr = list->next;
+ if (list->next != NULL)
+ list->next->prev = NULL;
+ free(list);
+ return ptr;
+}
+
+/*
+ If the item pointed to by *list isn't the head of the list, remove it,
+ set *list to the previous item, and return True. Else return False.
+*/
+Boolean
+dl_list_remove_item(struct dl_list **list)
+{
+ struct dl_list *ptr = *list; /* item to remove */
+ if (ptr->prev == NULL)
+ return False;
+ ptr->prev->next = ptr->next;
+ if (ptr->next != NULL)
+ ptr->next->prev = ptr->prev;
+ /* update list */
+ *list = (*list)->prev;
+ /* remove item */
+ free(ptr);
+
+ return True;
+}
+
+/*
+ Remove all items matching compare_func() from list. Must be called
+ with a pointer to the head of the list, which is also returned.
+ Returns the number of removed items in `count'.
+*/
+struct dl_list *
+dl_list_remove(struct dl_list *list, const void *item,
+ int *count,
+ void **removed_item,
+ Boolean (*compare_func)(const void *item1, const void *item2))
+{
+ struct dl_list *ptr = list;
+ while (ptr != NULL) {
+ struct dl_list *next = ptr->next;
+ if (compare_func(ptr->item, item)) { /* match */
+ *removed_item = ptr->item;
+ (*count)++;
+ if (ptr->prev != NULL) {
+ ptr->prev->next = ptr->next;
+ }
+ else { /* removed first element */
+ list = list->next;
+ }
+
+ if (ptr->next != NULL)
+ ptr->next->prev = ptr->prev;
+ free(ptr);
+ ptr = NULL;
+ }
+ ptr = next;
+ }
+ return list;
+}
+
+
+/* NOTE: keep this table in sync with the #defines in xdvi-debug.h! */
+struct debug_string_options debug_options[] = {
+ { DBG_BITMAP, "bitmap", ", " },
+ { DBG_DVI, "dvi", ", " },
+ { DBG_PK, "pk", ", " },
+ { DBG_BATCH, "batch", ", " },
+ { DBG_EVENT, "event", ", " },
+ { DBG_PS, "ps", ",\n"},
+ { DBG_STAT, "stat", ", " },
+ { DBG_HASH, "hash", ", " },
+ { DBG_OPEN, "open", ", " },
+ { DBG_PATHS, "paths", ", " },
+ { DBG_EXPAND, "expand", ", " },
+ { DBG_SEARCH, "search", ", " },
+ { DBG_KPATHSEA, "kpathsea", ",\n"},
+ { DBG_HTEX, "htex", ", " },
+ { DBG_SRC_SPECIALS,"src", ", " },
+ { DBG_CLIENT, "client", ", " },
+ { DBG_T1, "t1", ", " },
+ { DBG_T1_VERBOSE, "t1_verbose", ",\n"},
+ { DBG_GUI, "gui", ", " },
+ { DBG_FIND, "find", ", " },
+ { DBG_FILES, "files", ", " },
+ { DBG_ALL, "all", "\n" },
+ /* end marker */
+ { 0, NULL, NULL }
+};
+
+/*
+ * General utility routines.
+ */
+
+/*
+ * 2-step fopen using close_a_file() if first opening attempt fails with
+ * `too many open files'.
+ */
+FILE *
+try_fopen(const char *fname, const char *mode)
+{
+ FILE *fp = fopen(fname, mode);
+ if (fp == NULL && (errno == EMFILE || errno == ENFILE)) {
+ close_a_file();
+ fp = fopen(fname, mode);
+ }
+ return fp;
+}
+
+/*
+ * Like try_fopen(), for fdopen().
+ */
+FILE *
+try_fdopen(int fd, const char *mode)
+{
+ FILE *fp = fdopen(fd, mode);
+ if (fp == NULL && (errno == EMFILE || errno == ENFILE)) {
+ close_a_file();
+ fp = fdopen(fd, mode);
+ }
+ return fp;
+}
+
+
+/*
+ * Like try_fopen(), for open().
+ */
+int
+try_open(const char *fname, int flags)
+{
+ int fd = open(fname, flags);
+ if (fd < 0 && (errno == EMFILE || errno == ENFILE)) {
+ close_a_file();
+ fd = open(fname, flags);
+ }
+ return fd;
+}
+
+/*
+ * Like try_fopen(), for open() with 3 arguments.
+ */
+int
+try_open_mode(const char *fname, int flags, mode_t mode)
+{
+ int fd = open(fname, flags, mode);
+ if (fd < 0 && (errno == EMFILE || errno == ENFILE)) {
+ close_a_file();
+ fd = open(fname, flags);
+ }
+ return fd;
+}
+
+
+/*
+ * This routine should be used for all exits. (SU: This is different
+ * from non-k xdvi, where it's only used for `non-early' exits; all
+ * routines called here should be aware of their own state and either
+ * perform cleanup or just return, unless xdvi_exit() itself checks for
+ * the status).
+ */
+
+void
+xdvi_exit(int status)
+{
+ /* do the following only if the window has been opened: */
+ if (globals.widgets.top_level != 0 && XtIsRealized(globals.widgets.top_level)) {
+ char *filehist;
+ file_history_set_page(current_page);
+ filehist = file_history_get_list();
+ store_preference(NULL, "fileHistory", "%s", filehist);
+ free(filehist);
+
+#if MOTIF
+ if (preferences_changed()) {
+ return;
+ }
+/* else { */
+/* fprintf(stderr, "Preferences not changed.\n"); */
+/* } */
+#endif
+ /* try to save user preferences, unless we're exiting with an error */
+ if (status == 0 && !save_user_preferences(True))
+ return;
+
+ /* Clean up the "xdvi windows" property in the root window. */
+ update_window_property(XtWindow(globals.widgets.top_level), False);
+ }
+
+#if PS
+ ps_destroy();
+#endif
+ remove_tmp_dvi_file();
+
+ close_iconv();
+
+ exit(status);
+}
+
+/*
+ * invoked on SIGSEGV: try to stop gs before aborting, to prevent gs
+ * running on with 100% CPU consumption - this can be annoying during
+ * testing. We'd also like to clean up the "xdvi windows" property in
+ * the root window, but it might be already too late to talk to the
+ * X server here (the code can also be triggered by X errors).
+ */
+void
+do_abort()
+{
+#if PS
+ ps_destroy();
+#endif
+ /* if (globals.widgets.top_level) */
+ /* exit_clean_windows(); */
+ abort();
+}
+
+/*
+ Expand leading ~ or ~user in path to the actual homedirectory of the user.
+ Returns either NULL if unsuccessful, or result in freshly allocated string.
+ Bugs: ~user doesn't work with NIS/yellow pages.
+*/
+char *
+expand_homedir(const char *path)
+{
+ char *resolved = NULL;
+ const char *orig_path = path;
+ UNUSED(orig_path); /* if HAVE_GETPWNAM or HAVE_GETPWUID && HAVE_GETUID */
+
+ if (path == NULL)
+ return NULL;
+
+ /* if path doesn't start with ~, just return a copy of path */
+ if (*path != '~')
+ return xstrdup(path);
+
+ /* expand ~/ or ~user */
+ path++;
+ if (*path == '/') { /* expand `~/' to `$HOME/' */
+ char *homedir = getenv("HOME");
+ if (homedir != NULL) {
+ resolved = xstrdup(homedir);
+ resolved = xstrcat(resolved, path);
+ }
+ else {
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
+ /* homedir not set */
+ struct passwd *entry = getpwuid(getuid());
+ if (entry != NULL) {
+ homedir = entry->pw_dir;
+ if (homedir != NULL) {
+ resolved = xstrdup(homedir);
+ resolved = xstrcat(resolved, path);
+ }
+ else {
+ XDVI_ERROR((stderr, "getpwnam returned NULL for entry->pw_dir: %s", strerror(errno)));
+ return NULL;
+ }
+ }
+ else {
+ XDVI_ERROR((stderr, "getpwnam failed: %s", strerror(errno)));
+ return NULL;
+ }
+#else
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ "$HOME not set, and getpwuid() or getuid() not supported - could not expand \"%s\".",
+ orig_path);
+ return NULL;
+#endif
+ }
+ TRACE_GUI((stderr, "resolved: |%s|", resolved));
+ return resolved;
+ }
+ else { /* ~user -> try getpwnam() to get homedir */
+#ifdef HAVE_GETPWNAM
+ struct passwd *entry;
+ char *separator = strchr(path, '/');
+ char *homedir;
+
+ TRACE_GUI((stderr, "separator is: |%s|, len of username: %d",
+ separator, (int)(separator - path)));
+ if (separator == NULL)
+ return NULL;
+
+ resolved = xmalloc(separator - path + 1);
+ memcpy(resolved, path, separator - path);
+ resolved[separator - path] = '\0';
+
+ TRACE_GUI((stderr, "username is: |%s|", resolved));
+ entry = getpwnam(resolved);
+ if (entry == NULL) {
+ XDVI_ERROR((stderr, "getpwnam failed: %s", strerror(errno)));
+ return NULL;
+ }
+ TRACE_GUI((stderr, "homedir of user is: |%s|", entry->pw_dir));
+ homedir = entry->pw_dir;
+
+ free(resolved);
+ resolved = xstrdup(homedir);
+ resolved = xstrcat(resolved, path + (separator - path));
+ TRACE_GUI((stderr, "resolved: |%s|", resolved));
+ return resolved;
+#else
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ "Expanding \"%s\" failed: This platform doesn't support getpwnam().",
+ orig_path);
+ return NULL;
+#endif
+ }
+
+}
+
+/*
+ realpath implementation if no implementation available.
+ Try to canonicalize path, removing `~', `.' and `..' and expanding symlinks.
+
+ Adopted from wu-ftpd's fb_realpath (in realpath.c), but without the
+ seteuid(0) stuff (which we don't need, since we never change into
+ directories or read files the user has no permissions for), and
+ without the ugly goto(). Special care has been taken to avoid buffer
+ overflows (e.g. this version is not affected by
+ http://isec.pl/vulnerabilities/isec-0011-wu-ftpd.txt).
+
+ `resolved' should be a buffer of size MAXPATHLEN. */
+
+char *
+my_realpath(const char *path, char *resolved)
+{
+ struct stat sb;
+ int n;
+ /* char *p, *q, *tmp; */
+ char *base;
+ char tmpbuf[MAXPATHLEN];
+ int symlinks = 0;
+#ifdef HAVE_FCHDIR
+ int fd;
+#else
+ char cwd[MAXPATHLEN];
+#endif
+
+ /* Save cwd for going back later */
+#ifdef HAVE_FCHDIR
+ if ((fd = try_open(".", O_RDONLY)) < 0)
+ return NULL;
+#else /* HAVE_FCHDIR */
+ if (
+# ifdef HAVE_GETCWD
+ getcwd(cwd, MAXPATHLEN)
+# else
+ getwd(cwd)
+# endif
+ == NULL)
+ return NULL;
+#endif /* HAVE_FCHDIR */
+
+ if (strlen(path) + 1 > MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ strcpy(resolved, path);
+
+ for (;;) { /* loop for resolving symlinks in base name */
+ /* get base name and dir name components */
+ char *p = strrchr(resolved, '/');
+ if (p != NULL) {
+ base = p + 1;
+ if (p == resolved) {
+ /* resolved is in root dir; this must be treated as a special case,
+ since we can't chop off at `/'; instead, just use the `/':
+ */
+ p = "/";
+ }
+ else {
+ /* not in root dir; chop off path name at slash */
+ while (p > resolved && *p == '/') /* for multiple trailing slashes */
+ p--;
+ *(p + 1) = '\0';
+ p = resolved;
+ }
+
+ /* change into that dir */
+ if (chdir(p) != 0)
+ break;
+ }
+ else /* no directory component */
+ base = resolved;
+
+ /* resolve symlinks or directory names (not used in our case) in basename */
+ if (*base != '\0') {
+ if (
+#ifdef HAVE_LSTAT
+ lstat(base, &sb)
+#else
+ stat(base, &sb)
+#endif
+ == 0) {
+#ifdef HAVE_LSTAT
+ if (S_ISLNK(sb.st_mode)) { /* if it's a symlink, iterate for what it links to */
+ if (++symlinks > MAXSYMLINKS) {
+ errno = ELOOP;
+ break;
+ }
+
+ if ((n = readlink(base, resolved, MAXPATHLEN)) < 0)
+ break;
+
+ resolved[n] = '\0';
+ continue;
+ }
+#endif /* HAVE_LSTAT */
+ if (S_ISDIR(sb.st_mode)) { /* if it's a directory, go there */
+ if (chdir(base) != 0)
+ break;
+
+ base = "";
+ }
+ }
+ }
+
+ /* Now get full pathname of current directory and concatenate it with saved copy of base name */
+ strcpy(tmpbuf, base); /* cannot overrun, since strlen(base) <= strlen(path) < MAXPATHLEN */
+ if (
+#ifdef HAVE_GETCWD
+ getcwd(resolved, MAXPATHLEN)
+#else
+ getwd(resolved)
+#endif
+ == NULL)
+ break;
+
+ /* need to append a slash if resolved is not the root dir */
+ if (!(resolved[0] == '/' && resolved[1] == '\0')) {
+ if (strlen(resolved) + 2 > MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ break;
+ }
+ strcat(resolved, "/");
+ }
+
+ if (*tmpbuf) {
+ if (strlen(resolved) + strlen(tmpbuf) + 1 > MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ break;
+ }
+ strcat(resolved, tmpbuf);
+ }
+
+ /* go back to where we came from */
+#ifdef HAVE_FCHDIR
+ fchdir(fd);
+ close(fd);
+#else
+ chdir(cwd);
+#endif
+ return resolved;
+ }
+
+ /* arrive here in case of error: go back to where we came from, and return NULL */
+#ifdef HAVE_FCHDIR
+ fchdir(fd);
+ close(fd);
+#else
+ chdir(cwd);
+#endif
+ return NULL;
+}
+
+
+#ifndef KPATHSEA
+
+/*
+ * Either (re)allocate storage or fail with explanation.
+ */
+
+void *
+xmalloc(unsigned size)
+{
+ void *mem = malloc(size);
+
+ if (mem == NULL)
+ XDVI_FATAL((stderr, "Out of memory (allocating %u bytes).", size));
+ return mem;
+}
+
+void *
+xrealloc(void *where, unsigned size)
+{
+ void *mem = realloc(where, size);
+
+ if (mem == NULL)
+ XDVI_FATAL((stderr, "Out of memory (reallocating %u bytes).", size));
+ return mem;
+}
+
+
+/*
+ * Allocate a new string.
+ */
+
+char *
+xstrdup(const char *str)
+{
+ size_t len;
+ char *new;
+
+ ASSERT(fprintf(stderr, "Test assertion!\n") && 1 == 0);
+ ASSERT(str != NULL, "");
+ len = strlen(str) + 1;
+ new = xmalloc(len);
+ memcpy(new, str, len);
+ return new;
+}
+
+
+
+/*
+ * Allocate a new string. The second argument is the length.
+ */
+
+char *
+xmemdup(const char *str, size_t len)
+{
+ char *new;
+
+ new = xmalloc(len);
+ memcpy(new, str, len);
+ return new;
+}
+
+#endif /* not KPATHSEA */
+
+
+/*
+ * Append str2 to str1, reallocating str1 as neccessary.
+ * Note that this modifies str1, so if you want a clean
+ * new copy, use xstrdup() first, then xstrcat().
+ * str1 should be either NULL, or a valid char * that has
+ * previously been malloc()ed.
+ */
+
+char *
+xstrcat(char *str1, const char *str2)
+{
+ size_t len1 = (str1 == NULL) ? 0 : strlen(str1);
+ size_t len2 = strlen(str2) + 1;
+
+ str1 = xrealloc(str1, len1 + len2);
+ memcpy(str1 + len1, str2, len2);
+ return str1;
+}
+
+
+/*
+ * Allocate bitmap for given font and character
+ */
+
+void
+alloc_bitmap(struct bitmap *bitmap)
+{
+ unsigned int size;
+
+ /* fprintf(stderr, "allocating bitmap of size %u x %u\n", bitmap->w, bitmap->h); */
+ /* width must be multiple of <arch-defined> bits for raster_op */
+ bitmap->bytes_wide = ROUNDUP((int)bitmap->w, BMBITS) * BMBYTES;
+ size = bitmap->bytes_wide * bitmap->h;
+ bitmap->bits = xmalloc(size != 0 ? size : 1);
+}
+
+
+#ifndef HAVE_MEMICMP
+/*
+ * Case-insensitive version of memcmp(). This code assumes that the second
+ * argument (i.e. what is being compared with) is lower case.
+ */
+
+int
+memicmp(const char *s1, const char *s2, size_t n)
+{
+ while (n > 0) {
+ int i = tolower((int)*s1) - *s2;
+ if (i != 0)
+ return i;
+ ++s1;
+ ++s2;
+ --n;
+ }
+ return 0;
+}
+#endif /* HAVE_MEMICMP */
+
+/*
+ * Try to close the pixel file for the least recently used font.
+ * Invoked when we've run out of file descriptors.
+ */
+void
+close_a_file(void)
+{
+ struct font *fontp;
+ unsigned short oldest = USHRT_MAX;
+ struct font *f = NULL;
+
+ if (globals.debug & DBG_OPEN)
+ puts("Calling close_a_file().");
+
+ for (fontp = font_head; fontp != NULL; fontp = fontp->next) {
+ if (fontp->file != NULL && fontp->timestamp <= oldest) {
+ f = fontp;
+ oldest = fontp->timestamp;
+ }
+ }
+ /* fprintf(stderr, "oldest = %u\n", oldest); */
+ if (f == NULL)
+ XDVI_FATAL((stderr, "Can't find an open pixel file to close"));
+ fclose(f->file);
+ f->file = NULL;
+}
+
+/*
+ * Open a file in the given mode. We use XFOPEN since xfopen is already
+ * usurpated by kpathsea's xfopen.c, which just exits rather ungracefully
+ * if it detects a NULL return value; most certainly NOT what we want here.
+ */
+FILE *
+XFOPEN(const char *path, const char *mode)
+{
+ FILE *fp = NULL;
+#ifdef TESTING_OPEN_FILES
+ fprintf(stderr, "trying to open |%s|\n", path);
+#endif
+ if ((fp = try_fopen(path, mode)) == NULL && (errno == EMFILE || errno == ENFILE)) {
+ XDVI_FATAL((stderr, "too many open files"));
+ }
+ return fp;
+}
+
+/*
+ * Create a pipe, closing a file if necessary.
+ * We use socketpair() instead of pipe() because several operating
+ * systems don't support SIGPOLL/SIGIO on pipes:
+ * SGI IRIX 6.5 F_SETOWN not implemented
+ * Linux 2.4.2 Not supported
+ */
+
+int
+xpipe(int *fd)
+{
+ int retval;
+
+ for (;;) {
+ retval = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
+ if (retval == 0) { /* success */
+ break;
+ }
+ if ((errno != EMFILE && errno != ENFILE)) {
+ /* failed, but not because of too many files */
+ break;
+ }
+ close_a_file();
+ }
+ return retval;
+}
+
+
+
+/*
+ *
+ * Read size bytes from the FILE fp, constructing them into a
+ * signed/unsigned integer.
+ *
+ */
+
+unsigned long
+get_bytes(FILE *fp, int size)
+{
+ long x = 0;
+
+ while (size--)
+ x = (x << 8) | get_byte(fp);
+ return x;
+}
+
+long
+get_lbytes(FILE *fp, int size)
+{
+ long x;
+
+#if __STDC__
+ x = (signed char)getc(fp);
+#else
+ x = (unsigned char)getc(fp);
+ if (x & 0x80)
+ x -= 0x100;
+#endif
+ while (--size)
+ x = (x << 8) | get_byte(fp);
+ return x;
+}
+
+
+
+/*
+ * Create a temporary file and return its fd. Also put its filename
+ * in str. Create str if it's NULL.
+ */
+
+#ifndef P_tmpdir
+#define P_tmpdir "/tmp"
+#endif
+
+static const char tmp_suffix[] = "/xdvi-XXXXXX";
+
+int
+xdvi_temp_fd(char **str)
+{
+ int fd;
+ char *p;
+ size_t len;
+ static const char *template = NULL;
+#if !HAVE_MKSTEMP
+ static unsigned long seed;
+ static char letters[] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._";
+ char *p1;
+#endif
+
+ if (*str != NULL) {
+ p = *str;
+
+ /* O_EXCL is there for security (if root runs xdvi) */
+ if (!((fd = try_open_mode(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1
+ && errno == EEXIST))
+ return fd;
+#if HAVE_MKSTEMP
+ memcpy(p + strlen(p) - 6, "XXXXXX", 6);
+#endif
+ }
+ else {
+ if (template == NULL) {
+ const char *ourdir;
+
+ ourdir = getenv("TMPDIR");
+ if (ourdir == NULL || access(ourdir, W_OK) < 0) {
+ ourdir = P_tmpdir;
+ if (access(ourdir, W_OK) < 0)
+ ourdir = ".";
+ }
+ len = strlen(ourdir);
+ if (len > 0 && ourdir[len - 1] == '/')
+ --len;
+ template = p = xmalloc(len + sizeof tmp_suffix);
+ memcpy(p, ourdir, len);
+ memcpy(p + len, tmp_suffix, sizeof tmp_suffix);
+#if !HAVE_MKSTEMP
+ seed = 123456789 * time(NULL) + 987654321 * getpid();
+#endif
+ }
+ *str = p = xstrdup(template);
+ }
+
+#if HAVE_MKSTEMP
+ fd = mkstemp(p);
+ if (fd == -1 && (errno == EMFILE || errno == ENFILE)) {
+ close_a_file();
+ memcpy(p + strlen(p) - 6, "XXXXXX", 6);
+ fd = mkstemp(p);
+ }
+#else
+ p1 = p + strlen(p) - 6;
+ for (;;) {
+ unsigned long s = ++seed;
+ char *p2;
+
+ for (p2 = p1 + 5; p2 >= p1; --p2) {
+ *p2 = letters[s & 63];
+ s >>= 6;
+ }
+ if (!((fd = try_open_mode(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1
+ && errno == EEXIST))
+ break;
+ }
+#endif
+ return fd;
+}
+
+
+/* print a GUI error message for childs that exited with an errorcode */
+void
+handle_child_exit(int status, struct xchild *this)
+{
+ char *err_msg = NULL;
+
+ /* if child exited with error and xio struct is available for child,
+ print error text */
+ if (this->io != NULL
+ && (WIFEXITED(status) != 0)
+ && (WEXITSTATUS(status) != 0)
+ && (err_msg = (this->io->read_proc)(this->io->fd)) != NULL) {
+
+ if (this->name == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ NULL,
+ err_msg[0] == '\0' ? "An unknown error occurred" : err_msg);
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ "Xdvi tries to collect all messages from STDERR. "
+ "When no useful error message is available "
+ "(e.g. because the program has written to STDOUT instead), "
+ "try to run the command again from the command line "
+ "to find out what the problem was.",
+ "Command \"%s\" exited with error code %d\n%s\n",
+ this->name, WEXITSTATUS(status), err_msg);
+ }
+ free(err_msg);
+ }
+ free(this->name);
+ free(this->io);
+ free(this);
+}
+
+static void
+dummy_write_proc(int fd)
+{
+ UNUSED(fd);
+ fprintf(stderr, "============== dummy_write_proc called for fd %d\n", fd);
+}
+
+/*
+ * read what child printed to fd (should be set up to be stderr).
+ * Allocates and returns error text; caller is responsible for free()ing it
+ * afterwards.
+ */
+char *
+read_child_error(int fd)
+{
+ int bytes = 0, buf_old_size = 0, buf_new_size = 0;
+ char tmp_buf[BUF_SIZE];
+ char *err_buf = xstrdup("");
+ char *ret;
+ /* collect stderr messages into err_buf */
+ while ((bytes = read(fd, tmp_buf, BUF_SIZE - 1)) > 0) {
+ buf_old_size = buf_new_size;
+ buf_new_size += bytes;
+ err_buf = xrealloc(err_buf, buf_new_size + 1);
+ memcpy(err_buf + buf_old_size, tmp_buf, buf_new_size - buf_old_size);
+ err_buf[buf_new_size] = '\0';
+ }
+
+ close(fd);
+ ret = escape_format_arg(err_buf); /* this allocates ret */
+ free(err_buf);
+ return ret;
+}
+
+/*
+ * Fork a child process. If exit_proc is NULL, the process' error messages
+ * will be collected and a window popped up for GUI display. If exit_proc
+ * is non-NULL, it should be a function that does something reasonable
+ * with the error messages itself. It should also free the xchild struct.
+ *
+ * If dirname != NULL, the child will chdir into dirname before running the
+ * command.
+ */
+Boolean
+fork_process(const char *proc_name, Boolean redirect_stdout,
+ const char *dirname,
+ childProcT exit_proc, void *data,
+ char *const argv[])
+{
+ int i, pid;
+ struct xchild *my_child = xmalloc(sizeof *my_child);
+ struct xio *my_io = xmalloc(sizeof *my_io);
+ int err_pipe[2];
+ char *volatile buf = xstrdup("");
+
+ for (i = 0; argv[i] != NULL; i++) {
+ TRACE_GUI((stderr, "argv: |%s|", argv[i]));
+ buf = xstrcat(buf, argv[i]);
+ buf = xstrcat(buf, " ");
+ }
+
+ if (i > 0)
+ buf[strlen(buf) - 1] = '\0'; /* chop off trailing space */
+
+ TRACE_GUI((stderr, "forking: |%s|", buf));
+
+ /* 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);
+
+ if (pipe(err_pipe) < 0) {
+ XDVI_FATAL((stderr, "pipe error"));
+ }
+
+ switch (pid = vfork()) {
+ case -1: /* forking error */
+ perror("vfork");
+ close(err_pipe[0]);
+ close(err_pipe[1]);
+ return False;
+ case 0: /* child */
+ if (dirname != NULL)
+ chdir(dirname);
+ if (globals.debug & DBG_FILES) {
+ char path[MAXPATHLEN];
+ getcwd(path, MAXPATHLEN);
+ fprintf(stderr, "Directory of running `%s': `%s'\n",
+ proc_name, path);
+ }
+ /* FIXME: There's a bug which prevents this from working
+ with xdvi as child: Whenever xdvi tries to print to stderr,
+ this will hang the child forever. Closing all other file
+ descriptors, as in the #if TRY_FIX regions, seems to fix
+ this, but it also loses all output ...
+ */
+#if TRY_FIX
+ close(0);
+ close(1);
+#endif /* TRY_FIX */
+ close(err_pipe[0]); /* no reading from stderr */
+
+ /* redirect writing to stderr */
+ if (dup2(err_pipe[1], STDERR_FILENO) != STDERR_FILENO) {
+ perror("dup2 for stderr");
+ _exit(EXIT_FAILURE);
+ return False; /* make compiler happy */
+ }
+ if (redirect_stdout) {
+ /* also redirect writing to stdout */
+ if (dup2(err_pipe[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ perror("dup2 for stdout");
+ _exit(EXIT_FAILURE);
+ return False; /* make compiler happy */
+ }
+ }
+
+#if TRY_FIX
+ /* close all remaining descriptors */
+ i = 2;
+ while (i < 256 /* TODO: better handling of OPEN_MAX; see Stevens p. 43 */) {
+ close(i++);
+ }
+#endif /* TRY_FIX */
+ execvp(proc_name, argv);
+
+ /* arrive here only if execvp failed */
+ fprintf(stderr, "%s: Execution of %s failed.\n", globals.program_name, proc_name);
+ fflush(stderr);
+ close(err_pipe[1]);
+ _exit(EXIT_FAILURE);
+ return False; /* make compiler happy */
+ default: /* parent */
+ close(err_pipe[1]); /* no writing to stderr */
+
+ my_io->next = NULL;
+ my_io->fd = err_pipe[0];
+ my_io->xio_events = XIO_IN;
+#if HAVE_POLL
+ my_io->pfd = NULL;
+#endif
+ my_io->read_proc = read_child_error;
+ my_io->write_proc = dummy_write_proc;
+
+ my_child->next = NULL;
+ my_child->pid = pid;
+ my_child->name = buf;
+ my_child->data = data;
+ if (exit_proc == NULL) { /* use default exit procedure */
+ my_child->proc = handle_child_exit;
+ }
+ else {
+ my_child->proc = exit_proc;
+ }
+ my_child->io = my_io;
+
+ set_chld(my_child);
+
+ return True;
+ }
+}
+
+
+
+/*
+ * Prepare the file descriptor to generate SIGPOLL/SIGIO events.
+ * If called with a True argument, set it up for non-blocking I/O.
+ */
+
+void
+prep_fd(int fd, wide_bool noblock)
+{
+ /* Set file descriptor for non-blocking I/O */
+ if (noblock)
+ (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+#if !FLAKY_SIGPOLL
+# if HAVE_STREAMS
+ if (isastream(fd) > 0) {
+ if (ioctl(fd, I_SETSIG,
+ S_RDNORM | S_RDBAND | S_HANGUP | S_WRNORM) == -1)
+ perror("xdvi: ioctl I_SETSIG");
+ }
+ else
+# endif
+ {
+# ifdef FASYNC
+ if (fcntl(fd, F_SETOWN, getpid()) == -1)
+ perror("xdvi: fcntl F_SETOWN");
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | FASYNC) == -1)
+ perror("xdvi: fcntl F_SETFL");
+# elif defined SIOCSPGRP && defined FIOASYNC
+ /* For HP-UX B.10.10 and maybe others. See "man 7 socket". */
+ int arg;
+
+ arg = getpid();
+ if (ioctl(fd, SIOCSPGRP, &arg) == -1)
+ perror("xdvi: ioctl SIOCSPGRP");
+ arg = 1;
+ if (ioctl(fd, FIOASYNC, &arg) == -1)
+ perror("xdvi: ioctl FIOASYNC");
+# endif
+ }
+#endif /* not FLAKY_SIGPOLL */
+}
+
+
+/* APS Pointer locator: */
+/* Return screen positions */
+Boolean
+pointerlocate(int *xpos, int *ypos)
+{
+ Window root, child;
+ int root_x, root_y;
+ unsigned int keys_buttons;
+
+ if (!XtIsRealized(globals.widgets.top_level))
+ return False;
+
+ return XQueryPointer(DISP, mane.win, &root, &child,
+ &root_x, &root_y, xpos, ypos, &keys_buttons);
+}
+
+unsigned long
+parse_debugging_string(const char *arg)
+{
+ int retval = 0;
+ const char *curr, *last;
+ size_t i;
+
+ curr = last = arg;
+
+ while (curr != '\0') {
+ Boolean matched = False;
+
+ while (isspace((int)*curr))
+ curr++;
+ for (i = 0; debug_options[i].description != NULL; i++) {
+ /* match on length of passed argument, to allow for abbreviations */
+ if (memicmp(curr,
+ debug_options[i].description,
+ strlen(debug_options[i].description)) == 0
+ && (curr[strlen(debug_options[i].description)] == '\0'
+ || curr[strlen(debug_options[i].description)] == ','
+ || isspace((int)curr[strlen(debug_options[i].description)]))) {
+ matched = True;
+ retval |= debug_options[i].bitmap;
+ fprintf(stderr, "Debugging option: \"%s\" = \"%s\", debug: %d\n",
+ curr, debug_options[i].description, retval);
+ }
+ }
+ if (!matched) {
+ char *tempstr = xstrdup(curr);
+ char *test;
+ if ((test = strchr(curr, ',')) != NULL) {
+ *test = '\0';
+ }
+ XDVI_WARNING((stderr, "Ignoring unknown debugging option \"%s\". Valid options are:\n", tempstr));
+ for (i = 0; debug_options[i].description != NULL; i++) {
+ fprintf(stderr, "`%s'%s",
+ debug_options[i].description,
+ debug_options[i].help_formatting);
+ }
+ fprintf(stderr, "\n");
+ free(tempstr);
+ }
+ curr = strchr(curr, ',');
+ if (curr != NULL)
+ curr++;
+ }
+
+ return retval;
+}
+
+unsigned long
+parse_debugging_option(const char *ptr)
+{
+ if (ptr == NULL)
+ return 0L;
+ else if (isdigit((int)*ptr)) {
+ if (resource.debug_arg == NULL)
+ return DBG_ALL; /* per default debug everything */
+ else
+ return strtol(resource.debug_arg, (char **)NULL, 10);
+ } else if (*ptr == '-')
+ return DBG_ALL;
+ else return parse_debugging_string(ptr);
+}
+
+/* determine average width of a font */
+int
+get_avg_font_width(XFontStruct *font)
+{
+ int width;
+
+ assert(font != NULL);
+ width = font->max_bounds.width + font->min_bounds.width / 2;
+ if (width == 0) {
+ /* if min_bounds.width = -max_bounds.width, we probably
+ have a scalable TT font; try to determine its actual
+ width by measuring the letter `x':
+ */
+ width = XTextWidth(font, "x", 1);
+ }
+ if (width == 0) { /* last resort */
+ width = font->max_bounds.width / 2;
+ }
+ return width;
+
+}
+
+/*
+ Splits LINE from BEGIN to END (not neccessarily null-terminated)
+ into items separated by SEP, removes leading or trailing whitespace,
+ and saves the items as newly allocated char*s into the return array.
+ Returns the number of items that have been saved as RET_ITEMS.
+ Empty entries are returned as such, i.e. both `abc:' and `abc: '
+ return RET_ITEMS = 2 and "" as second entry.
+*/
+char **
+split_line(const char *line, char sep, size_t begin, size_t end, size_t *ret_items)
+{
+ const char *c_ptr = line + begin;
+ const char *e_ptr = line + end;
+ const char *test_end;
+
+ size_t result_cnt = 0;
+ size_t alloc_len = 0;
+ size_t len;
+ const size_t ALLOC_STEP = 8;
+ char **result_arr = NULL;
+
+ /* create new result item, resizing result_arr as needed
+ * (an empty string will coun1 as 1 item: "") */
+ while (result_cnt + 1 >= alloc_len) {
+ alloc_len += ALLOC_STEP;
+ result_arr = xrealloc(result_arr, alloc_len * sizeof *result_arr);
+ }
+
+ while (c_ptr <= e_ptr) {
+ /* skip leading whitespace */
+ while (c_ptr < e_ptr && isspace((int)*c_ptr)) {
+ c_ptr++;
+ }
+
+ /* find end of current elem, which is either the separator or out of range */
+ test_end = strchr(c_ptr, sep);
+ /* skip escaped separators */
+ while (test_end != NULL && test_end <= e_ptr) {
+ if (test_end > c_ptr && *(test_end - 1) == '\\') {
+ test_end = strchr(test_end + 1, sep);
+ }
+ else
+ break;
+ }
+ /* if nothing found, use e_ptr */
+ if (test_end == NULL || test_end > e_ptr) {
+ test_end = e_ptr;
+ }
+
+ len = test_end - c_ptr;
+
+ /* skip trailing whitespace */
+ while (len > 0 && isspace((int)c_ptr[len - 1])) {
+ len--;
+ }
+
+ result_arr[result_cnt] = xmalloc(len + 1);
+ /* copy into result item, skipping the escape '\\' characters */
+ {
+ size_t i = 0, j = 0;
+ while (i < len) {
+ if (c_ptr[i] == '\\' && c_ptr[i + 1] == sep) /* i + 1 is safe since (i < len) */
+ i++;
+ result_arr[result_cnt][j++] = c_ptr[i++];
+ }
+ result_arr[result_cnt][j] = '\0';
+ }
+ result_cnt++;
+
+ /* skip to next item */
+ c_ptr = test_end + 1;
+ }
+ result_arr[result_cnt] = NULL; /* null-terminate return array, just to be safe */
+ *ret_items = result_cnt;
+ return result_arr;
+}
+
+
+/*------------------------------------------------------------
+ * find_file
+ *
+ * Arguments:
+ * filename - absolute or relative file name
+ * statbuf - buffer to stat filename
+ * pathinfo - kpse_file_format_type, only used if a kpathsearch for the
+ * file is performed.
+ * See kpathsea/tex-file.h for a list of possible values.
+ *
+ * Returns:
+ * expanded filename
+ *
+ * Purpose:
+ * Find a file name corresponding to <filename>, possibly
+ * expanding it to a full path name; checks if the file
+ * exists by stat()ing it; returns NULL if nothing has
+ * been found, else the expanded filename in fresh memory.
+ *
+
+ *------------------------------------------------------------*/
+
+char *
+find_file(const char *filename, struct stat *statbuf, kpse_file_format_type pathinfo)
+{
+ char *tmp;
+ char *pathname;
+
+ TRACE_SRC((stderr, "checking filename \"%s\"", filename));
+
+ /*
+ * case 1:
+ * try absolute filename
+ */
+ if (filename[0] == '/') {
+ if (stat(filename, statbuf) == 0) {
+ TRACE_SRC((stderr, "Found absolute filename \"%s\"", filename));
+ return xstrdup(filename);
+ }
+ else {
+ TRACE_SRC((stderr, "Can't stat absolute filename \"%s\"\n", filename));
+ return NULL;
+ }
+ }
+
+ /*
+ * case 2:
+ * prepend filename with dir component from the `main' xdvi file (globals.dvi_file.dirname).
+ * This works for both
+ * /absolute/path/ + filename
+ * and
+ * /absolute/path/ + relative/path/filename
+ */
+ ASSERT(globals.dvi_file.dirname != NULL, "globals.dvi_file.dirname should have been initialized");
+ {
+ pathname = xstrdup(globals.dvi_file.dirname);
+ pathname = xstrcat(pathname, filename);
+
+ TRACE_SRC((stderr, "Trying globals.dvi_file.dirname: \"%s\"", pathname));
+ if (stat(pathname, statbuf) == 0) {
+ return pathname;
+ }
+ }
+
+ /*
+ * case 3:
+ * try current directory; if it's a match, expand to full (but uncanonicalized) path name.
+ */
+ if (stat(filename, statbuf) == 0) {
+ TRACE_SRC((stderr, "Found file \"%s\" in current dir", filename));
+ free(pathname);
+ return expand_filename(filename, USE_CWD_PATH);
+ }
+
+ /*
+ * case 4:
+ * try a kpathsea search for filename
+ */
+ TRACE_SRC((stderr,
+ "trying kpathsearch for filename \"%s\"",
+ filename));
+ tmp = kpse_find_file(filename, pathinfo, True);
+
+ if (tmp != NULL && stat(tmp, statbuf) == 0) {
+ TRACE_SRC((stderr, "Found file: `%s'", tmp));
+ free(pathname);
+ return tmp;
+ }
+
+ /*
+ * case 5:
+ * try a kpathsea search for pathname
+ */
+ TRACE_SRC((stderr,
+ "trying kpathsearch for pathname \"%s\"",
+ pathname));
+ tmp = kpse_find_file(pathname, pathinfo, True);
+
+ if (tmp != NULL && stat(tmp, statbuf) == 0) {
+ TRACE_SRC((stderr, "Found file: `%s'", tmp));
+ free(pathname);
+ return tmp;
+ }
+
+ /* not found */
+ free(pathname);
+ free(tmp);
+ errno = 0;
+ return NULL;
+}
+
+/*
+ Hashtable functions
+
+ The purpose of these is to wrap kpathsea's rather strange hash
+ functions that can be used to store 2 type of values: char *, and
+ long, where the latter is interpreted as char *. (See kpathsea/dir.c
+ for an example of where this is used).
+ We can't use a different approach (like using a void *) since
+ the debugging ouput of kpathsea relies on printing the value
+ either as char * or long (depending on the value of the global flag
+ `kpse_debug_hash_lookup_int').
+*/
+/*
+ If key is in hashtable, return True and the integer value in val;
+ else return False (and leave val untouched).
+*/
+Boolean
+find_str_int_hash(hashTableT *hashtable, const char *key, size_t *val)
+{
+ string *ret;
+#ifdef KPSE_DEBUG
+ if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
+ kpse_debug_hash_lookup_int = True;
+#endif
+ ret = hash_lookup(*hashtable, key);
+#ifdef KPSE_DEBUG
+ if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
+ kpse_debug_hash_lookup_int = False;
+#endif
+
+ if (ret != NULL) {
+ long l = (long)*ret;
+ *val = (size_t)l;
+ return True;
+ }
+ return False;
+}
+
+/*
+ Insert key-value pair into hashtable. Note that the key is
+ *not* copied (i.e. it is expected that is had been allocated
+ somewhere else, and persists throughout the program).
+ */
+void
+put_str_int_hash(hashTableT *hashtable, const char *key, size_t val)
+{
+ long ptr = (long)val;
+ hash_insert(hashtable, key, (const string)ptr);
+}
+
+/* set globals.dvi_name, globals.dvi_file.dirname and globals.dvi_file.dirlen */
+void
+set_dvi_name_expand(const char *new_filename)
+{
+ ASSERT(new_filename != NULL, "");
+ free(globals.dvi_name);
+ globals.dvi_name = expand_filename_append_dvi(new_filename, USE_CWD_PATH, True);
+
+ free(globals.dvi_file.dirname);
+ globals.dvi_file.dirname = get_dir_component(globals.dvi_name);
+
+ ASSERT(globals.dvi_file.dirname != NULL, "dvi_name should be a path with dir component");
+ globals.dvi_file.dirlen = strlen(globals.dvi_file.dirname);
+}
+
+/* set globals.dvi_name, globals.dvi_file.dirname and globals.dvi_file.dirlen
+ In contrast to previous function, input filename is not copied.
+ */
+void
+set_dvi_name(char *new_filename)
+{
+ ASSERT(new_filename != NULL, "");
+ free(globals.dvi_name);
+ globals.dvi_name = new_filename;
+
+ free(globals.dvi_file.dirname);
+ globals.dvi_file.dirname = get_dir_component(globals.dvi_name);
+
+ ASSERT(globals.dvi_file.dirname != NULL, "dvi_name should be a path with dir component");
+ globals.dvi_file.dirlen = strlen(globals.dvi_file.dirname);
+}
+
+/*
+ * Copy the file pointer `in' to the file pointer `out'. Return True
+ * if successful, False else (in which case caller should examine
+ * errno to find the error).
+ * The caller is responsible for closing the files.
+ */
+Boolean
+copy_fp(FILE *in, FILE *out)
+{
+#define TMP_BUF_SIZE 4 * 1024
+ char buf[TMP_BUF_SIZE];
+
+ while (feof(in) == 0) {
+ size_t bytes_in, bytes_out;
+
+ bytes_in = fread(buf, 1, TMP_BUF_SIZE, in);
+ if (bytes_in < TMP_BUF_SIZE && !feof(in))
+ return False;
+ bytes_out = fwrite(buf, 1, bytes_in, out);
+/* fprintf(stderr, "read %d, wrote %d bytes\n", bytes_in, bytes_out); */
+ if (bytes_out < bytes_in)
+ return False;
+ }
+ return True;
+
+#undef TMP_BUF_SIZE
+}
+
+/*
+ * Copy a file from `from_path' to `to'. Return True if successful, False else
+ * (in which case caller should examine errno to find the error).
+ */
+Boolean
+copy_file(const char *from_path, const char *to_path) {
+ FILE *from_fp;
+ FILE *to_fp;
+
+ Boolean retval;
+
+ if ((from_fp = try_fopen(from_path, "rb")) == NULL) {
+ XDVI_ERROR((stderr, "opening %s for reading failed: %s", from_path, strerror(errno)));
+ return False;
+ }
+
+ if ((to_fp = try_fopen(to_path, "wb")) == NULL) {
+ XDVI_ERROR((stderr, "opening %s for writing failed: %s", to_path, strerror(errno)));
+ return False;
+ }
+
+ retval = copy_fp(from_fp, to_fp);
+
+ fclose(from_fp);
+ fclose(to_fp);
+
+ return retval;
+}
+
+const char *
+get_text_encoding(void)
+{
+ const char *text_encoding = NULL;
+
+ /* if resource.text_encoding isn't set, use nl_langinfo() if langinfo is available */
+ if (resource.text_encoding == NULL) {
+#if USE_LANGINFO
+ if (globals.orig_locale == NULL) {
+ XDVI_ERROR((stderr, "Call to setlocale() returned NULL; assuming ISO-8859-1 charset."));
+ text_encoding = "ISO-8859-1";
+ }
+ else {
+ if (strcmp(globals.orig_locale, "C") == 0 || strcmp(globals.orig_locale, "POSIX") == 0) {
+ /* nl_langinfo returns rather strange values for these ... */
+ text_encoding = "ISO-8859-1";
+ TRACE_FIND((stderr, "Assuming |%s| for locale |%s|",
+ text_encoding, globals.orig_locale));
+ }
+ else {
+ text_encoding = nl_langinfo(CODESET);
+ TRACE_FIND((stderr, "nl_langinfo returned: |%s| for locale |%s|",
+ text_encoding, globals.orig_locale));
+ }
+ }
+#else
+ XDVI_WARNING((stderr,
+ "nl_langinfo() not available on this platform, "
+ "and XDvi.textEncoding resource not set; using default "
+ "encoding ISO-8859-1."));
+ text_encoding = "ISO-8859-1";
+#endif
+ }
+ else {
+ text_encoding = resource.text_encoding;
+ }
+ return text_encoding;
+}
+
+char *
+iconv_convert_string(const char *from_enc, const char *to_enc, const char *str)
+{
+ static Boolean have_warned = False;
+#if HAVE_ICONV_H
+ size_t input_len = strlen(str);
+ size_t conv_len = input_len * 4 + 1; /* worst case ... */
+ int conv_len_save = conv_len;
+ char *conv_buf = xmalloc(conv_len);
+ const char *in_ptr = str;
+ const char *out_ptr = conv_buf;
+
+ iconv_t conv_desc = iconv_open(to_enc, from_enc);
+
+ if (conv_desc == (iconv_t)(-1)) {
+ if (!have_warned) {
+ popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_ERR,
+ NULL,
+ "iconv_open() error: Encoding \"%s\" is not supported by this version of iconv.\n"
+ "Please check the output of \"iconv -l\" and set the X resource\n"
+ "\"XDvi.textEncoding\" to an appropriate value.", from_enc);
+ have_warned = True;
+ }
+ free(conv_buf);
+ return NULL;
+ }
+
+ TRACE_FIND((stderr, "iconv_convert_string: from `%s', to `%s'", from_enc, to_enc));
+ if (iconv(conv_desc, (iconv_char_pptrT)&in_ptr, &input_len, (char **)&out_ptr, &conv_len) == (size_t)(-1)) {
+ popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_ERR,
+ NULL,
+ "iconv_convert_string(): Could not convert %s to %s: %s.",
+ from_enc, to_enc, strerror(errno));
+ iconv_close(conv_desc);
+ free(conv_buf);
+ return NULL;
+ }
+
+ iconv_close(conv_desc);
+ conv_len = conv_len_save - conv_len;
+ conv_buf[conv_len] = '\0';
+
+ TRACE_FIND((stderr, "after iconv conversion: |%s| %lu bytes\n",
+ conv_buf, (unsigned long)conv_len));
+
+
+ return conv_buf;
+
+#else /* HAVE_ICONV_H */
+
+ UNUSED(from_enc);
+ UNUSED(to_enc);
+ UNUSED(str);
+
+ /* no iconv available */
+ if (!have_warned) {
+ popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
+ MSG_ERR,
+ "You can either set the \"LANG\" environment variable or the X resource "
+ "\"XDvi.textEncoding\" to make xdvi use a different language/encoding setting.\n"
+ "Without iconv, only the encodings ISO-8859-1 and UTF-8 are supported. "
+ "For real iconv support, you will need to install the iconv library "
+ "and recompile xdvik.",
+ "Cannot convert from %s to UTF-8 without iconv support compiled in.");
+ have_warned = True;
+ }
+ return NULL;
+
+#endif /* HAVE_ICONV_H */
+}
+
+#if 0
+/*
+ * Search integer array <arr> of length <arr_len> for for <item>.
+ * Return the index of the item, or the index of the next smaller item
+ * if there's no exact match. (That we want the latter is the
+ * reason why we can't use bsearch()).
+ */
+int
+binary_search(int *arr, int arr_len, int item)
+{
+ int lower = -1;
+ int upper = arr_len;
+ int mid;
+
+ ASSERT(arr_len >= 1, "binary_search expects arrays of length >= 1");
+
+ do {
+ mid = (lower + upper) / 2;
+ if (item > arr[mid])
+ lower = mid;
+ else if (item < arr[mid])
+ upper = mid;
+ else /* exact match */
+ return mid;
+ } while (upper - lower > 1);
+
+ /* no exact match, return next lower item */
+ if (mid > 0 && arr[mid] > item)
+ return mid - 1;
+ else
+ return mid;
+}
+#endif /* 0 */
diff --git a/Build/source/texk/xdvik/util.h b/Build/source/texk/xdvik/util.h
new file mode 100644
index 00000000000..473d8d1be6d
--- /dev/null
+++ b/Build/source/texk/xdvik/util.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <stdio.h>
+#include "xdvi-config.h"
+#include "version.h"
+#include "kpathsea/c-stat.h"
+#include "kpathsea/hash.h"
+#include "kpathsea/tex-file.h"
+
+#if HAVE_POLL
+# include <poll.h>
+# define XIO_IN POLLIN
+# define XIO_OUT POLLOUT
+#else
+# if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# else
+# if HAVE_SELECT_H
+# include <select.h>
+# endif
+# endif
+# define XIO_IN 1
+# define XIO_OUT 2
+#endif
+
+#include "events.h" /* for child proc stuff */
+
+/* double linked list */
+struct dl_list {
+ void *item;
+ struct dl_list *prev;
+ struct dl_list *next;
+};
+
+struct dl_list *dl_list_head(struct dl_list *list);
+struct dl_list *dl_list_push_front(struct dl_list *list, void *item);
+struct dl_list *dl_list_insert(struct dl_list *list, void *item);
+struct dl_list *dl_list_truncate(struct dl_list *list);
+struct dl_list *dl_list_truncate_head(struct dl_list *list);
+struct dl_list *dl_list_remove(struct dl_list *list,
+ const void *elem,
+ int *count,
+ void **item,
+ Boolean (*compare_func)(const void *item1, const void *item2));
+Boolean dl_list_remove_item(struct dl_list **list);
+FILE *try_fopen(const char *fname, const char *mode);
+FILE *try_fdopen(int fd, const char *mode);
+int try_open(const char *fname, int flags);
+int try_open_mode(const char *fname, int flags, mode_t mode);
+
+extern int xdvi_temp_fd(char **tempfilename);
+
+
+typedef void (*child_exited_proc)(int status, struct xchild *this);
+
+extern void handle_child_exit(int status, struct xchild *this);
+extern char *read_child_error(int fd);
+extern Boolean fork_process(const char *file, Boolean redirect_stdout,
+ const char *dirname,
+ childProcT exit_proc, void *data,
+ char *const argv[]);
+extern void prep_fd(int fd, wide_bool noblock);
+
+struct bitmap; /* forward declaration */
+extern void alloc_bitmap(struct bitmap *);
+
+extern char *my_realpath(const char *path, char *real);
+#ifdef HAVE_REALPATH
+#include <limits.h>
+# define REALPATH realpath
+#else
+# define REALPATH my_realpath
+#endif
+
+char *expand_homedir(const char *path);
+void set_dvi_name_expand(const char *new_filename);
+void set_dvi_name(char *new_filename);
+FILE *XFOPEN(const char *path, const char *mode);
+
+
+#ifndef HAVE_MEMICMP
+extern int memicmp(const char *, const char *, size_t);
+#endif
+
+/* NOTE: all of the following are already defined by kpathsea. */
+/* extern void *xmalloc(unsigned); */
+/* extern void *xrealloc(void *, unsigned); */
+/* extern char *xstrdup(const char *); */
+/* extern char *xmemdump(const char *, size_t); */
+/* extern void xputenv(const char *, const char *); */
+
+extern char *xstrcat(char *str1, const char *str2);
+extern int xpipe(int *);
+extern void close_a_file(void);
+extern unsigned long get_bytes(FILE *, int);
+extern long get_lbytes(FILE *, int);
+
+extern void xdvi_exit(int);
+extern void do_abort(void);
+
+/* various levels of warning/error messages */
+extern void xdvi_info(const char *fmt, ...);
+extern void xdvi_warning(const char *fmt, ...);
+extern void xdvi_error(const char *fmt, ...);
+extern void xdvi_fatal(const char *fmt, ...);
+extern void xdvi_abort(const char *fmt, ...);
+
+extern Boolean pointerlocate(int *, int *);
+extern unsigned long parse_debugging_string(const char *arg);
+extern unsigned long parse_debugging_option(const char *ptr);
+
+extern int get_avg_font_width(XFontStruct *font);
+extern char **split_line(const char *line, char sep, size_t begin, size_t end, size_t *ret_items);
+extern char *find_file(const char *filename, struct stat *statbuf, kpse_file_format_type pathinfo);
+
+/*
+ hashtable wrapper functions, mostly used by dvi-draw.c to
+ map filenames to integers. This uses the hashtable implementation
+ from kpathsea, which is reasonably fast.
+*/
+
+/*
+ We use this dummy wrapper stuct, which we cast to void *, to get integer
+ values into/from the hashtable (natively, kpahtsea only supports string
+ values).
+*/
+struct str_int_hash_item {
+ int value;
+};
+
+
+typedef hash_table_type hashTableT; /* from kpathsea */
+extern Boolean find_str_int_hash(hashTableT *hashtable, const char *key, size_t *val);
+void put_str_int_hash(hashTableT *hashtable, const char *key, size_t val);
+
+Boolean copy_file(const char *from, const char *to);
+Boolean copy_fp(FILE *in, FILE *out);
+
+extern const char *get_text_encoding(void);
+extern char *iconv_convert_string(const char *from_enc, const char *to_enc, const char *str);
+
+
+/* Various error reporting macros.
+ The reasons why these are macros are:
+ - possibility to use __FILE__, __LINE__
+ - (more importantly:) gcc can't do type checking on generic vararg
+ macros, but does so for the printf() functions.
+*/
+
+/*
+ * Print an informative message to stdout,
+ * unless the resource `hush_stdout' is set.
+ */
+#define XDVI_INFO(X) do { \
+ fprintf(stdout, "%s: Info: ", globals.program_name); \
+ fflush(stdout); /* in case following goes to stderr accidentally ... */ \
+ fprintf X; \
+ fprintf(stdout, "\n"); \
+ fflush(stdout); /* to make sure it doesn't get intermingled with stderr */ \
+} while(0)
+
+
+/*
+ * Print a warning message to stderr.
+ * This can't be shut off by `hush_stdout'.
+ */
+#define XDVI_WARNING(X) do { \
+ fprintf(stderr, "%s: Warning: ", globals.program_name); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+} while(0)
+
+/*
+ * Print an un-typed message to stderr, without starting a newline.
+ * This can't be shut off by `hush_stdout'.
+ */
+#define XDVI_MSG(X) do { \
+ fprintf(stderr, "%s: ", globals.program_name); \
+ fprintf X; \
+} while(0)
+
+
+/*
+ * Print an error message to stderr.
+ * This can't be shut off by `hush_stdout'.
+ */
+#define XDVI_ERROR(X) do { \
+ fprintf(stderr, "%s: Error: ", globals.program_name); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+} while(0)
+
+/*
+ * Print an error message and quit. Use this only with extreme care,
+ * if recovery is really impossible!
+ */
+#define XDVI_FATAL(X) do { \
+ fprintf(stderr, "%s: Fatal error: ", globals.program_name); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ xdvi_exit(EXIT_FAILURE); \
+} while(0)
+
+/*
+ * Print an error message and abort. Use this instead of assertions
+ * if you want to give a more informative message.
+ */
+#define XDVI_ABORT(X) do { \
+ fprintf(stderr, "%s %s: %s:%d: Shouldn't happen: ", \
+ globals.program_name, \
+ XDVI_VERSION_INFO, \
+ __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ do_abort(); \
+} while(0)
+
+#endif /* UTIL_H_ */
diff --git a/Build/source/texk/xdvik/version.h b/Build/source/texk/xdvik/version.h
new file mode 100644
index 00000000000..e2c6ef4744f
--- /dev/null
+++ b/Build/source/texk/xdvik/version.h
@@ -0,0 +1,19 @@
+/* Version info that is displayed at -h, -v and in GUI elements */
+#ifndef VERSION_H_
+#define VERSION_H_
+
+#define XDVI_VERSION "22.84.10"
+
+#ifdef MOTIF
+#define XDVI_GUI "(Motif toolkit)"
+#else
+#define XDVI_GUI "(Xaw toolkit)"
+#endif
+
+#define XDVIK_PROGNAME "xdvik"
+#define XDVI_PROGNAME "xdvi"
+
+#define XDVI_VERSION_INFO XDVI_VERSION" "XDVI_GUI
+#define XDVI_TERSE_VERSION_INFO XDVI_VERSION
+
+#endif /* VERSION_H_ */
diff --git a/Build/source/texk/xdvik/vf.c b/Build/source/texk/xdvik/vf.c
new file mode 100644
index 00000000000..7fd4cd0379d
--- /dev/null
+++ b/Build/source/texk/xdvik/vf.c
@@ -0,0 +1,184 @@
+/*========================================================================*\
+
+Copyright (c) 1992-2004 Paul Vojta
+
+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.
+
+\*========================================================================*/
+
+/*
+ * VF font reading routines.
+ * Public routine is read_index---because virtual characters are presumed
+ * to be short, we read the whole virtual font in at once, instead of
+ * faulting in characters as needed.
+ */
+
+#include "xdvi-config.h"
+#include "dvi.h"
+#include "xdvi.h"
+#include "util.h"
+#include "dvi-init.h"
+#include "dvi-draw.h"
+
+#define LONG_CHAR 242
+
+/*
+ * These are parameters which determine whether macros are combined for
+ * storage allocation purposes. Small macros ( <= VF_PARM_1 bytes) are
+ * combined into chunks of size VF_PARM_2.
+ */
+
+#ifndef VF_PARM_1
+#define VF_PARM_1 20
+#endif
+#ifndef VF_PARM_2
+#define VF_PARM_2 256
+#endif
+
+/*
+ * The main routine
+ */
+
+unsigned long
+read_VF_index(struct font *fontp, wide_bool hushcs)
+{
+ FILE *VF_file = fontp->file;
+ ubyte cmnd;
+ ubyte *avail, *availend; /* available space for macros */
+ long checksum;
+ struct macro *newmacro;
+ unsigned long maxcc = 0;
+ Boolean dummy = False;
+
+ fontp->read_char = NULL;
+ fontp->flags |= FONT_VIRTUAL;
+ fontp->set_char_p = set_vf_char;
+ if (globals.debug & DBG_PK)
+ printf("Reading VF file %s\n", fontp->filename);
+ /*
+ * Read preamble.
+ */
+ fseek(VF_file, (long)get_byte(VF_file), SEEK_CUR); /* skip comment */
+ checksum = get_bytes(VF_file, 4);
+ if (checksum != fontp->checksum && checksum != 0 && fontp->checksum != 0
+ && !hushcs)
+ XDVI_WARNING((stderr, "Checksum mismatch (dvi = %lu, vf = %lu) in font file %s",
+ fontp->checksum, checksum, fontp->filename));
+ (void)get_bytes(VF_file, 4); /* skip design size */
+ /*
+ * Read the fonts.
+ */
+ fontp->vf_table = xmalloc(VFTABLELEN * sizeof(struct font *));
+ memset((char *)fontp->vf_table, 0, VFTABLELEN * sizeof(struct font *));
+ fontp->vf_chain = NULL;
+ fontp->first_font = NULL;
+ while ((cmnd = get_byte(VF_file)) >= FNTDEF1 && cmnd <= FNTDEF4) {
+ struct font *newfontp = define_font(True,
+ VF_file, cmnd, fontp,
+ fontp->vf_table, VFTABLELEN,
+ &fontp->vf_chain,
+ &dummy);
+ if (fontp->first_font == NULL)
+ fontp->first_font = newfontp;
+ }
+ /*
+ * Prepare macro array.
+ */
+ if (resource.omega) {
+ fontp->maxchar = 65535;
+ fontp->macro = xmalloc(65536 * sizeof(struct macro));
+ memset((char *)fontp->macro, 0, 65536 * sizeof(struct macro));
+ }
+ else {
+ fontp->macro = xmalloc(256 * sizeof(struct macro));
+ memset((char *)fontp->macro, 0, 256 * sizeof(struct macro));
+ }
+ /*
+ * Read macros.
+ */
+ avail = availend = NULL;
+ for (; cmnd <= LONG_CHAR; cmnd = get_byte(VF_file)) {
+ struct macro *m;
+ int len;
+ unsigned long cc;
+ long width;
+
+ if (cmnd == LONG_CHAR) { /* long form packet */
+ len = get_bytes(VF_file, 4);
+ cc = get_bytes(VF_file, 4);
+ width = get_bytes(VF_file, 4);
+ if ((resource.omega && cc >= 65536)
+ || (!resource.omega && cc >= 256)) {
+ XDVI_WARNING((stderr, "Virtual character %lu in font %s ignored.",
+ cc, fontp->fontname));
+ fseek(VF_file, (long)len, SEEK_CUR);
+ continue;
+ }
+ }
+ else { /* short form packet */
+ len = cmnd;
+ cc = get_byte(VF_file);
+ width = get_bytes(VF_file, 3);
+ }
+ if (resource.omega) {
+ maxcc = (cc > maxcc) ? cc : maxcc;
+ }
+ m = &fontp->macro[cc];
+ m->dvi_adv = width * fontp->dimconv;
+ if (len > 0) {
+ if (len <= availend - avail) {
+ m->pos = avail;
+ avail += len;
+ }
+ else {
+ m->free_me = True;
+ if (len <= VF_PARM_1) {
+ m->pos = avail = xmalloc(VF_PARM_2);
+ availend = avail + VF_PARM_2;
+ avail += len;
+ }
+ else
+ m->pos = xmalloc((unsigned)len);
+ }
+ fread((char *)m->pos, 1, len, VF_file);
+ m->end = m->pos + len;
+ }
+ if (globals.debug & DBG_PK)
+ printf("Read VF macro for character %lu; dy = %ld, length = %d\n",
+ cc, m->dvi_adv, len);
+ }
+ if (cmnd != POST)
+ XDVI_FATAL((stderr, "Wrong command byte found in VF macro list: %d", cmnd));
+
+ fclose(VF_file);
+ fontp->file = NULL;
+ if (resource.omega) {
+ size_t i;
+ newmacro = xmalloc((maxcc + 1) * sizeof(struct macro));
+ for (i = 0; i <= maxcc; i++) {
+ newmacro[i] = fontp->macro[i];
+ }
+ free(fontp->macro);
+ fontp->macro = newmacro;
+ fontp->maxchar = maxcc;
+ return maxcc;
+ }
+ else
+ return 0; /* dummy */
+}
diff --git a/Build/source/texk/xdvik/withenable.ac b/Build/source/texk/xdvik/withenable.ac
new file mode 100644
index 00000000000..a6bb7495cc5
--- /dev/null
+++ b/Build/source/texk/xdvik/withenable.ac
@@ -0,0 +1,149 @@
+dnl withenable.ac: --with and --enable options.
+
+# Check if the user wants to use Ghostscript, DPS or NeWS to
+# display PostScript.
+AC_ARG_WITH([ps],
+[ --with-ps=PS Use PostScript (PS=no/yes/gs/dps/news, default gs)],
+[case $withval in
+ yes|gs) PS_DEF="$PS_DEF -DPS_GS";;
+ no) PS_DEF=no;;
+ dps) PS_DEF="$PS_DEF -DPS_DPS";;
+ news) PS_DEF="$PS_DEF -DPS_NEWS";;
+ *) AC_MSG_WARN([Unknown --with-ps argument \`$withval'; using gs.]);;
+ esac])
+
+AC_ARG_ENABLE([grey],
+[ --disable-grey Disable greyscale anti-aliasing for shrunken bitmaps]
+,
+[if test "$enableval" = yes; then
+ AC_DEFINE(GREY)
+ else
+ echo DISABLED grey
+fi],
+[AC_DEFINE(GREY)])
+
+AC_ARG_ENABLE([color],
+[ --disable-color Disable support for color specials],
+[if test "$enableval" = yes; then
+ AC_DEFINE(COLOR)
+ else
+ echo DISABLED color
+fi],
+[AC_DEFINE(COLOR)])
+
+dnl OBSOLETE AC_ARG_ENABLE([buttons],
+dnl OBSOLETE [ --disable-buttons Disable buttons on the side of the window],
+dnl OBSOLETE [if test "$enableval" = yes; then
+dnl OBSOLETE AC_DEFINE(BUTTONS)
+dnl OBSOLETE else
+dnl OBSOLETE echo DISABLED buttons
+dnl OBSOLETE fi],
+dnl OBSOLETE [AC_DEFINE(BUTTONS)])
+
+dnl OBSOLETE AC_ARG_ENABLE([statusline],
+dnl OBSOLETE [ --disable-statusline Disable statusline at bottom of window],
+dnl OBSOLETE [if test "$enableval" = yes; then
+dnl OBSOLETE AC_DEFINE(STATUSLINE)
+dnl OBSOLETE else
+dnl OBSOLETE echo DISABLED statusline
+dnl OBSOLETE fi],
+dnl OBSOLETE [AC_DEFINE(STATUSLINE)])
+
+AC_ARG_ENABLE([t1lib],
+[ --disable-t1lib Do not use T1lib (direct rendering of Type1 fonts)],
+[if test "$enableval" = yes; then
+ T1LIB=1
+ LDT1LIB=../../libs/t1lib/lib/.libs/libt1.a
+ AC_DEFINE(LDT1LIB)
+ AC_DEFINE(T1LIB)
+else
+ T1LIB=
+ LDT1LIB=
+ echo DISABLED t1lib
+fi],
+[T1LIB=1
+LDT1LIB=../../libs/t1lib/lib/.libs/libt1.a
+AC_DEFINE(LDT1LIB)
+AC_DEFINE(T1LIB)])
+
+AC_ARG_ENABLE([gf],
+[ --enable-gf Enable gf format pixel files (in addition to pk)],
+[if test "$enableval" != no; then
+ AC_DEFINE(USE_GF)
+ OPT_SRCS="$OPT_SRCS gf.c"
+ OPT_OBJS="$OPT_OBJS gf.o"
+fi])
+
+AC_ARG_ENABLE([a4],
+[ --disable-a4 Set default paper size to letter and default unit to inch],
+[if test "$enableval" = yes; then
+ AC_DEFINE(A4)
+ else
+ echo Disabled a4/cm, using letter/in instead
+fi],
+[AC_DEFINE(A4)])
+
+AC_ARG_ENABLE([magick],
+[ --enable-magick Use ImageMagick to load/render image files.
+ EXPERIMENTAL - DO NOT USE!],
+[if test "$enableval" != no; then
+ echo -n "checking for ImageMagick >= 5.3 ... "
+ if MAGICK_VER=`Magick-config --version 2>/dev/null`; then
+ echo $MAGICK_VER
+ set -- `echo $MAGICK_VER | sed -e 's/\./ /g'`
+ MAGICK_VER_MAJOR=$1
+ MAGICK_VER_MINOR=$2
+ if expr $MAGICK_VER_MAJOR \> 4 >/dev/null && \
+ (expr $MAGICK_VER_MAJOR \> 5 >/dev/null || \
+ expr $MAGICK_VER_MINOR \> 2 >/dev/null); then
+ MAGICK_CPP="-DMAGICK_VER_MAJOR=$MAGICK_VER_MAJOR -DMAGICK_VER_MINOR=$MAGICK_VER_MINOR `Magick-config --cppflags`"
+ # echo "CPP: $MAGICK_CPP"
+ MAGICK_LD="`Magick-config --libs`"
+ # echo "LD: $MAGICK_LD"
+ echo "ImageMagick support enabled"
+ MAGICK_INCLUDE=
+ MAGICK_LIBDIR=
+
+ if test "x$with_magick_include" != x; then
+ MAGIC_INCLUDE="-I$with_magick_include"
+ fi
+ if test "x$with_magick_libdir" != x; then
+ MAGIC_LIBDIR="-L$with_magick_libdir"
+ fi
+
+ X_EXTRA_LIBS="$X_EXTRA_LIBS $MAGIC_LIBDIR $MAGICK_LD"
+ X_CFLAGS="$X_CFLAGS $MAGIC_INCLUDE $MAGICK_CPP"
+ AC_DEFINE(MAGICK)
+ #echo MAGICK_DEF=\"$MAGICK_DEF\"
+ else
+ echo "ImageMagick version too old - ImageMagick support disabled"
+ fi
+ else
+ echo "Can't run 'Magick-config' - ImageMagick support disabled"
+ fi
+fi])
+
+AC_SUBST(LDT1LIB)
+
+dnl This defines --with-x implicitly (which is why we use that package
+dnl name below), so put it here, so it comes first in the --help output.
+dnl This reads best.
+
+dnl Remember to add AC_PATH_XTRA when actually using X.
+
+AC_ARG_WITH([xdvi-x-toolkit],
+[ --with-xdvi-x-toolkit=KIT
+ Use toolkit KIT for xdvi (KIT=motif/xaw/xaw3d/neXtaw).
+ If no --with-xdvi-x-toolkit option is used, use Motif
+ if available, else Xaw.],
+[ case "${withval}" in
+ next | nextaw | neXtaw ) val=neXtaw ;;
+ xaw3d ) val=xaw3d ;;
+ x | xa | xaw ) val=xaw ;;
+ m | mo | mot | moti | motif ) val=motif ;;
+ * )
+AC_MSG_WARN([unknown --with-xdvi-x-toolkit argument \`$withval'; using xaw.])
+ val=xaw;;
+ esac
+ with_xdvi_x_toolkit=$val
+])
diff --git a/Build/source/texk/xdvik/x_util.c b/Build/source/texk/xdvik/x_util.c
new file mode 100644
index 00000000000..79dd5a6a531
--- /dev/null
+++ b/Build/source/texk/xdvik/x_util.c
@@ -0,0 +1,1221 @@
+#include "xdvi-config.h"
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/StringDefs.h>
+
+
+#if !MOTIF
+# include <X11/Xaw/Form.h>
+#endif
+
+#include "x_util.h"
+#include "string-utils.h"
+#include "util.h"
+#include "statusline.h"
+#include "message-window.h"
+#include "events.h" /* for set_bar_value() */
+
+#define DEBUG_SCROLL_IF_NEEDED 0
+
+Boolean do_autoscroll = False;
+
+
+/* Center window wa over window wb */
+void
+center_window(Widget wa, Widget wb)
+{
+ Position x, y;
+ Dimension w1, h1, w2, h2;
+
+ if (!XtIsRealized(wa) || !XtIsRealized(wb))
+ return;
+
+ XtVaGetValues(wa,
+ XtNwidth, &w1,
+ XtNheight, &h1,
+ NULL);
+ XtVaGetValues(wb,
+ XtNwidth, &w2,
+ XtNheight, &h2,
+ XtNx, &x,
+ XtNy, &y,
+ NULL);
+ XtVaSetValues(wa, XtNx, x + (w2 - w1) / 2,
+ XtNy, y + (h2 - h1) / 2,
+ NULL);
+}
+
+/* Position window w at coordinates x, y */
+void
+position_window(Widget w, Position x, Position y)
+{
+ if (!XtIsRealized(w))
+ return;
+
+ TRACE_GUI((stderr, "positioning %ld at %d, %d", (unsigned long)w, x, y));
+ XtVaSetValues(w, XtNx, x, XtNy, y, NULL);
+}
+
+/*
+ Used for the hyperref and forward search markers: scroll the page
+ to make the marker visible.
+*/
+void
+scroll_page_if_needed(int x_min, int x_max, int y_min, int y_max)
+{
+ Position drawing_x, drawing_y, drawing_h, clip_x, clip_y, clip_h, clip_w;
+ int test_scroll, need_v_scroll = 0, need_h_scroll = 0;
+
+ if (!do_autoscroll)
+ return;
+
+ XtVaGetValues(globals.widgets.clip_widget,
+ XtNx, &clip_x, XtNy, &clip_y,
+ XtNheight, &clip_h, XtNwidth, &clip_w,
+ NULL);
+ XtVaGetValues(globals.widgets.draw_widget,
+ XtNx, &drawing_x, XtNy, &drawing_y,
+ XtNheight, &drawing_h,
+ NULL);
+
+#if DEBUG_SCROLL_IF_NEEDED
+ fprintf(stderr, "y: %d, drawing_y: %d, clip_h: %d\n", y, drawing_y, clip_h);
+#endif
+ /* check if we need to scroll vertically; first, down for y_min */
+ test_scroll = y_min + drawing_y - clip_h;
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0)
+ test_scroll += global_statusline_h;
+
+ TRACE_SRC((stderr, "test_scroll vertically: %d", test_scroll));
+#if DEBUG_SCROLL_IF_NEEDED
+ fprintf(stderr, "%d + %d > %d?\n", drawing_y, y_min, clip_h);
+#endif
+ if (test_scroll > 0) { /* need to scroll down? */
+ need_v_scroll = test_scroll;
+ TRACE_SRC((stderr, "need_v_scroll down: %d", need_v_scroll));
+ }
+ else if (abs(drawing_y) + 2 > y_max) { /* need to scroll up? */
+ need_v_scroll = -((abs(drawing_y) - y_max) + 1);
+ TRACE_SRC((stderr, "need_v_scroll up: %d (%d > %d; %d)", need_v_scroll, abs(drawing_y), y_max, clip_y));
+ }
+
+ /* check if we need to scroll horizontally; x_min < 0 blocks this
+ (e.g. for hyperref, where we don't want it) */
+ if (x_min >= 0) {
+ test_scroll = x_min + drawing_x - clip_w + 1;
+ TRACE_SRC((stderr, "test_scroll horizontally: %d", test_scroll));
+
+ if (test_scroll > 0) {
+ /* need to scroll to right (i.e. make stuff on right-hand side visible)? */
+ need_h_scroll = test_scroll;
+ TRACE_SRC((stderr, "need_h_scroll right: %d", need_h_scroll));
+ }
+ else if (abs(drawing_x) > x_max) {
+ /* need to scroll to left (i.e. make stuff on left-hand side visible)? */
+ need_h_scroll = -(abs(drawing_x) - x_max);
+ TRACE_SRC((stderr, "need_h_scroll left: %d", need_h_scroll));
+ }
+ }
+
+ /* FIXME: should we not scroll if keep_flag is active? */
+ if (need_v_scroll != 0 && globals.widgets.y_bar != NULL) {
+#ifdef MOTIF
+ /* need to add new value to current one */
+ XtVaGetValues(globals.widgets.y_bar, XmNvalue, &test_scroll, NULL);
+ (void)set_bar_value(globals.widgets.y_bar, test_scroll + need_v_scroll, (int)(globals.page.h - mane.height));
+#else
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer)need_v_scroll);
+#endif
+ }
+
+ if (need_h_scroll != 0 && globals.widgets.x_bar != NULL) {
+#ifdef MOTIF
+ /* need to add new value to current one */
+ XtVaGetValues(globals.widgets.x_bar, XmNvalue, &test_scroll, NULL);
+ (void)set_bar_value(globals.widgets.x_bar, test_scroll + need_h_scroll, (int)(globals.page.w - mane.width));
+#else
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)need_h_scroll);
+#endif
+ }
+
+ do_autoscroll = False;
+}
+
+void adjust_width(Widget a, Widget b)
+{
+ Dimension w1, w2;
+
+ XtVaGetValues(a, XtNwidth, &w1, NULL);
+ XtVaGetValues(b, XtNwidth, &w2, NULL);
+
+ if (w1 < w2)
+ XtVaSetValues(a, XtNwidth, w2, NULL);
+ else if (w2 > w1)
+ XtVaSetValues(b, XtNwidth, w1, NULL);
+}
+
+/* change a GC and return it, or create one if it doesn't exist yet */
+GC
+set_or_make_gc(GC gc, int function, Pixel fg, Pixel bg)
+{
+ XGCValues values;
+ values.function = function;
+ values.foreground = fg;
+ values.background = bg;
+
+ /* Since print is in round dots we make drawings as "smooth" as possible. */
+ values.cap_style = CapRound;
+ values.join_style = JoinRound;
+
+ if (gc != NULL)
+ XChangeGC(DISP, gc, GCFunction | GCForeground | GCBackground
+ | GCCapStyle | GCJoinStyle, &values);
+ else
+ gc = XCreateGC(DISP, XtWindow(globals.widgets.top_level), GCFunction | GCForeground | GCBackground
+ | GCCapStyle | GCJoinStyle, &values);
+
+ return gc;
+}
+
+/*
+ * Atom handling.
+ */
+
+static char *atom_names[] = {
+ "XDVI_WINDOWS",
+ "DVI_NAME",
+ "SRC_GOTO",
+ "RELOAD",
+ "NEWDOC",
+ "NEWPAGE",
+ "RAISE",
+ "FIND_STRING",
+ "REREAD_PREFS"
+};
+static Atom atoms[XtNumber(atom_names)];
+
+Window
+get_window_id(char *window_p)
+{
+ Window w;
+
+#ifndef WORD64
+ w = (*((xuint32 *) window_p));
+#else
+# if WORDS_BIGENDIAN
+ w = ((unsigned long)wp[0] << 24) |
+ ((unsigned long)wp[1] << 16) |
+ ((unsigned long)wp[2] << 8) |
+ (unsigned long)wp[3];
+# else
+ w = ((unsigned long)wp[3] << 24) |
+ ((unsigned long)wp[2] << 16) |
+ ((unsigned long)wp[1] << 8) |
+ (unsigned long)wp[0];
+# endif
+#endif
+ return w;
+}
+
+size_t
+property_get_data(Window w, Atom a, char **ret_buf,
+ int (*x_get_property)(Display *, Window, Atom, long,
+ long, Bool, Atom, Atom *, int *, unsigned long *,
+ unsigned long *, unsigned char **))
+{
+ /* all of these are in 8-bit units */
+ unsigned long byte_offset = 0;
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems_ret;
+ unsigned long bytes_after_ret = 0;
+ unsigned char *prop_ret = NULL;
+
+ /*
+ * buffer for collecting returned data; this is static to
+ * avoid expensive malloc()s at every call (which is often!)
+ */
+ static unsigned char *buffer = NULL;
+ static size_t buffer_len = 0;
+
+ while (x_get_property(DISP, w,
+ a, byte_offset / 4, (bytes_after_ret + 3) / 4, False,
+ a, &type_ret, &format_ret, &nitems_ret,
+ &bytes_after_ret, &prop_ret)
+ == Success) {
+
+ if (type_ret != a || format_ret == 0)
+ break;
+
+ nitems_ret *= (format_ret / 8); /* convert to bytes */
+
+ while ((byte_offset + nitems_ret) >= buffer_len) {
+ buffer_len += 256;
+ buffer = xrealloc(buffer, buffer_len);
+ }
+
+ /* the +1 captures the extra '\0' that Xlib puts after the end. */
+ memcpy(buffer + byte_offset, prop_ret, nitems_ret + 1);
+ byte_offset += nitems_ret;
+
+ XFree(prop_ret);
+ prop_ret = NULL;
+
+ if (bytes_after_ret == 0) /* got all data */
+ break;
+ }
+
+ if (prop_ret != NULL)
+ XFree(prop_ret);
+
+ *ret_buf = (char *)buffer;
+ return byte_offset;
+}
+
+size_t
+property_get_window_list(char **window_list)
+{
+ size_t len = property_get_data(DefaultRootWindow(DISP),
+ atom_xdvi_windows(), window_list,
+ XGetWindowProperty);
+ if (len == 0) {
+ TRACE_CLIENT((stderr, "No \"xdvi windows\" property found"));
+ return 0;
+ }
+
+ if (len % 4 != 0) {
+ TRACE_CLIENT((stderr, "\"XDVI_WINDOWS\" property had incorrect size; deleting it."));
+ XDeleteProperty(DISP, DefaultRootWindow(DISP), atom_xdvi_windows());
+ return 0;
+ }
+ return len;
+}
+
+void
+set_window_id(Window w, unsigned char *data)
+{
+#if WORDS_BIGENDIAN
+ data[0] = (unsigned int)w >> 24;
+ data[1] = (unsigned int)w >> 16;
+ data[2] = (unsigned int)w >> 8;
+ data[3] = (unsigned int)w;
+#else
+ data[0] = (unsigned int)w;
+ data[1] = (unsigned int)w >> 8;
+ data[2] = (unsigned int)w >> 16;
+ data[3] = (unsigned int)w >> 24;
+#endif
+}
+
+/**
+ ** set_dvi_property sets the appropriate property for the main
+ ** window (used in source special handoff).
+ **/
+
+void
+set_dvi_property(void)
+{
+ XChangeProperty(DISP, XtWindow(globals.widgets.top_level), atom_dvi_file(), atom_dvi_file(),
+ 8, PropModeReplace, (unsigned char *)dvi_property, dvi_property_length);
+}
+
+
+/*
+ * Delete all occurences of window w from the window list property. Then,
+ * if `prepend' is true, prepend the window ID to the existing list.
+ */
+void
+update_window_property(Window w, Boolean prepend)
+{
+ char *wlist;
+ size_t wlist_len;
+ char *wlist_end;
+ char *wp;
+#if 0
+ int i;
+#endif /* 0 */
+
+ /* this allocates wlist */
+ if ((wlist_len = property_get_window_list(&wlist)) == 0)
+ return;
+
+ /* Loop over list of windows. */
+ wlist_end = wlist + wlist_len;
+
+#if 0
+ for (i = 0, wp = wlist; wp < wlist_end; wp += 4, i++) {
+ fprintf(stderr, "WIN %d: %08lx; len: %d\n", i, get_window_id(wp), wlist_len);
+ }
+#endif /* 0 */
+
+ for (wp = wlist; wp < wlist_end; wp += 4) {
+ if (get_window_id(wp) == w) { /* match, remove our ID */
+ wlist_len -= 4;
+ wlist_end -= 4;
+ memmove(wp, wp + 4, wlist_end - wp);
+ wp -= 4; /* new item is now at wp; don't skip it in next iteration */
+ }
+ }
+
+ if (prepend) { /* add our ID again to front */
+#ifdef WORD64
+ unsigned char data[4];
+ set_window_id(w, data);
+#else
+ xuint32 data = w;
+#endif
+ /* Note: no need to realloc wlist, since the original length
+ was sufficient for all elements.
+ */
+ memmove(wlist + 4, wlist, wlist_len);
+ wlist_len += 4;
+ memcpy(wlist, &data, 4);
+ }
+
+ if (wlist_len == 0)
+ XDeleteProperty(DISP, DefaultRootWindow(DISP),
+ atom_xdvi_windows());
+ else
+ XChangeProperty(DISP, DefaultRootWindow(DISP),
+ atom_xdvi_windows(), atom_xdvi_windows(), 32,
+ PropModeReplace, (unsigned char *)wlist,
+ wlist_len / 4);
+
+ XFlush(DISP);
+}
+
+void
+property_initialize(void)
+{
+ size_t i;
+
+#if XlibSpecificationRelease >= 6
+ if (!XInternAtoms(DISP, atom_names, XtNumber(atom_names), False, atoms))
+ XDVI_FATAL((stderr, "XtInternAtoms failed."));
+#else
+ for (i = 0; i < XtNumber(atom_names); i++) {
+ if ((atoms[i] = XInternAtom(DISP, atom_names[i], False)) == None)
+ XDVI_FATAL((stderr, "XtInternAtoms failed."));
+ }
+#endif
+
+ if (globals.debug & DBG_CLIENT) {
+ for (i = 0; i < XtNumber(atom_names); i++)
+ TRACE_CLIENT((stderr, "Atom(%s) = %lu", atom_names[i], atoms[i]));
+ }
+}
+
+
+Atom atom_xdvi_windows(void)
+{
+ return atoms[0];
+}
+
+Atom atom_dvi_file(void)
+{
+ return atoms[1];
+}
+
+Atom atom_src_goto(void)
+{
+ return atoms[2];
+}
+
+Atom atom_reload(void)
+{
+ return atoms[3];
+}
+
+Atom atom_newdoc(void)
+{
+ return atoms[4];
+}
+
+Atom atom_newpage(void)
+{
+ return atoms[5];
+}
+
+Atom atom_raise(void)
+{
+ return atoms[6];
+}
+
+Atom atom_find_string(void)
+{
+ return atoms[7];
+}
+
+Atom atom_reread_prefs(void)
+{
+ return atoms[8];
+}
+
+/*
+ * Syntetisize a button press object for the `button' passed as
+ * the second argument.
+ */
+void
+synthetisize_event(XEvent *ev, Widget button)
+{
+ memset(ev, 0, sizeof(XButtonPressedEvent));
+ ev->type = ButtonPress;
+ ev->xbutton.serial = 1;
+ ev->xbutton.send_event = True;
+ ev->xbutton.button = 1;
+ ev->xbutton.display = XtDisplayOfObject(button);
+ ev->xbutton.window = XtWindowOfObject(button);
+}
+
+#ifdef MOTIF
+int xm_get_height(Widget w)
+{
+ int ret_h = 0;
+ static Arg args = { XtNheight, (XtArgVal)0 };
+ ASSERT(w != NULL, "widget in xm_get_width mustn't be NULL!");
+
+ args.value = (XtArgVal)&ret_h;
+ XtGetValues(w, &args, 1);
+ TRACE_GUI((stderr, "xm_get_height: %d", ret_h));
+ return ret_h;
+}
+
+int xm_get_width(Widget w)
+{
+ int ret_w = 0;
+ static Arg args = { XtNwidth, (XtArgVal)0 };
+ ASSERT(w != NULL, "widget in xm_get_width mustn't be NULL!");
+
+ args.value = (XtArgVal)&ret_w;
+ XtGetValues(w, &args, 1);
+ TRACE_GUI((stderr, "xm_get_width: %d", ret_w));
+ return ret_w;
+}
+
+/*
+ * Get pixel from color `colorname'. We try to keep this as
+ * high-level as possible, with simple black as fallback.
+*/
+void
+str_to_pixel(Widget w, const char *colorname, Pixel *ret)
+{
+ XrmValue from, to;
+
+ from.addr = (char *)colorname;
+ from.size = strlen(from.addr) + 1;
+ to.addr = (XtPointer)ret;
+ to.size = sizeof(Pixel);
+ if (!XtConvertAndStore(w, XtRString, &from, XtRPixel, &to)) {
+ fprintf(stderr, "String to pixel conversion failed for %s!\n", colorname);
+ from.addr = (char *)"black";
+ from.size = strlen(from.addr) + 1;
+ to.addr = (XtPointer)ret;
+ to.size = sizeof(Pixel);
+ XtConvertAndStore(w, XtRString, &from, XtRPixel, &to);
+ }
+}
+
+/*
+ * Convert pixel value `pix' to color name passed as str,
+ * of length len, or `black' if conversion failed.
+ * -- FIXME: This is broken!!!
+*/
+void
+pixel_to_str(Widget w, Pixel pix, char *str, size_t len)
+{
+ XrmValue from, to;
+
+ from.addr = (XtPointer)&pix;
+ from.size = sizeof(Pixel);
+ to.addr = str;
+ to.size = len;
+
+ if (!XtConvertAndStore(w, XtRString, &from, XtRPixel, &to)) {
+ fprintf(stderr, "Pixel to String conversion failed for %ld!\n", pix);
+ sprintf(str, "white");
+ }
+}
+
+/* Free color, and initialize it anew with pixel value `pix' */
+void
+pixel_to_color(Pixel pix, XColor *color, Display *display, Colormap colormap)
+{
+ XColor test;
+ test.pixel = pix;
+ XQueryColor(display, colormap, &test);
+
+ color->red = test.red;
+ color->green = test.green;
+ color->blue = test.blue;
+
+ if (!XAllocColor(display, colormap, color)) {
+ fprintf(stderr, "Fatal: Couldn't XAllocColor!");
+ exit(1);
+ }
+}
+#endif /* MOTIF */
+
+/* helper routine for get_matching_parent() */
+static Widget
+matches_parent(Widget w, const char *name)
+{
+ for (; w != NULL; w = XtParent(w)) {
+ char *ptr;
+ ptr = XtName(w);
+ TRACE_GUI((stderr, "parent: %s", ptr == NULL ? "<NULL>" : ptr));
+ if (ptr != NULL && strcmp(ptr, name) == 0) { /* found */
+ TRACE_GUI((stderr, "match!"));
+ break;
+ }
+ }
+ TRACE_GUI((stderr, "returning: %p (0x%lx)", (void *)w, w ? XtWindow(w) : 0));
+ return w;
+}
+
+/* Traverse widget hieararchy upwards until a widget matches
+ a name in the (NULL-terminated) list fmt, or Widget d (`default')
+ if none is found.
+*/
+Widget
+get_matching_parent(Widget w, Widget d, const char *fmt, ...)
+{
+ Widget parent = d;
+ const char *str = fmt;
+
+ va_list argp;
+ va_start(argp, fmt);
+
+ TRACE_GUI((stderr, "get_matching_parent of %p (0x%lx)", (void *)w, XtWindow(w)));
+ while (str != NULL) {
+ Widget p;
+ if ((p = matches_parent(w, str)) != NULL) {
+ parent = p;
+ break;
+ }
+ str = va_arg(argp, char *);
+ }
+
+ va_end(argp);
+
+ return parent;
+}
+
+/* Return True if p is a parent of widget w, stopping (and returning FALSE)
+ if s is reached (which should be the toplevel window of the hierarchy).
+*/
+Boolean
+widget_is_parent(Widget w, Widget p, Widget s)
+{
+ Widget curr = XtParent(w);
+ while (curr != NULL && curr != s) {
+ fprintf(stderr, "Comparing: %p - %p\n", (void *)curr, (void *)p);
+ if (curr == p)
+ return True;
+ curr = XtParent(curr);
+ }
+ return False;
+}
+
+/*
+ Adjust height in a NULL-terminated list of widgets. For Motif,
+ this works better than the following adjust_vertically().
+*/
+void
+adjust_heights(Widget w, ...)
+{
+ va_list ap;
+ Widget curr;
+ Dimension h, max;
+
+ ASSERT(w != NULL, "Must have at least one element in va_list for adjust_heights!");
+
+#if MOTIF
+#define HEIGHT XmNheight
+#else
+#define HEIGHT XtNheight
+#endif
+
+ /* initialize maximum */
+ XtVaGetValues(w, HEIGHT, &max, NULL);
+
+ /* get maximum height */
+ va_start(ap, w);
+ while ((curr = va_arg(ap, Widget)) != NULL) {
+ XtVaGetValues(curr, HEIGHT, &h, NULL);
+ if (h > max)
+ max = h;
+ }
+ va_end(ap);
+
+ /* set maximum height for all widgets */
+ XtVaSetValues(w, HEIGHT, max, NULL);
+
+ va_start(ap, w);
+ while ((curr = va_arg(ap, Widget)) != NULL)
+ XtVaSetValues(curr, HEIGHT, max, NULL);
+ va_end(ap);
+
+#undef HEIGHT
+
+}
+
+/*
+ Adjust height in a NULL-terminated list of widgets. For Motif,
+ this works better than the following adjust_vertically().
+*/
+void
+adjust_heights_min(Widget w, ...)
+{
+ va_list ap;
+ Widget curr;
+ Dimension h, min;
+
+ ASSERT(w != NULL, "Must have at least one element in va_list for adjust_heights!");
+
+#if MOTIF
+#define HEIGHT XmNheight
+#else
+#define HEIGHT XtNheight
+#endif
+
+ /* initialize minimum */
+ XtVaGetValues(w, HEIGHT, &min, NULL);
+
+ /* get minimum height */
+ va_start(ap, w);
+ while ((curr = va_arg(ap, Widget)) != NULL) {
+ XtVaGetValues(curr, HEIGHT, &h, NULL);
+ if (h < min)
+ min = h;
+ }
+ va_end(ap);
+
+ /* set maximum height for all widgets */
+ XtVaSetValues(w, HEIGHT, min, NULL);
+
+ va_start(ap, w);
+ while ((curr = va_arg(ap, Widget)) != NULL)
+ XtVaSetValues(curr, HEIGHT, min, NULL);
+ va_end(ap);
+
+#undef HEIGHT
+
+}
+
+/* adjust two widgets vertically */
+void
+adjust_vertically(Widget w1, Widget w2, int default_dist)
+{
+ Dimension h1, h2;
+#if MOTIF
+ XtVaGetValues(w1, XmNheight, &h1, NULL);
+ XtVaGetValues(w2, XmNheight, &h2, NULL);
+ XtVaSetValues(w1, XmNtopOffset, default_dist + (h2 - h1) / 2, NULL);
+ /* XtVaSetValues(w2, XmNtopOffset, default_dist + (h2 - h1) / 2, NULL); */
+#else
+ XtVaGetValues(w1, XtNheight, &h1, NULL);
+ XtVaGetValues(w2, XtNheight, &h2, NULL);
+ XtVaSetValues(w1, XtNvertDistance, default_dist + (h2 - h1) / 2, NULL);
+ XtVaSetValues(w2, XtNvertDistance, default_dist + (h2 - h1) / 2, NULL);
+#endif /* MOTIF */
+}
+
+
+/*
+ * This is a hack to block further processing of some events on widgets:
+ * Add as an event handler for all mouse/key events for a specific widget.
+ */
+void
+block_event_callback(Widget w, XtPointer client_data,
+ XEvent *ev, Boolean *cont)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(ev);
+
+ /* Don't propagate this event further down... */
+ *cont = False;
+
+ return;
+}
+
+
+/* Get a widget with `name' somewhere in the widget hierarchy below `parent'
+ (matching is done against `*name') and return it in `ret'.
+ If `report_error' is True, a warning message is popped up if the widget isn't found.
+*/
+Boolean
+get_widget_by_name(Widget *ret, Widget parent, const char *name, Boolean report_error)
+{
+ char buf[1024];
+ Widget test;
+
+/* if (parent == 0 || !XtIsManaged(parent)) { */
+/* fprintf(stderr, "Widget %p not managed!\n", parent); */
+/* return False; */
+/* } */
+
+ if (strlen(name) > 1023) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "Widget name `%s' too long, couldn't get parent", name);
+ return False;
+ }
+
+ buf[0] = '*'; /* add wildcard to also match paths */
+ strcpy(buf + 1, name);
+
+ if ((test = XtNameToWidget(parent, buf)) != NULL) {
+ *ret = test;
+ return True;
+ }
+ else {
+ if (report_error)
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "XtNameToWidget failed for `%s', parent `%s'", name, XtName(parent));
+ return False;
+ }
+}
+
+void
+unexpected_widget_in_callback(Widget w, const char *callback)
+{
+ ASSERT(w != NULL, "Widget mustn't be NULL!");
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "Unexpected widget `%s' in callback `%s'",
+ XtName(w), callback);
+}
+
+static XrmDatabase m_user_db = NULL;
+
+/*
+ * Merge the resource `name' with a value specified by `fmt' into
+ * the database `db' (if db == NULL, use m_user_db).
+ */
+void
+store_preference(XrmDatabase *db, const char *name, const char *fmt, ...)
+{
+ size_t offset = strlen("xdvi.");
+ size_t name_len = strlen(name);
+ char *name_buf = xmalloc(name_len + offset + 1);
+ char *buf = NULL;
+ XrmDatabase tmp_db = NULL;
+
+ if (db == NULL)
+ db = &m_user_db;
+
+ XDVI_GET_STRING_ARGP(buf, fmt);
+
+ memcpy(name_buf, "xdvi.", offset);
+ strcpy(name_buf + offset, name);
+
+ TRACE_GUI((stderr, "storing resource: `%s: %s'", name_buf, buf));
+ XrmPutStringResource(&tmp_db, name_buf, buf);
+ XrmMergeDatabases(tmp_db, db);
+
+ free(buf);
+ free(name_buf);
+}
+
+void
+merge_into_user_db(XrmDatabase db)
+{
+ XrmMergeDatabases(db, &m_user_db);
+}
+
+const char *const xdvirc_filename = ".xdvirc";
+const char *const xdvirc_signature_line = "!!! ~/.xdvirc, used by xdvi(1) to save user preferences.\n";
+const char *const xdvirc_header = ""
+ "!!!\n"
+ "!!! Do not edit this file, it will be overwritten by xdvi.\n"
+ "!!! This file contains resources that have been set via the\n"
+ "!!! menus/dialogs. The contents of this file will override\n"
+ "!!! the entries in your ~/.Xdefaults file (but not the command\n"
+ "!!! line arguments passed to xdvi). Remove this file\n"
+ "!!! if you want to get rid of all these customizations,\n"
+ "!!! or start xdvi with the `-q' option to ignore this file.\n"
+ "!!!\n";
+
+static char *
+get_xdvirc_path(const char *basename)
+{
+ const char *homedir;
+ size_t len;
+ char *str;
+
+ if (basename == NULL)
+ return NULL;
+
+ homedir = getenv("HOME");
+ len = strlen(homedir) + strlen(basename) + 2; /* 1 more for '/' */
+ str = xmalloc(len);
+
+ sprintf(str, "%s/%s", homedir, basename);
+ return str;
+}
+
+static void
+save_geometry(void)
+{
+ int x_off, y_off;
+ Dimension w, h;
+ Window dummy;
+/* char *geom_str; */
+
+ (void)XTranslateCoordinates(DISP, XtWindow(globals.widgets.top_level),
+ RootWindowOfScreen(SCRN),
+ 0, 0,
+ &x_off, &y_off,
+ &dummy);
+ XtVaGetValues(globals.widgets.top_level,
+ XtNwidth, &w,
+ XtNheight, &h,
+#ifdef MOTIF
+/* XmNgeometry, &geom_str, */
+#endif
+ NULL);
+ TRACE_GUI((stderr, "geometry: %dx%d+%d+%d", w, h, x_off, y_off));
+
+ store_preference(NULL, "windowSize", "%dx%d", w, h);
+}
+
+/* Save user preferences to ~/.xdvirc. If `backup_only' is True,
+ it only writes to ~/.xdvirc.tmp and does not remove this temporary
+ file (this is used for synchronization between several xdvi instances).
+*/
+Boolean
+save_user_preferences(Boolean full_save)
+{
+ char testbuf[1024];
+ char *xdvirc_name;
+ char *tmpname;
+ FILE *from_fp, *to_fp;
+ int fd;
+
+ if (resource.no_init_file
+ || m_user_db == NULL) /* nothing to do */
+ return True;
+
+ if (resource.remember_windowsize)
+ save_geometry();
+
+ xdvirc_name = get_xdvirc_path(xdvirc_filename);
+
+ if ((to_fp = fopen(xdvirc_name, "r")) != NULL) {
+ TRACE_GUI((stderr, "~/.xdvirc exists, checking file contents ..."));
+ if (fgets(testbuf, 1024, to_fp) != NULL &&
+ memcmp(testbuf, xdvirc_signature_line, strlen(xdvirc_signature_line)) != 0) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ "Xdvi uses the file ~/.xdvirc to save the preferences set via "
+ "the menu bar or the preferences dialog (in the Motif version only). "
+ "To avoid overwriting files created by the user, the first line of the "
+ "file is compared with a special signature line. If that signature line "
+ "is not found, the preferences won't be written. Your file doesn't seem "
+ "to contain that signature line. You should move the file to a safe location, "
+ "and then try to quit xdvi again.",
+ /* message */
+ "The file `%s' was apparently not written by xdvi(k). "
+ "Please move or delete this file first, then try to exit xdvi again. ",
+ xdvirc_name);
+ return False;
+ }
+ fclose(to_fp);
+ }
+
+ /* don't use xdvi_temp_fd here, since XrmPutFileDatabase()
+ closes the FILE*, creating a temp race */
+ tmpname = xstrdup(xdvirc_name);
+ tmpname = xstrcat(tmpname, ".tmp");
+
+ /* since XrmPutFileDatabase doesn't give a useful error message if it fails,
+ check that creating the file works beforehand. The file is created with 0600 permissions. */
+ if ((fd = try_open_mode(tmpname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
+ XDVI_ERROR((stderr, "Could not save preferences!\nOpening %s for writing failed: %s", tmpname, strerror(errno)));
+ return True;
+ }
+ close(fd);
+
+ XrmPutFileDatabase(m_user_db, tmpname);
+
+ if (full_save) {
+ if ((from_fp = try_fopen(tmpname, "r")) == NULL) {
+ XDVI_ERROR((stderr, "Could not save preferences!\nOpening %s for reading failed: %s", tmpname, strerror(errno)));
+ return True;
+ }
+
+ /* again, create the file with 600 permissions */
+ if ((fd = try_open_mode(xdvirc_name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
+ XDVI_ERROR((stderr, "Could not save preferences!\nOpening %s for writing failed: %s", xdvirc_name, strerror(errno)));
+ return True;
+ }
+
+ if ((to_fp = fdopen(fd, "w")) == NULL) {
+ XDVI_ERROR((stderr, "Could not save preferences!\nfdopen for %s for writing failed: %s", xdvirc_name, strerror(errno)));
+ return True;
+ }
+
+ if (fputs(xdvirc_signature_line, to_fp) == EOF
+ || fputs(xdvirc_header, to_fp) == EOF
+ || !copy_fp(from_fp, to_fp)) {
+ XDVI_ERROR((stderr, "Could not save preferences!\nError writing to %s: %s", xdvirc_name, strerror(errno)));
+ }
+
+ fclose(from_fp);
+ fclose(to_fp);
+ }
+
+ free(xdvirc_name);
+
+ if (full_save)
+ unlink(tmpname);
+ free(tmpname);
+
+ return True;
+}
+
+/*
+ * Read the user preferences from xdvirc_filename and merge them into the
+ * current resource database *and* into m_user_db so that all of them are
+ * saved again when xdvi exits.
+ */
+void
+read_user_preferences(Widget toplevel, const char *filename)
+{
+ char *fullpath;
+ XrmDatabase db;
+#if XtSpecificationRelease == 4
+ XrmDatabase file_db;
+#endif
+
+ fullpath = get_xdvirc_path(filename);
+ TRACE_GUI((stderr, "Reading resources from `%s'", fullpath));
+ db = XtDatabase(XtDisplay(toplevel));
+
+#if XtSpecificationRelease == 4
+ file_db = XrmGetFileDatabase(fullpath);
+ XrmMergeDatabases(file_db, &db);
+ XrmMergeDatabases(file_db, &m_user_db);
+#else /* Xt >= X11R5 */
+ XrmCombineFileDatabase(fullpath, &db, True);
+ XrmCombineFileDatabase(fullpath, &m_user_db, True);
+#endif
+ free(fullpath);
+}
+
+
+/*
+ * Routines for running as source-special client.
+ */
+
+static unsigned long xdvi_next_request = 0;
+static int xerrno;
+static int (*XdviOldErrorHandler)(Display *, XErrorEvent *);
+
+static int
+XdviErrorHandler(Display *d, XErrorEvent *event)
+{
+ if (event->serial != xdvi_next_request || event->error_code != BadWindow)
+ return XdviOldErrorHandler(d, event);
+
+ xerrno = 1;
+ return 0;
+}
+
+static int
+XdviGetWindowProperty(Display *display,
+ Window w,
+ Atom property,
+ long long_offset,
+ long long_length,
+ Bool delete,
+ Atom req_type,
+ Atom *actual_type_return,
+ int *actual_format_return,
+ unsigned long *nitems_return,
+ unsigned long *bytes_after_return,
+ unsigned char **prop_return)
+{
+ int retval;
+
+ xdvi_next_request = NextRequest(display);
+ xerrno = 0;
+
+ retval = XGetWindowProperty(display, w, property, long_offset,
+ long_length, delete, req_type,
+ actual_type_return, actual_format_return,
+ nitems_return, bytes_after_return, prop_return);
+
+ return (xerrno != 0 ? BadWindow : retval);
+}
+
+/* helper function to set a string property of type `prop' for window `win' */
+void
+set_string_property(const char *str, Atom prop, Window win)
+{
+ XChangeProperty(DISP, win, prop, prop, 8, PropModeReplace,
+ (const unsigned char *)str, strlen(str));
+ XFlush(DISP); /* necessary to get the property set */
+}
+
+/*
+ * Check for another running copy of xdvi. If same_file is true, return
+ * the window ID of that other instance only if it has currently loaded the
+ * same file; else, return 0.
+ * If same_file is false, return the first valid xdvi window ID.
+ */
+Window
+get_xdvi_window_id(Boolean same_file, property_cbT callback)
+{
+ char *window_list;
+ size_t window_list_len;
+ char *window_list_end;
+ char *wp;
+ char *p;
+ Boolean need_rewrite = False;
+ Window ret_window = 0;
+
+ /*
+ * Get window list. Copy it over (we'll be calling property_get_data()
+ * again).
+ */
+ if ((window_list_len = property_get_window_list(&p)) == 0)
+ return 0;
+
+ window_list = xmalloc(window_list_len);
+ memcpy(window_list, p, window_list_len);
+
+ XdviOldErrorHandler = XSetErrorHandler(XdviErrorHandler);
+
+ /* Loop over list of windows. */
+
+ window_list_end = window_list + window_list_len;
+ TRACE_CLIENT((stderr, "My property: `%s'", dvi_property));
+
+ for (wp = window_list; wp < window_list_end; wp += 4) {
+ Window w;
+ char *buf_ret;
+ size_t len;
+
+ w = get_window_id(wp);
+
+ TRACE_CLIENT((stderr, "Checking window %08lx", w));
+
+ len = property_get_data(w, atom_dvi_file(), &buf_ret,
+ XdviGetWindowProperty);
+
+ if (len == 0) {
+ /* not getting back info for a window usually indicates
+ that the application the window had belonged to had
+ been killed with signal 9
+ */
+ TRACE_CLIENT((stderr, "Window %08lx: doesn't exist any more, deleting", w));
+ window_list_len -= 4;
+ window_list_end -= 4;
+ memmove(wp, wp + 4, window_list_end - wp);
+ wp -= 4; /* new item is now at wp; don't skip it in next iteration */
+ need_rewrite = True;
+ continue;
+ }
+ else { /* window still alive */
+ if (globals.debug & DBG_CLIENT) {
+#if 0
+ unsigned long ino;
+ int i;
+
+ ino = 0;
+ for (i = 7; i >= 0; --i)
+ ino = (ino << 8) | (unsigned char)(buf_ret[i]);
+#endif
+ TRACE_CLIENT((stderr, "Window %08lx: property: `%s'", w, buf_ret));
+ }
+
+ /* invoke callback if given */
+ if (callback != NULL) {
+ callback(w);
+ }
+
+ if (!same_file && ret_window == 0) {
+ ret_window = w;
+ if (callback == 0) /* can return early */
+ break;
+ }
+ else if (strcmp(buf_ret, dvi_property) == 0 && ret_window == 0) { /* match */
+ ret_window = w;
+ if (callback == 0) /* can return early */
+ break;
+ }
+ }
+ }
+
+ XSetErrorHandler(XdviOldErrorHandler);
+
+ if (need_rewrite)
+ XChangeProperty(DISP, DefaultRootWindow(DISP),
+ atom_xdvi_windows(), atom_xdvi_windows(), 32,
+ PropModeReplace, (unsigned char *)window_list,
+ window_list_len / 4);
+
+ return ret_window;
+}
+
+Boolean
+clip_region(int *x, int *y, int *w, int *h)
+{
+#if 0
+ fprintf(stderr, "globals.win_expose.min_x: %d, globals.win_expose.max_x: %d, "
+ "globals.win_expose.min_y: %d, globals.win_expose.max_y: %d\n",
+ globals.win_expose.min_x, globals.win_expose.max_x,
+ globals.win_expose.min_y, globals.win_expose.max_y);
+#endif
+ /* check for <= so that we also return false if *w or *h == 0 */
+ if (*x + *w <= globals.win_expose.min_x
+ || *x >= globals.win_expose.max_x
+ || *y + *h <= globals.win_expose.min_y
+ || *y >= globals.win_expose.max_y
+ /* extra protection agains *w or *h == 0; don't know if this can actually happen ... */
+ || globals.win_expose.max_y == globals.win_expose.min_y
+ || globals.win_expose.max_x == globals.win_expose.min_x) {
+ return False;
+ }
+ if (*x < globals.win_expose.min_x) {
+ *w -= globals.win_expose.min_x - *x;
+ *x = globals.win_expose.min_x;
+ }
+ if (*x + *w > globals.win_expose.max_x) {
+ *w = globals.win_expose.max_x - *x;
+ }
+ if (*y < globals.win_expose.min_y) {
+ *h -= globals.win_expose.min_y - *y;
+ *y = globals.win_expose.min_y;
+ }
+ if (*y + *h > globals.win_expose.max_y) {
+ *h = globals.win_expose.max_y - *y;
+ }
+ return True;
+}
+
+Boolean
+clip_region_to_rect(XRectangle *rect)
+{
+ int x = rect->x;
+ int y = rect->y;
+ int w = rect->width;
+ int h = rect->height;
+ Boolean ret = clip_region(&x, &y, &w, &h);
+ if (ret) {
+ rect->x = x;
+ rect->y = y;
+ rect->width = w;
+ rect->height = h;
+ }
+ return ret;
+}
+
diff --git a/Build/source/texk/xdvik/x_util.h b/Build/source/texk/xdvik/x_util.h
new file mode 100644
index 00000000000..8ea92be5d29
--- /dev/null
+++ b/Build/source/texk/xdvik/x_util.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ */
+
+#ifndef X_UTIL_H_
+#define X_UTIL_H_
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include "xdvi.h"
+
+/* nasty globals */
+/*
+ Whether program should autoscroll to make href target marker or
+ forward search marker visible.
+ This is disabled by ordinary user scrolling (otherwise xdvi would
+ jump back to the old place, undoing the user scroll), so we need
+ global access to it.
+ */
+extern Boolean do_autoscroll;
+
+
+extern void center_window(Widget w1, Widget w2);
+extern void position_window(Widget w, Position x, Position y);
+extern void scroll_page_if_needed(int x_min, int x_max, int y_min, int y_max);
+extern void adjust_width(Widget a, Widget b);
+extern GC set_or_make_gc(GC gc, int function, Pixel fg, Pixel bg);
+
+extern size_t property_get_data(Window, Atom, char **,
+ int (*x_get_property) (Display *, Window, Atom, long,
+ long, Bool, Atom, Atom *, int *, unsigned long *,
+ unsigned long *, unsigned char **));
+
+extern size_t property_get_window_list(char **window_list);
+extern void set_dvi_property(void);
+extern void set_window_id(Window w, unsigned char *data);
+extern Window get_window_id(char *window_p);
+extern void update_window_property(Window w, Boolean prepend);
+extern void update_dvi_property(void);
+extern void property_initialize(void);
+
+/*
+ * atom_xdvi_windows() is attached to the root window of the default
+ * screen of the display; it contains a list of (hopefully active)
+ * xdvi windows.
+ */
+Atom atom_xdvi_windows(void);
+
+/*
+ * atom_dvi_file() is attached to the main xdvi window; it tells the
+ * world what dvi file is being viewed. It is set by that copy of
+ * xdvi and read by this routine. The first 8 bytes are the inode
+ * number, and the rest is the file name. We use 8 instead of
+ * sizeof(ino_t) because the latter may vary from machine to machine,
+ * and the format needs to be machine independent.
+ */
+Atom atom_dvi_file(void);
+
+/* Atoms attached to the main xdvi window */
+
+/* instruct the current instance to do a forward search
+ * on the source string encoded in the property */
+Atom atom_src_goto(void);
+
+/* instruct the current instance to do a string search
+ * on the string encoded in the property */
+Atom atom_find_string(void);
+
+/* instruct the current instance to reload the current file */
+Atom atom_reload(void);
+
+/* instruct the current instance to load the new file contained in the property */
+Atom atom_newdoc(void);
+
+/* instruct the current instance to go to the page encoded in the property */
+Atom atom_newpage(void);
+
+/* instruct the current instance to raise its window */
+Atom atom_raise(void);
+
+/* instruct the current instance to reread preferences from ~/.xdvirc.tmp */
+Atom atom_reread_prefs(void);
+
+extern void synthetisize_event(XEvent *ev, Widget button);
+
+#ifdef MOTIF
+extern int xm_get_height(Widget w);
+extern int xm_get_width(Widget w);
+extern void str_to_pixel(Widget w, const char *colorname, Pixel *ret);
+extern void pixel_to_str(Widget w, Pixel pix, char *str, size_t len);
+extern void pixel_to_color(Pixel pix, XColor *color, Display *display, Colormap colormap);
+#endif
+
+extern Widget get_matching_parent(Widget w, Widget p, const char *fmt, ...);
+extern Boolean widget_is_parent(Widget w, Widget p, Widget s);
+
+extern void adjust_vertically(Widget w1, Widget w2, int default_dist);
+extern void adjust_heights(Widget w1, ...);
+extern void adjust_heights_min(Widget w1, ...);
+/* extern void adjust_widths(Widget w1, ...); */
+
+void block_event_callback(Widget w, XtPointer client_data,
+ XEvent *ev, Boolean *cont);
+
+extern void unexpected_widget_in_callback(Widget w, const char *callback);
+extern Boolean get_widget_by_name(Widget *ret, Widget parent, const char *name, Boolean report_error);
+
+extern void merge_into_user_db(XrmDatabase db);
+extern void store_user_preference(const char *name, const char *fmt, ...);
+extern void store_preference(XrmDatabase *db, const char *name, const char *fmt, ...);
+extern Boolean save_user_preferences(Boolean full_save);
+extern void read_user_preferences(Widget toplevel, const char *filename);
+
+/* property related routines */
+typedef void (*property_cbT)(Window w);
+extern Window get_xdvi_window_id(Boolean same_file, property_cbT callback);
+extern void set_string_property(const char *str, Atom prop, Window win);
+
+extern Boolean clip_region(int *x, int *y, int *w, int *h);
+extern Boolean clip_region_to_rect(XRectangle *rect);
+
+#endif
diff --git a/Build/source/texk/xdvik/xdvi-config.h b/Build/source/texk/xdvik/xdvi-config.h
new file mode 100644
index 00000000000..0fb60e3c035
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi-config.h
@@ -0,0 +1,37 @@
+/* xdvi-config.h: master configuration file, included first by all
+ compilable source files (not headers). */
+
+#ifndef CONFIG_H_
+#define CONFIG_H_
+
+/* Some xdvi options we want by default. */
+#define USE_PK
+#define USE_GF
+#define MAKEPK
+
+/* all others are defined in this file */
+#include "c-auto.h"
+
+#ifndef HAVE_VPRINTF
+#ifdef HAVE_DOPRNT
+#define vfprintf(stream, message, args) _doprnt(message, args, stream)
+/* If we have neither, should fall back to fprintf with fixed args. */
+#endif
+#endif
+
+/* XPM is used for the toolbar buttons and in xicon.c */
+#if USE_XPM
+# if defined(HAVE_X11_XPM_H) || defined(HAVE_XM_XPMP_H) || defined(HAVE_XPM_H)
+# define HAVE_XPM 1
+# else
+# define HAVE_XPM 0
+# endif
+#endif
+
+/* enable X server info output */
+#define XSERVER_INFO 1
+
+/* change this to 1 when #470325 is fixed */
+#define FIXED_FLUSHING_PAGING 0
+
+#endif /* not CONFIG_H_ */
diff --git a/Build/source/texk/xdvik/xdvi-debug.h b/Build/source/texk/xdvik/xdvi-debug.h
new file mode 100644
index 00000000000..10eacefa87b
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi-debug.h
@@ -0,0 +1,218 @@
+#ifndef XDVI_DEBUG_H_
+#define XDVI_DEBUG_H_
+
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * 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.
+ *
+ */
+
+/* debugging flags and macros */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+
+#if HAVE_STRINGIZE
+#ifdef NDEBUG
+/* for production code, a failed ASSERT(x) just prints out a warning;
+ else it aborts and dumps core.
+*/
+#define ASSERT(x, y) do { \
+ if(!(x)) { \
+ fprintf(stderr, \
+ "************************************************************\n" \
+ "XDvi %s: Failed assertion:\n%s:%d: \"%s\": %s\n" \
+ "Please report this as a bug to:\n" \
+ "http://sourceforge.net/tracker/?group_id=23164&atid=377580\n" \
+ "************************************************************\n", \
+ XDVI_VERSION_INFO, __FILE__, __LINE__, #x, y); \
+ } } while (0)
+#else /* NDEBUG */
+#define ASSERT(x, y) do { \
+ if(!(x)) { \
+ fprintf(stderr, \
+ "\n************************************************************\n" \
+ "XDvi %s: Failed assertion:\n%s:%d: \"%s\": %s\n" \
+ "Aborting now. Please report this as a bug to:\n" \
+ "http://sourceforge.net/tracker/?group_id=23164&atid=377580\n" \
+ "If a core dump has been produced, please invoke:\n" \
+ "gdb %s core\nThen type \"bt\", " \
+ "and include the resulting output in your bug report.\n" \
+ "************************************************************\n", \
+ XDVI_VERSION_INFO, __FILE__, __LINE__, #x, y, globals.program_name); \
+ do_abort(); \
+ } } while (0)
+#endif /* NDEBUG */
+#else /* HAVE_STRINGIZE */
+#define ASSERT(x, y) /* as nothing */
+#endif
+
+/* for temporary debugging statements */
+/* #define MYDEBUG 1 */
+#ifdef MYDEBUG
+# define MYTRACE(X) do { \
+ fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+} while(0)
+#else
+# define MYTRACE(X)
+#endif
+
+/* NOTE: keep these in sync with the debug_string_options array in util.c! */
+#define DBG_BITMAP 1
+#define DBG_DVI 2
+#define DBG_PK 4
+#define DBG_BATCH 8
+#define DBG_EVENT 16
+#define DBG_PS 32
+/* start of kpathsea debugging options */
+#define DBG_STAT 64
+#define DBG_HASH 128
+#define DBG_OPEN 256
+#define DBG_PATHS 512
+#define DBG_EXPAND 1024
+#define DBG_SEARCH 2048
+#define DBG_KPATHSEA 4032 /* handy abbrev */
+/* end of kpathsea debugging options */
+#define DBG_HTEX 4096
+#define DBG_SRC_SPECIALS 8192
+#define DBG_CLIENT 16384
+#define DBG_T1 32768
+#define DBG_T1_VERBOSE 65536
+#define DBG_GUI 131072
+#define DBG_FIND 262144
+#define DBG_FILES 524288
+#define DBG_ALL (~DBG_BATCH)
+
+/* a mapping of numerical options to descriptive strings, defined in util.c */
+struct debug_string_options {
+ int bitmap;
+ const char *description;
+ const char *help_formatting;
+};
+
+/*
+ */
+
+#if 0
+/* we don't want this defined for NDEBUG, since the tracing macros
+ are pretty useful also for users reporting bugs etc.; so we
+ enable them always.
+*/
+#define TRACE_HTEX(X)
+#define TRACE_SRC(X)
+#define TRACE_CLIENT(X)
+#define TRACE_T1(X)
+#define TRACE_T1_VERBOSE(X)
+#define TRACE_GUI(X)
+#define TRACE_EVENTS(X)
+#define TRACE_FIND(X)
+#define TRACE_FILES(X)
+
+#else /* 0 */
+
+/*
+ * Note that the argument to these macros is always ((stderr, "...")).
+ * We could also have
+ * TRACE_SRC(("..."));
+ * and invoke a function, but then gcc (3.1) won't be able to check
+ * inconsistencies between conversion specifiers and arguments any
+ * more, and that's a real killer IMHO.
+ */
+
+#define TRACE_HTEX(X) \
+ do { \
+ if (globals.debug & DBG_HTEX) { \
+ fprintf(stderr, "%s:%d: HTEX: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_SRC(X) \
+ do { \
+ if (globals.debug & DBG_SRC_SPECIALS) { \
+ fprintf(stderr, "%s:%d: SRC: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_CLIENT(X) \
+ do { \
+ if (globals.debug & DBG_CLIENT) { \
+ fprintf(stderr, "%s:%d: CLIENT: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_T1(X) \
+ do { \
+ if (globals.debug & DBG_T1) { \
+ fprintf(stderr, "%s:%d: T1: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_T1_VERBOSE(X) \
+ do { \
+ if (globals.debug & DBG_T1_VERBOSE) { \
+ fprintf(stderr, "%s:%d: T1_VERBOSE: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_GUI(X) \
+ do { \
+ if (globals.debug & DBG_GUI) { \
+ fprintf(stderr, "%s:%d: GUI: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_EVENTS(X) \
+ do { \
+ if (globals.debug & DBG_EVENT) { \
+ fprintf(stderr, "%s:%d: EVENT: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+#define TRACE_FIND(X) \
+ do { \
+ if (globals.debug & DBG_FIND) { \
+ fprintf(stderr, "%s:%d: FIND: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+
+#define TRACE_FILES(X) \
+ do { \
+ if (globals.debug & DBG_FILES) { \
+ fprintf(stderr, "%s:%d: FILES: ", __FILE__, __LINE__); \
+ fprintf X; \
+ fprintf(stderr, "\n"); \
+ } \
+ } while(0)
+
+#endif /* 0 */
+
+#endif /* XDVI_DEBUG_H_ */
diff --git a/Build/source/texk/xdvik/xdvi-search.el b/Build/source/texk/xdvik/xdvi-search.el
new file mode 100644
index 00000000000..75e86d3bb35
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi-search.el
@@ -0,0 +1,345 @@
+;;; (X)Emacs frontend to forward search with xdvi(k).
+;;; Requires xdvi(k) >= 22.38.
+;;;
+;;; See http://xdvi.sourceforge.net/inverse-search.html and the section
+;;; `FORWARD SEARCH' in the xdvi man page for more information on forward search.
+;;;
+;;; This file is available from: http://xdvi.sourceforge.net/xdvi-search.el
+;;;
+;;; $Revision: 1.15.2.43 $, tested with Emacs 20.4 to 21.2 and Xemacs 21.1 to 21.5
+;;;
+;;; This program is free software; you can redistribute it and/or
+;;; modify it under the terms of the GNU General Public License
+;;; as published by the Free Software Foundation; either version 2
+;;; of the License, or (at your option) any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program; if not, write to the Free Software
+;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+;;;
+;;;
+;;; Usage:
+;;;
+;;; - Add this file to some place where emacs can find it
+;;; (e.g. put it into a directory ~/emacs/, which you add to your
+;;; load path by putting the following line into your .emacs file:
+;;;
+;;; (add-to-list 'load-path (expand-file-name "~/emacs/"))
+;;;
+;;; Then, add the following line to your .emacs file:
+;;;
+;;; (require 'xdvi-search)
+;;;
+;;; After compiling your .tex file with source specials activated, you should
+;;; be able to use
+;;; M-x xdvi-jump-to-line
+;;; to make xdvi jump to the current location of the cursor.
+;;;
+;;; You could also bind this command to a key, e.g. by adding
+;;; a binding to tex-mode-hook:
+;;;
+;;; (add-hook 'tex-mode-hook (lambda ()
+;;; (local-set-key "\C-c\C-j" 'xdvi-jump-to-line)))
+;;;
+;;; (without AucTeX; use LaTeX-mode-hook instead of tex-mode-hook with AucTeX.
+;;; Note that with AucTeX, C-c C-j is already bound to LaTeX-insert-item, so
+;;; you might want to use a different key combination instead.)
+;;;
+;;; - Note that with xdvik < 22.74.2, you may need to use one of the
+;;; functions xdvi-jump-to-line-fullpath() or xdvi-jump-to-line-relpath()
+;;; instead of xdvi-jump-to-line(), depending on the type of paths contained
+;;; in your \include{} commands. See the docstring of xdvi-jump-to-line()
+;;; for more information.
+;;;
+;;; Please send bug reports, improvements etc. to
+;;; <stefanulrich@users.sourceforge.net>.
+;;;
+
+
+;;;
+;;; Customizable stuff
+;;;
+(defgroup xdvi-search nil
+ "Support for inverse search with (La)TeX and DVI previewers."
+ :group 'languages)
+
+(defcustom explicit-shell-file-name nil
+ "*If non-nil, file name to use for explicitly requested inferior shell."
+ :type '(choice (const :tag "nil" nil) file)
+ :group 'xdvi-search)
+
+(defcustom xdvi-bin "xdvi"
+ "*Name of the xdvi executable."
+ :type '(choice (const "xdvi") file)
+ :group 'xdvi-search)
+
+(defcustom xdvi-logfile "~/.xdvi-log"
+ "*Write xdvi output to this file, or throw away output if set to nil."
+ :type '(choice (const :tag "nil" nil) file)
+ :group 'xdvi-search)
+
+
+;;;
+;;; global variables/constants
+;;;
+(defvar xdvi-version-number 0
+ "*Version of xdvi(k) you're using; only set this to override the built-in
+version recognition if that fails.
+The version number is computed as: major * 1000000 + minor * 1000 + patchlevel,
+where alphabetic characters are ignored; e.g. 22040000 equals version 22.40c;
+ 22077002 equals version 22.77.2.")
+
+(defvar xdvi-is-xdvik nil
+ "Whether we're really using xdvik instead of xdvi.")
+
+(defconst xdvik-new-search-version 22074001
+ "First version of xdvik to implement new search algorithm that ignores .tex suffixes and
+has a -nofork option.")
+
+
+;;;
+;;; exported functions
+;;;
+(defun xdvi-jump-to-line-fullpath ()
+ (interactive)
+ "See `xdvi-jump-to-line' for documentation."
+ (xdvi-jump-to-line 3))
+
+(defun xdvi-jump-to-line-relpath ()
+ (interactive)
+ "See `xdvi-jump-to-line' for documentation."
+ (xdvi-jump-to-line 2))
+
+(defun xdvi-jump-to-line (flag)
+ "Call xdvi to perform a `forward search' for current file and line number.
+Xdvi needs three pieces of information for this:
+
+- the current line number
+- the name of the current input file
+- the name of the master .tex file.
+
+The `master' .tex file (following AucTeX's terminology) is the same
+as `\jobname' and determines the name of the DVI file. It is either
+obtained by using AucTeX's function `TeX-master-file' or, in case
+AucTeX isn't available, by calling `xdvi-master-file-name', a function
+which tries to mimick AucTeX's behaviour to obtain this filename.
+
+For the current input file name, we need to rely on the DVI viewer to
+make a smart matching of path suffixes with the file names that
+actually occur in the specials, since specials inserted by TeX's
+`-src' option may contain absolute or relative paths, depending on
+whether TeX is called with a relative or absolute filename. (Similarly
+for srcltx.sty, which can't expand paths.)
+
+Note to users of older versions of xdvik (< 22.74.2), or non-k xdvi:
+
+There are various ways of specifying an input file path for LaTeX's
+\\input{} commands (which will end up in the source specials):
+
+ (1) Filename only: \\input{chapter1}
+ (2) Relative path name: \\input{chapters/chapter1}
+ (3) Full path name: \\input{/home/user/tex/diss/chapters/chapter1}
+
+Versions of xdvik < 22.74.2 and plain xdvi will not match pathname suffixes.
+With these versions, `xdvi-jump-to-line' will only work with variant (1);
+for (2) or (3) you will need to use one of `xdvi-jump-to-line-relpath' (for 2)
+or `xdvi-jump-to-line-fullpath' (for 3) instead.
+"
+ (interactive "P")
+ (save-excursion
+ (save-restriction
+ (widen)
+ (beginning-of-line 1)
+ (if (not flag)
+ (setq flag 1))
+ (let* (;;; Current line in file.
+ ;;; `count-lines' yields different results at beginning and in the
+ ;;; middle of a line, so we normalize by going to BOL first and
+ ;;; then adding 1
+ (curr-line (+ 1 (count-lines (point-min) (point))))
+ ;;; name of master .tex file, to be used as DVI basename:
+ (master-file (if (fboundp 'TeX-master-file)
+ (TeX-master-file t)
+ (xdvi-get-masterfile (xdvi-master-file-name))))
+ (xdvi-version-info (xdvi-get-version-number xdvi-version-number))
+ ;;; DVI file name:
+ (dvi-file (concat (file-name-sans-extension master-file) ".dvi"))
+ ;;; Current source filename
+ (filename (get-source-filename (buffer-file-name) (car xdvi-version-info) flag)))
+ (if (xdvi-has-no-inverse-search (car xdvi-version-info))
+ (error "Your xdvi version is too old; see http://xdvi.sourceforge.net/inverse-search.html for more information."))
+ (if (not (file-exists-p dvi-file))
+ (message "File %s does not exist; maybe you need to run latex first?" dvi-file)
+ (save-window-excursion
+ (if (xdvi-has-nofork (car xdvi-version-info) (car (cdr xdvi-version-info)))
+ (progn
+ (setq proc
+ (start-process "xdvi" "*xdvi output*"
+ xdvi-bin
+ "-nofork"
+ "-sourceposition"
+ (concat (int-to-string curr-line) " " filename)
+ dvi-file))
+ (set-process-sentinel proc 'xdvi-process-sentinel))
+ ;;;
+ ;;; More complicated if we don't have nofork: start a
+ ;;; subshell, since otherwise there's no way of viewing
+ ;;; the stderr/stdout output of the xdvi child process
+ ;;; without having either xdvi freezing, Emacs freezing,
+ ;;; or Emacs killing the xdvi child process (which is
+ ;;; forked when running with -sourceposition).
+ ;;;
+ ;;; Obtain the type of I/O-redirection needed for current shell:
+ (let* ((default-shell
+ (or (and (boundp 'explicit-shell-file-name) explicit-shell-file-name)
+ (getenv "ESHELL")
+ (getenv "SHELL")
+ "/bin/sh"))
+ (shell-redirection
+ (cond ((string-match "/bin/t?csh" default-shell)
+ (list ">&" ""))
+ ;; bash/ksh/sh
+ ((list ">" "2>&1")))))
+ (cond ((string-match "XEmacs" emacs-version)
+ (shell))
+ ((< emacs-major-version 21)
+ (shell))
+ ((shell "*xdvi-shell*")))
+ (comint-send-input)
+ (insert xdvi-bin
+ " -sourceposition '" (int-to-string curr-line) " " filename "' "
+ dvi-file
+ " "
+ ;;; we could probably do without the logfile, but it's an easy
+ ;;; way for toggling between /dev/null and logging.
+ (if xdvi-logfile
+ (let ((xdvi-logfile-fullname (expand-file-name xdvi-logfile)))
+ ;;; to avoid problems with `noclobber'
+ (if (file-exists-p xdvi-logfile-fullname)
+ (delete-file xdvi-logfile-fullname))
+ (car shell-redirection)
+ " "
+ xdvi-logfile-fullname
+ " "
+ (car (cdr shell-redirection))
+ )
+ )
+ " &")
+ (if xdvi-logfile
+ (message "Writing xdvi output to \"%s\"." xdvi-logfile))
+ (comint-send-input)))))))))
+
+;;;
+;;; internal functions
+;;;
+(defun xdvi-has-no-inverse-search (version)
+ (< version 22038000))
+
+(defun xdvi-has-nofork (version is-xdvik)
+ (if is-xdvik
+ ; xdvik got -nofork in version 22.74.1
+ (>= version 22074001)
+ (>= version 22061000)))
+
+(defun get-source-filename (fname version flag)
+ (if (> flag 1)
+ (if (> flag 2)
+ ;;; full path name, for use with TeX patch and when using the
+ ;;; full path in \input or \include with srcltx.sty:
+ (expand-file-name (buffer-file-name))
+ ;;; relative path name: if current path and path of master file match partly,
+ ;;; use the rest of this path; else use buffer name. This can treat both the
+ ;;; cases when a relative path is used in \input{}, or when just the filename
+ ;;; is used and the file is located in the current directory (suggested by
+ ;;; frisk@isy.liu.se).
+ (if (string-match (concat "^" (regexp-quote (file-name-directory master-file)))
+ (buffer-file-name))
+ (substring (buffer-file-name) (match-end 0))
+ (buffer-file-name)))
+ ;;; buffer file name without path:
+ (file-name-nondirectory (buffer-file-name))))
+
+(defun xdvi-get-version-number (default)
+ "Return a tuple of (version-number xdvi-is-xdvik), or (default nil) if default != 0."
+ (if (not (= default 0))
+ (list default nil)
+ (save-window-excursion
+ (switch-to-buffer "*xdvi-version*")
+ (erase-buffer)
+ (call-process xdvi-bin nil "*xdvi-version*" nil "-version")
+ (goto-char (point-min))
+ (if (not (re-search-forward "xdvi\\((?k)?\\)? version \\([0-9]+\\)\\.\\([0-9]+\\)\\(\\.\\([0-9]+\\)\\)?" nil t))
+ (error "Unable to get xdvi version number - please check value of `xdvi-bin', or set it manually via `xdvi-version-number'.")
+ (let* ((major (string-to-int (buffer-substring (match-beginning 2) (match-end 2))))
+ (minor (string-to-int (buffer-substring (match-beginning 3) (match-end 3))))
+ (patchlevel (if (match-beginning 5)
+ (string-to-int (buffer-substring (match-beginning 5) (match-end 5)))
+ 0))
+ (xdvi-is-xdvik (if (match-beginning 1) t nil))
+ (version (+ (* 1000 minor) (* 1000000 major) patchlevel)))
+ (kill-buffer "*xdvi-version*")
+;;; (message "Xdvi%s version: major %d, minor %d, version %d" (if xdvi-is-xdvik "k" "") major minor version)
+ (list version xdvi-is-xdvik)
+ )))))
+
+(defun xdvi-process-sentinel (process signal)
+ (let ((retmsg (substring signal 0 -1)))
+ (if (string-match "abnormally" retmsg)
+ (progn
+ (message "XDvi: %s" retmsg)
+ (pop-to-buffer (process-buffer process)))
+ (message "XDvi: %s" retmsg))))
+
+(defun xdvi-get-masterfile (file)
+ "Small helper function for AucTeX compatibility.
+Converts the special value t that TeX-master might be set to
+into a real file name."
+ (if (eq file t)
+ (buffer-file-name)
+ file))
+
+
+(defun xdvi-master-file-name ()
+ "Emulate AucTeX's TeX-master-file function.
+Partly copied from tex.el's TeX-master-file and TeX-add-local-master."
+ (if (boundp 'TeX-master)
+ TeX-master
+ (let ((master-file (read-file-name "Master file (default this file): ")))
+ (if (y-or-n-p "Save info as local variable? ")
+ (progn
+ (goto-char (point-max))
+ (if (re-search-backward "^\\([^\n]+\\)Local Variables:" nil t)
+ (let* ((prefix (if (match-beginning 1)
+ (buffer-substring (match-beginning 1) (match-end 1))
+ ""))
+ (start (point)))
+ (re-search-forward (regexp-quote (concat prefix "End:")) nil t)
+ (if (re-search-backward (regexp-quote (concat prefix "TeX-master")) start t)
+ ;;; if TeX-master line exists already, replace it
+ (progn
+ (beginning-of-line 1)
+ (kill-line 1))
+ (beginning-of-line 1))
+ (insert prefix "TeX-master: " (prin1-to-string master-file) "\n"))
+ (insert "\n%%% Local Variables: "
+;;; mode is of little use without AucTeX ...
+;;; "\n%%% mode: " (substring (symbol-name major-mode) 0 -5)
+ "\n%%% TeX-master: " (prin1-to-string master-file)
+ "\n%%% End: \n"))
+ (save-buffer)
+ (message "(local variables written.)"))
+ (message "(nothing written.)"))
+ (set (make-local-variable 'TeX-master) master-file))))
+
+
+(provide 'xdvi-search)
+
+;;; page break to avoid "Local variables entry is missing the prefix" error for previous stuff
+
+
+;;; xdvi-search.el ends here
diff --git a/Build/source/texk/xdvik/xdvi-sh.in b/Build/source/texk/xdvik/xdvi-sh.in
new file mode 100755
index 00000000000..6f77a666bc9
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi-sh.in
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# This is the xdvi wrapper script for teTeX, version 0.2.
+# Copyright Thomas Esser, 1998. Permission to distribute under the terms
+# of the GNU general public license version 2 or later.
+
+# This script sets some environment variables to make sure that xdvi's
+# resource file in $XDVIINPUTS/xdvi is read by xdvi.bin.
+
+test -f /bin/sh5 && test -z "$RUNNING_SH5" \
+ && test x"`(uname -s) 2>&1`" = xULTRIX \
+ && { RUNNING_SH5=true; export RUNNING_SH5; exec /bin/sh5 $0 ${1+"$@"}; }
+RUNNING_SH5=
+
+test -f /bin/bsh && test -z "$RUNNING_BSH" \
+ && test x"`(uname -s) 2>&1`" = xAIX \
+ && { RUNNING_BSH=true; export RUNNING_BSH; exec /bin/bsh $0 ${1+"$@"}; }
+RUNNING_BSH=
+
+# -help and -version only work if they are the only options. Therefore,
+# we cannot give the "-name xdvi" parameter in that case.
+# SU: Actually, with current xdvik, they should work in any position; but
+# we may keep this for compatibility with older versions and non-k xdvi.
+case "$#:$1" in
+ 1:-help|1:-version)
+ NAMEOPT=;;
+ *)
+ NAMEOPT='-name xdvi';;
+esac
+
+xdviappfile=`kpsewhich -progname=xdvi --format='other text files' XDvi`
+if test -n "$xdviappfile"; then
+ xdviappdir=`dirname "$xdviappfile"`
+ xdviapppath="${xdviappdir}/%l_%t/%N:${xdviappdir}/%N"
+
+ # For R3, we have to set XAPPLRESDIR.
+ ### SU: removed, xdvik won't work with R3 anyway, and XAPPLRESDIR is
+ ### for user customizations in current X
+ ### XAPPLRESDIR="$xdviappdir"; export XAPPLRESDIR
+
+ # For R4 or later, we have to set XFILESEARCHPATH, since XAPPLRESDIR might
+ # be ignored (if XUSERFILESEARCHPATH is set)
+ XFILESEARCHPATH="$xdviapppath:${XFILESEARCHPATH-%D}"; export XFILESEARCHPATH
+fi
+
+exec @final_exec_name@ $NAMEOPT ${1+"$@"}
diff --git a/Build/source/texk/xdvik/xdvi.1.in b/Build/source/texk/xdvik/xdvi.1.in
new file mode 100644
index 00000000000..6c75cec79bd
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi.1.in
@@ -0,0 +1,4284 @@
+.\" Copyright (c) 1990-2004 Paul Vojta and others
+.\"
+.\" This is Paul's license, included here only for reference, it does not apply
+.\" to all parts of the k version.
+.\" ----
+.\" 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.
+.\" ----
+.\" This is the xdvik license:
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" following is UGLY ... use La\*(Te\& instead:
+.\" .if t .ds La L\\h'-0.1667m'\\v'-0.20v'A\\v'0.20v'\\h'-0.1667m'T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.\" .if n .ds La LaTeX
+.if t .ds Te T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.if n .ds Te TeX
+' # small and boldface (not all -man's provide it)
+.de SB
+\&\fB\s-1\&\\$1 \\$2\s0\fR
+..
+.TH XDVI 1 "@XDVI_DATE@" "Xdvik @XDVI_VERSION@"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+xdvi \- DVI Previewer for the X Window System
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.B xdvi
+.nh
+[\fB+\fP[\fIpage\fP]]
+[\fB\--help\fP]
+#ifps
+[\fB\-allowshell\fP]
+#endif
+[\fB\-altfont\fP \fIfont\fP]
+[\fB\-base\fP \fIbase URL\fP]
+.\" [\fB\-bd\fP \fIcolor\fP]
+[\fB\-bg\fP \fIcolor\fP]
+[\fB\-browser\fP \fIWWWbrowser\fP]
+[\fB\-bw\fP \fIwidth\fP]
+[\fB\-bw\fP \fIwidth\fP]
+[\fB\-copy\fP]
+[\fB\-cr\fP \fIcolor\fP]
+[\fB\-debug\fP \fIbitmask\fP|\fIstring[,string ...]\fP]
+[\fB\-display\fP \fIhost:display\fP]
+[\fB\-dvipspath\fP \fIpath\fP]
+[\fB\-editor\fP \fIcommand\fP]
+[\fB\-expertmode\fP \fIflag\fP]
+[\fB\-fg\fP \fIcolor\fP]
+[\fB\-findstring\fP \fIstring\fP]
+[\fB\-font\fP \fIfont\fP]
+[\fB\-fullscreen \fP]
+#ifgrey
+[\fB\-gamma\fP \fIg\fP]
+#endif
+[\fB\-geometry\fP \fIgeometry\fP]
+#ifghost
+[\fB\-gsalpha\fP]
+#endif
+#ifghost
+[\fB\-gspalette\fP \fIpalette\fP]
+#endif
+[\fB\-h\fP]
+[\fB\-help\fP]
+[\fB\-hl\fP \fIcolor\fP]
+[\fB\-href\fP \fIanchor\fP]
+[\fB\-hush\fP]
+[\fB\-hushchars\fP]
+[\fB\-hushchecksums\fP]
+[\fB\-hushspecials\fP]
+[\fB\-hushstdout\fP]
+[\fB\-icongeometry\fP \fIgeometry\fP]
+[\fB\-iconic\fP]
+#ifgrey
+[\fB\-install\fP]
+#endif
+#ifghost
+[\fB\-interpreter\fP \fIpath\fP]
+#endif
+[\fB\-keep\fP]
+[\fB\-l\fP]
+[\fB\-linkcolor\fP \fIcolor\fP]
+[\fB\-linkstyle\fP \fI0|1|2|3\fP]
+[\fB\-margins\fP \fIdimen\fP]
+#ifkpathsea
+[\fB\-mfmode\fP \fImode-def\fP[\fB:\fP\fIdpi\fP]]
+#endif
+#ifnokpathsea
+[\fB\-mfmode\fP \fImode-def\fP]
+#endif
+[\fB\-mgs\fP[\fIn\fP] \fIsize\fP]
+[\fB\-mousemode\fP \fI0|1|2\fP]
+#ifcolor
+[\fB\-nocolor\fP]
+#endif
+#ifdps
+[\fB\-nodps\fP]
+#endif
+[\fB\-nofork\fP]
+#ifghost
+[\fB\-noghostscript\fP]
+#endif
+#ifgrey
+[\fB\-nogrey\fP]
+#endif
+#ifghost
+[\fB\-nogssafer\fP]
+#endif
+#ifgrey
+[\fB\-noinstall\fP]
+#endif
+#ifmakepk
+[\fB\-nomakepk\fP]
+#endif
+[\fB\-nomatchinverted\fP]
+#ifnews
+[\fB\-nonews\fP]
+#endif
+[\fB\-noomega\fP]
+[\fB\-noscan\fP]
+#ift1
+[\fB\-not1lib\fP]
+#endif
+[\fB\-notempfile\fP]
+[\fB\-offsets\fP \fIdimen\fP]
+[\fB\-p\fP \fIpixels\fP]
+[\fB\-paper\fP \fIpapertype\fP]
+[\fB\-pause\fP]
+[\fB\-pausespecial\fP \fIspecial-string\fP]
+#ifps
+[\fB\-postscript\fP \fIflag\fP]
+#endif
+[\fB\-rulecolor\fP \fIcolor\fP]
+[\fB\-rv\fP]
+[\fB\-S\fP \fIdensity\fP]
+[\fB\-s\fP \fIshrink\fP]
+[\fB\-safer\fP]
+[\fB\-sidemargin\fP \fIdimen\fP]
+[\fB\-sourceposition\fP \fIline\fP[\fB:\fP\fIcol\fP][\ ]\fIfilename\fP]
+[\fB\-statusline\fP]
+[\fB\-thorough\fP]
+[\fB\-topmargin\fP \fIdimen\fP]
+[\fB\-unique\fP]
+[\fB\-version\fP]
+[\fB\-visitedlinkcolor\fP \fIcolor\fP]
+[\fB\-warnspecials\fP]
+[\fB\-watchfile\fP \fIsecs\fP]
+[\fB\-wheelunit\fP \fIpixels\fP]
+[\fB\-xoffset\fP \fIdimen\fP]
+[\fB\-yoffset\fP \fIdimen\fP]
+[\fIdvi_file\fP]
+.hy
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.B Xdvi
+is a program for previewing
+.I dvi
+files, as produced e.g. by the
+.BR tex (1)
+program, under the X window system.
+.PP
+.B Xdvi
+can show the file shrunken by various
+integer factors, and it has a ``magnifying glass'' for viewing
+parts of the page enlarged (see the section MAGNIFIER below). This version
+of
+.B xdvi
+is also referred to as
+.B xdvik
+since it uses the kpathsea library to locate and generate font files.
+In addition to that, it supports the following features:
+.RS 2
+.TP 2
+-
+hyperlinks in DVI files (section HYPERLINKS),
+.TP
+-
+#ift1
+direct rendering of Postscript<tm> Type1 fonts (section T1LIB),
+.TP
+-
+#endif
+source specials in the DVI file (section SOURCE SPECIALS),
+.TP
+-
+string search in DVI files (section STRING SEARCH),
+.TP
+-
+saving or printing (parts of) the DVI file (sections PRINT DIALOG and SAVE DIALOG).
+.RE
+.PP
+Xdvi can be compiled with the Motif toolkit or the Xaw (Athena) toolkit
+(and variants of it), and the Motif version has a slightly different GUI;
+these differences are noted below.
+.PP
+Before displaying a page of a DVI file,
+.B xdvi
+will check to see if the file has changed since the last time it was
+displayed. If this is the case, it will reload the file. This
+feature allows you to preview many versions of the same file while
+running
+.B xdvi
+only once. Since it cannot read partial DVI files,
+.B xdvik
+versions starting from 22.74.3 will create a temporary copy of the
+DVI file being viewed, to ensure that the file can be viewed without
+interruptions. (The
+.B \-notempfile
+can be used to turn off this feature).
+#ifps
+.PP
+.B Xdvi
+can show PostScript<tm> specials by any of three methods.
+It will try first to use Display PostScript<tm>, then NeWS, then it
+will try to use Ghostscript to render the images. All of these options
+depend on additional software to work properly; moreover, some of them
+may not be compiled into this copy of
+.BR xdvi .
+.PP
+For performance reasons,
+.B xdvi
+does not render PostScript specials in the magnifying glass.
+#endif
+.PP
+If no file name has been specified on the command line,
+xdvi will try to open the most recently opened file; if the file
+history (accessible via the
+.B File > Open Recent
+menu) is empty, or if none of the files in the history are valid DVI files,
+it will pop up a file selector for choosing a file name.
+(In previous versions, which didn't have a file history, the file selector
+was always used; you can set the X resource
+.B noFileArgUseHistory
+to
+.I false
+to get back the old behaviour.)
+.PP
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH OPTIONS
+In addition to specifying the
+.I dvi
+file (with or without the
+.B .dvi
+extension),
+.B xdvi
+supports the following command line options. If the option begins with a
+.RB ` + '
+instead of a
+.RB ` \- ',
+the option is restored to its default value. By default, these options can
+be set via the resource names given in parentheses in the description of
+each option.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI + page
+Specifies the first page to show. If
+.B +
+is given without a number, the last page is assumed; the first page is
+the default.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifps
+.TP
+.B \-allowshell
+.RB ( .allowShell )
+This option enables the shell escape in PostScript specials.
+(For security reasons, shell escapes are disabled by default.)
+This option should be rarely used; in particular it should not be used just
+to uncompress files: that function is done automatically if the file name
+ends in
+.BR .Z ,
+.BR .gz ,
+or
+.BR .bz2 .
+Shell escapes are always turned off if the
+.B \-safer
+option is used.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-altfont " font"
+.RB ( .altFont )
+Declares a default font to use when the font in the
+.I dvi
+file cannot be found. This is useful, for example, with PostScript <tm> fonts.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-background " color"
+.RB ( .background )
+Determines the color of the background. Same as
+.BR -bg .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\" .TP
+.\" .BI \-bd " color"
+.\" .RB ( .borderColor )
+.\" Determines the color of the window border.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-bg " color"
+.RB ( .background )
+Determines the color of the background.
+.\" .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\" .TP
+.\" .BI \-bordercolor " color"
+.\" Same as
+.\" .BR -bd .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-borderwidth " width"
+.RB ( .borderWidth )
+Specifies the width of the border of the window. Same as
+.BR -bw .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-browser " browser"
+.RB ( .wwwBrowser )
+Defines the web browser used for handling external URLs. The value of this
+option or resource has the same syntax as the
+.B BROWSER
+environment variable; see the explanation of that variable in the
+section `ENVIRONMENT' below for a detailed description.
+If neither the option nor the X resource
+.I wwwBrowser
+is specified, the environment variables
+.B BROWSER
+and
+.B WWWBROWSER
+(in that order) are used to determine the browser command. If these are
+not set either, the following default value is used:
+.SB netscape -raise -remote "openURL(%s,new-window)":xterm -e lynx %s:xterm -e wget %s
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-bw " width"
+.RB ( .borderWidth )
+Specifies the width of the border of the window.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifgrey
+.TP
+.B \-copy
+.RB ( .copy )
+Always use the
+.I copy
+operation when writing characters to the display.
+This option may be necessary for correct operation on a color display, but
+overstrike characters will be incorrect.
+If greyscale anti-aliasing is in use, the
+.B \-copy
+operation will disable the use of colorplanes and make overstrikes come
+out incorrectly.
+#endif
+See also
+.BR \-thorough .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-cr " color"
+.RB ( .cursorColor )
+Determines the color of the mouse cursor. The default is the same as
+the foreground color.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-debug " bitmask|string[,string ...]"
+.RB ( .debugLevel )
+If nonzero, prints additional information on standard output. The
+argument can be either a bitmask specified as a decimal number, or
+comma-separated list of strings.
+.br
+For the bitmask representation, multiple values can
+be specified by adding the numbers that represent the individual bits;
+e.g. to debug all all file searching and opening commands, use 4032
+(= 2048 + 1024 + 512 + 256 + 128 + 64). Use -1 to turn on debugging
+of everything (this will produce huge output).
+.br
+For the string representation, use the strings listed in the following
+table, with a comma to separate the values; e.g. to debug
+all file searching and opening commands, use
+.BR search,expand,paths,hash,stat,open .
+(The option `kpathsea' is provided as a shorthand for these.)
+Note that such a list may need to be quoted to prevent the shell
+from interpreting commas or spaces in the list.
+.br
+The individual numbers and strings have the following meanings:
+.nf
+.sp 1n
+.ta 1L +8L +12L
+ 1 bitmap Bitmap creation
+ 2 dvi DVI translation
+ 4 pk PK fonts
+ 8 batch Batch mode: Exit after
+ reading the DVI file
+ 16 event Event handling
+ 32 ps PostScript interpreter calls
+ 64 stat Kpathsea stat(2) calls
+ 128 hash Kpathsea hash table lookups
+ 256 open Kpathsea file opening
+ 512 paths Kpathsea path definitions
+ 1024 expand Kpathsea path expansion
+ 2048 search Kpathsea searching
+ 4032 kpathsea All Kpathsea options
+ 4096 htex Hypertex specials
+ 8192 src Source specials
+ 16384 client Client/server mode (see -unique
+ and -sourceposition options)
+ 32768 t1 Type1 font library messages
+ 65536 t1_verbose Verbose Type1 library messages
+ 131072 gui GUI elements
+.sp 1n
+.fi
+Some of the Kpathsea debugging options are actually provided by Kpathsea;
+see the Debugging section in the Kpathsea manual for more information on
+these.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-density " density"
+.RB ( .densityPercent )
+Determines the density used when shrinking bitmaps for fonts.
+A higher value produces a lighter font. The default value is 40.
+#ifgrey
+If greyscaling is in use, this argument does not apply; use
+.B \-gamma
+instead.
+#endif
+See also the
+.RB ` S '
+keystroke.
+Same as
+.BR \-S .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-display " host" : display
+Specifies the host and screen to be used for displaying the
+.I dvi
+file. By default this is obtained from the environment variable
+.SB DISPLAY.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-dvipspath " path"
+.RB ( .dvipsPath )
+Use
+.I path
+as the
+.B dvips
+program to use when printing. The default for this is
+.BR dvips .
+The program or script should read the DVI file from standard input,
+and write the Postscript file to standard output.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-editor " editor"
+.RB ( .editor )
+Specifies the editor that will be invoked when the
+.I source-special()
+action is triggered to start a reverse search (by default via Ctrl-Mouse 1).
+The argument to this option is a format string in which occurrences of
+.RB `` %f ''
+are replaced by the file name, occurrences of
+.RB `` %l ''
+are replaced by the line number within the file, and optional
+occurrences of
+.RB `` %c ''
+are replaced by the column number within the line.
+.sp
+If neither the option nor the X resource
+.I .editor
+is specified, the following environment variables are checked
+to determine the editor command:
+.BR XEDITOR ,
+.BR VISUAL ,
+and
+.B EDITOR
+(in this sequence). If the string is found as the value
+of the
+.SB VISUAL
+or
+.SB EDITOR
+environment variables, then
+.RI `` "xterm -e "''
+is prepended to the string; if the editor is specified by other means, then
+it must be in the form of a shell command to pop up an X window with an
+editor in it. If none of these variables is set, a warning message is displayed
+and the command
+.RI `` "xterm -e vi +%l %f"''
+is used.
+.sp
+If no
+.RB `` %f ''
+or
+.RB `` %l ''
+occurs in the string, the missing format strings are appended automatically.
+(This is for compatibility with other programs when using one of the environment
+variables).
+.sp
+A new instance of the editor is started each time this command is used;
+therefore it is preferrable to use an editor that can be invoked in
+`client' mode to load new files into the same instance. Example
+settings are:
+.RS 7
+.TP 7
+.SB emacsclient --no-wait
+(older Emacsen)
+.TP
+.SB gnuclient -q
+(XEmacs and newer Emacsen)
+.TP
+.SB gvim --servername xdvi --remote
+(VIM v6.0+; the `--servername xdvi' option will cause gvim to run a
+dedicated instance for the files opened by xdvi.)
+.TP
+.SB nc
+(nedit)
+.PP
+.sp
+Note that those strings need to be enclosed
+into quotes when using them on the command-line
+to protect them from the shell; when using them
+as argument for the
+.I .editor
+resource in an X resource file, no quotes should be used.
+.sp
+.B NOTE ON SECURITY:
+The argument of this option isn't executed as a shell command,
+but via
+.I exec()
+to prevent evil tricks with the contents of source specials.
+.RE
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-expert
+This option is only supported for backwards compatibility;
+it is equivalent to
+.BR "\-expertmode 0" ,
+which should be preferred.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-expertmode " flag"
+.RB ( .expertMode )
+With an argument of
+.IR 0 ,
+this option switches off the display of the buttons, scrollbars,
+the toolbar (Motif only),
+the statusline and the page list. These GUI elements
+can also be (de)activated separately, by combining the
+appropriate values in the
+.I flag
+argument. This acts similar to the
+.B \-debug
+option: The integer
+.I flag
+is treated as a bitmap where each bit represents one
+element. If the bit has the value
+.IR 1 ,
+the element is switched on, if it has the value
+.IR 0 ,
+the element is switched off. The meaning of the bits
+is as follows:
+.nf
+.sp 1n
+.ta 1L +8L +12L
+ 1 statusline
+ 2 scrollbars
+ 4 Motif: pagelist, Xaw: buttons and pagelist
+ 8 toolbar (Motif only)
+ 16 menubar (Motif only)
+.sp 1n
+.fi
+For example, to turn on only the statusline and the scrollbars,
+use 3 (= 1 + 2).
+See also the
+.RB ` x '
+keystroke, where the bits are addressed by their positions, from 1 to
+3 (Xaw) or 5 (Motif), respectively.
+.PP
+If the statusline is not active, all messages
+that would normally be printed to the statusline will be printed to
+.IR stdout ,
+unless the
+.B \-hushstdout
+option is used.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-fg " color"
+.RB ( .foreground )
+Determines the color of the text (foreground).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-findstring\fP \fIstring\fP
+This option triggers a search for
+.I string
+in the DVI file mentioned on the command-line, similar to forward search
+(see the description of the
+.B sourceposition
+option):
+If there is already another
+instance of
+.B xdvi
+running on the displaying that DVI file, it will cause that instance
+to perform the search instead. The search starts at the top of the current
+page of the DVI file.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-font " font"
+.RB ( *font )
+Sets the font used in menus, buttons etc., as described in the
+.I X(7x)
+man page. The font for child windows can be set separately,
+e.g.:
+.RS 7
+.nf
+.ft 3
+.sp 1n
+xdvi*statusline*font: \e
+ -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*
+.sp 1n
+.ft
+.fi
+.RE
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-foreground " color"
+Same as
+.BR -fg .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-fullscreen
+When this option is used, xdvi will (try to) run in fullscreen mode, with
+no window decorations.
+This option is not guaranteed to work with all windowmanagers/desktops;
+if you're experiencing problems with it, please use the
+.B \-geometry
+option instead, and a suitable window manager setting to remove
+the window decorations.
+When using this option for presentations, you might want
+to get rid of all the control widgets as well, using the
+.B -expertmode
+option. This option can also be toggled at runtime using the
+.B fullscreen
+action (by default bound to Ctrl-l).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifgrey
+.TP
+.BI \-gamma " gamma"
+.RB ( .gamma )
+Controls the interpolation of colors in the greyscale anti-aliasing color
+palette. Default value is 1.0. For 0 <
+.I gamma
+< 1, the fonts will be lighter (more like the background), and for
+.I gamma
+> 1, the fonts will be darker (more like the foreground). Negative
+values behave the same way, but use a slightly different algorithm.
+For color and grayscale displays; for monochrome, see
+.BR \-density .
+See also the
+.RB ` S '
+keystroke.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-geometry " geometry"
+.RB ( .geometry )
+Specifies the initial geometry of the main window,
+as described in the
+.I X(7x)
+man page. The geometry of child windows can be set
+separately, e.g.:
+.br
+.I xdvi*helpwindow.geometry: 600x800
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-gsalpha
+.RB ( .gsAlpha )
+Causes
+.B Ghostscript
+to be called with the
+.B x11alpha
+driver instead of the
+.B x11
+driver. The
+.B x11alpha
+driver enables anti-aliasing in PostScript specials, for a nicer appearance.
+It is available on newer versions of
+.BR Ghostscript .
+This option can also be toggled with the
+.RB ` V '
+keystroke.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifghost
+.TP
+.BI \-gspalette " palette"
+.RB ( .palette )
+Specifies the palette to be used when using Ghostscript for rendering
+PostScript specials. Possible values are
+.BR Color ,
+.BR Greyscale ,
+and
+.BR Monochrome .
+The default is
+.BR Color .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR \-h , " \-help" , " \--help"
+Prints a short help text with an overview of the command-line options
+to standard output.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-hl " color"
+.RB ( .highlight )
+Determines the color of the page border, of the ruler in `ruler mode',
+and of the highlighting markers in forward search and string search.
+The default is the foreground color.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-href " anchor"
+Jump to
+.I anchor
+after opening the DVI file. This is only useful when invoking
+.B xdvi
+from other applications.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-hush
+.RB ( .Hush )
+Causes
+.B xdvi
+to suppress all suppressible warnings.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-hushchars
+.RB ( .hushLostChars )
+Causes
+.B xdvi
+to suppress warnings about references to characters which are not defined
+in the font.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-hushchecksums
+.RB ( .hushChecksums )
+Causes
+.B xdvi
+to suppress warnings about checksum mismatches between the
+.I dvi
+file and the font file.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifkpathsea
+.TP
+.B \-hushspecials
+.RB ( .hushSpecials )
+Causes
+.B xdvi
+to suppress warnings about
+.B \especial
+strings that it cannot process.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-hushstdout
+.RB ( .hushStdout )
+Suppresses printing of status messages to
+.IR stdout .
+Note that errors or warnings will still be printed to
+.I stderr
+even if this option is used.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-icongeometry " geometry"
+.RB ( .iconGeometry )
+Specifies the initial position for the icon.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-iconic
+.RB ( .iconic )
+Causes the
+.B xdvi
+window to start in the iconic state. The default is to start with the
+window open.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifgrey
+.TP
+.B \-install
+.RB ( .install )
+If
+.B xdvi
+is running under a
+.B PseudoColor
+visual, then (by default) it will check for
+.B TrueColor
+visuals with more bits per pixel, and switch to such a visual if one exists.
+If no such visual exists, it will use the current visual and colormap. If
+.B \-install
+is selected, however, it will still use a
+.B TrueColor
+visual with a greater depth, if one is available; otherwise, it will
+install its own colormap on the current visual. If the current visual is not
+.BR PseudoColor ,
+then
+.B xdvi
+will not switch the visual or colormap, regardless of its options.
+The default value of the
+.B install
+resource is the special value,
+.BR maybe .
+There is no
+.B +install
+option. See also
+.BR \-noinstall ,
+and the GREYSCALING AND COLORMAPS section.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifghost
+.TP
+.BI \-interpreter " filename"
+.RB ( .interpreter )
+Use
+.I filename
+as the Ghostscript interpreter. By default it uses
+.BR @GS_PATH@ .
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-keep
+.RB ( .keepPosition )
+Sets a flag to indicate that
+.B xdvi
+should not move to the home position when moving to a new page. See also the
+.RB ` k '
+keystroke. This flag is only honoured by the
+.B up()
+and
+.B down()
+actions, not by
+.B up-or-previous()
+and
+.BR down-or-next() .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-l
+.RB ( .listFonts )
+List the names of all fonts used.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-linkcolor
+.RB ( .linkColor )
+Color used for unvisited hyperlinks (`Blue2' by default). Hyperlinks
+are unvisited before you click on them, or after the DVI file has been reloaded.
+The value should be either a valid X color name (such as
+.IR DarkGoldenrod4 )
+or a hexadecimal color string (such as
+.IR #8b6508 ). See also
+.B \-visitedlinkcolor
+and
+.BR \-linkstyle .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-linkstyle
+.RB ( .LinkStyle )
+Determines the style in which hyperlinks are displayed. Possible
+values and their meanings are:
+.nf
+.sp 1n
+.ta 1L +8L
+ 0 No highlighting of links
+ 1 Underline links with \fIlink color\fR
+ 2 No underlining, color text with \fIlink color\fR
+ 3 Underline and display text colored with
+ \fIlink color\fR
+.sp 1n
+.fi
+The values for \fIlink color\fR are specified by the options/resources
+.BI \-linkcolor
+and
+.BI \-visitedlinkcolor
+(which see).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-margins " dimen"
+.RB ( .Margin )
+Specifies the size of both the top margin and side margin.
+This determines the ``home'' position of the page within the window as
+follows. If the entire page fits in the window, then the margin settings
+are ignored. If, even after removing the margins from the left, right,
+top, and bottom, the page still cannot fit in the window, then the page
+is put in the window such that the top and left margins are hidden, and
+presumably the upper left-hand corner of the text on the page will be
+in the upper left-hand corner of the window.
+Otherwise, the text is centered in the window.
+The dimension should be a decimal number optionally followed by
+any of the two-letter abbreviations for units accepted by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+By default, the unit will be
+.BR @DEFAULT_UNIT@.
+See also
+.BR \-sidemargin ", " \-topmargin ,
+and the keystroke
+.RB ` M .'
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifkpathsea
+.TP
+.BI \-mfmode " mode-def"
+#endif
+#ifnokpathsea
+.BI \-mfmode " mode-def\fR[\fP\fB:\fPdpi\fR]\fP"
+#endif
+.RB ( .mfMode )
+Specifies a
+.I mode-def
+string, which can be used in searching for fonts (see ENVIRONMENT, below).
+Generally, when changing the
+.IR mode-def ,
+it is also necessary to change the font size to the appropriate value
+for that mode. This is done by adding a colon and the value in dots per inch;
+for example,
+.BR "\-mfmode ljfour:600" .
+This method overrides any value given by the
+.B pixelsPerInch
+resource or the
+.B \-p
+command-line argument.
+#ifmakepk
+The metafont mode is also passed to
+.B metafont
+during automatic creation of fonts.
+#endif
+By default, it is
+.BR "@MFMODE@" .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-mgs " size"
+Same as
+.BR \-mgs1 .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-mgs[ n ] " size"
+.RB ( .magnifierSize\fR[\fIn\fR] )
+Specifies the size of the window to be used for the ``magnifying glass''
+for Button
+.IR n .
+The size may be given as an integer (indicating that the magnifying glass
+is to be square), or it may be given in the form
+.IR width x height .
+See the MOUSE ACTIONS section. Defaults are 200x150, 400x250, 700x500,
+1000x800, and 1200x1200.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-mousemode " " [ 0 | 1 | 2 ]
+.RB ( .mouseMode )
+Specifies the default mode of xdvi at startup: Magnifier (0), Text Selection Mode (1)
+or Ruler Mode (2). See the section
+.BR MODES ,
+below, for more information.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifcolor
+.TP
+.B \-nocolor
+.RB ( .color )
+Turns off the use of color specials. This option can be toggled with the
+.RB ` C '
+keystroke.
+(Note:
+.B \-nocolor
+corresponds to
+.BR color:off ;
+.B +nocolor
+to
+.BR color:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifdps
+.TP
+.B \-nodps
+.RB ( .dps )
+Inhibits the use of Display PostScript<tm> for displaying PostScript<tm>
+specials. Other forms of PostScript emulation, if installed, will be used
+instead.
+(Note:
+.B \-nodps
+corresponds to
+.BR dps:off ;
+.B +nodps
+to
+.BR dps:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-nofork
+.RB ( .fork )
+With the
+.B \-sourceposition
+and
+.B \-unique
+options, the default behavior is for
+.B xdvi
+to put itself into the background (like a daemon) if there
+is no appropriate instance of
+.B xdvi
+already running.
+This argument makes it run in the foreground instead. This is useful
+for debugging, or if your client application cannot deal well with
+a program self-backgrounding itself in this way -- e.g., the IPC functions
+in
+.B emacs
+are known to have problems with this.
+If no
+.B \-sourceposition
+or
+.B \-unique
+argument is given, then this option has no effect.
+(Note:
+.B \-nofork
+corresponds to
+.BR fork:off ;
+.B +nofork
+to
+.BR fork:on .)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifghost
+.TP
+.B \-noghostscript
+.RB ( .ghostscript )
+Inhibits the use of Ghostscript for displaying PostScript<tm> specials.
+(Note:
+.B \-noghostscript
+corresponds to
+.BR ghostscript:off ;
+.B +noghostscript
+to
+.BR ghostscript:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifgrey
+.TP
+.B \-nogrey
+.RB ( .grey )
+Turns off the use of greyscale anti-aliasing when printing shrunken bitmaps.
+(Note:
+.B \-nogrey
+corresponds to
+.BR grey:off ;
+.B +nogrey
+to
+.BR grey:on .)
+See also the
+.RB ` G '
+keystroke.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifghost
+.TP
+.B \-nogssafer
+.RB ( .gsSafer )
+Normally, if Ghostscript is used to render PostScript specials, the Ghostscript
+interpreter is run with the option
+.BR \-dSAFER .
+The
+.B \-nogssafer
+option runs Ghostscript without
+.BR \-dSAFER .
+The
+.B \-dSAFER
+option in Ghostscript disables PostScript operators such as
+.BR deletefile ,
+to prevent possibly malicious PostScript programs from having any effect.
+If the
+.B \-safer
+option is specified, then this option has no effect; in that case Ghostscript
+is always run with
+.BR \-dSAFER .
+(Note:
+.B \-nogssafer
+corresponds to
+.BR gsSafer:off ;
+.B +nogssafer
+to
+.BR gsSafer:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifgrey
+.TP
+.B \-noinstall
+.RB ( .install )
+Inhibit the default behavior of switching to a
+.B TrueColor
+visual if one is available with more bits per pixel than the current visual.
+(Note:
+\-noinstall
+corresponds
+.BR install:off ;
+there is no
+.B +noinstall
+option.)
+See also
+.BR \-install ,
+and the GREYSCALING AND COLORMAPS section.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifmakepk
+.TP
+.B \-nomakepk
+.RB ( .makePk )
+Turns off automatic generation of font files that cannot be found by other
+means.
+(Note:
+.B \-nomakepk
+corresponds to
+.BR makePk:off ;
+.B +nomakepk
+to
+.BR makePK:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-nomatchinverted
+.RB ( .matchInverted )
+Don't highlight string search matches in inverted color; instead, draw a rectangle in
+.I highlight
+color (see the
+.B \-hl
+option) around the match. This option is activated automatically if
+the display isn't running in TrueColor.
+(Note:
+.B \-nomatchinverted
+corresponds to
+.BR matchInverted:off ;
+.B +nomatchinverted
+to
+.BR matchInverted:on .)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifnews
+.TP
+.B \-nonews
+.RB ( .news )
+Inhibits the use of NeWS<tm> for displaying PostScript<tm> specials.
+Ghostscript, if enabled by the installation, will be used instead.
+(Note:
+.B \-nonews
+corresponds to
+.BR news:off ;
+.B +nonews
+to
+.BR news:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-noomega
+.RB ( .omega )
+This will disable the use of Omega extensions when interpreting DVI files.
+By default, the additional opcodes
+.I 129
+and
+.I 134
+are recognized by xdvi as Omega extensions and interpreted as requests
+to set 2-byte characters. The only drawback is that the virtual font
+array will require 65536 positions instead of the default 256 positions,
+i.e. the memory requirements of xdvi will be slightly larger. If you find
+this unacceptable or encounter another problem with the Omega extensions,
+you can switch this extension off by using
+.B \-noomega
+(but please do send a bug report if you find such problems - see the bug
+address in the
+.B AUTHORS
+section below).
+.br
+(Note:
+.B \-noomega
+corresponds to
+.BR "omega: off" ;
+.B +noomega
+to
+.BR "omega: on" .)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-noscan
+.RB ( .prescan )
+By default,
+.B xdvi
+does a preliminary scan of the
+.I dvi
+file to process any
+.B papersize
+specials; this is especially important at startup since the paper size may be
+needed to determine the window size.
+#ifps
+If PostScript<tm> is in use, then prescanning is also necessary in order to
+properly process header files.
+#endif
+#ifcolor
+In addition, prescanning is needed to correctly determine the background color
+of a page.
+#endif
+This option turns off such prescanning.
+(Prescanning will be automatically be turned back on if
+.B xdvi
+detects any of the specials mentioned above.)
+(Note:
+.B \-noscan
+corresponds to
+.BR prescan:off ;
+.B +noscan
+to
+.BR prescan:on .)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ift1
+.TP
+.BI \-not1lib
+.RB ( .t1lib )
+This will disable the use of T1Lib to display PostScript<tm> fonts.
+Use this option as a workaround when you encounter problems with the
+display of T1Lib (but please don't forget to send a bug report in
+this case, to the URL mentioned in the section AUTHORS below).
+.br
+(Note:
+.B \-not1lib
+corresponds to
+.BR t1lib:off ;
+.B +not1lib
+to
+.BR t1lib:on .)
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-notempfile
+.RB ( .tempFile )
+As mentined in the section
+.B DESCRIPTION
+above, xdvi will create a temporary copy of the DVI file so that it
+can be accessed without interruptions even while the file is being
+rewritten by
+.BR TeX .
+Since this introduces the overhead of copying the file every time
+it has changed, the
+.B \-notempfile
+allows you to turn off this behaviour. In this case, exposing parts of the
+window while the DVI file is being written by \*(Te\& will erase the current
+window contents until the DVI file can be completely reread.
+.br
+(Note:
+.B \-notempfile
+corresponds to
+.BR tempFile:off ;
+.B +notempfile
+to
+.BR tempFile:on .)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-offsets " dimen"
+.RB ( .Offset )
+Specifies the size of both the horizontal and vertical offsets of the
+output on the page. By decree of the Stanford \*(Te\& Project,
+the default \*(Te\& page origin is always 1 inch over and down from
+the top-left page corner, even when non-American paper sizes are used.
+Therefore, the default offsets are 1.0 inch.
+The argument
+.I dimen
+should be a decimal number optionally followed by any of the two-letter
+abbreviations for units accepted by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+By default, the unit will be
+.BR @DEFAULT_UNIT@.
+See also
+.B \-xoffset
+and
+.BR \-yoffset .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-p " pixels"
+.RB ( .pixelsPerInch )
+Defines the size of the fonts to use, in pixels per inch. The
+default value is @BDPI@. This option is provided only for backwards
+compatibility; the preferred way is to set both the resolution
+and the Metafont mode via the
+.B \-mfmode
+option (which see).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-paper " papertype"
+.RB ( .paper )
+Specifies the size of the printed page. Note that in most cases it's
+best to specify the paper size in the TeX input file via the line
+.sp
+.B \eusepackage[dvips]{geometry}
+.sp
+which will be recognized by both dvips and xdvi; in that case the
+use of a `-paper' option should be unneccessary.
+.br
+The paper size may be specified in the form
+\fIwidth\fBx\fIheight\fR optionally followed by a unit, where
+.I width
+and
+.I height
+are decimal numbers giving the width and height of the paper, respectively,
+and the unit is any of the two-letter abbreviations for units accepted
+by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+By default, the unit is
+.BR @DEFAULT_UNIT@\fR.
+.br
+There are also synonyms which may be used:
+.B us
+(8.5x11in),
+.B legal
+(8.5x14in),
+.B foolscap
+(13.5x17in),
+as well as the ISO sizes
+.BR a1 - a7 ,
+.BR b1 - b7 ,
+.BR c1 - c7 .
+Each of these also has a landscape or `rotated' variant:
+.B usr
+(11x8.5in),
+.BR a1r - a7r ,
+etc. For compatibility with
+.BR dvips ,
+the formats
+.B letter
+(8.5x11in),
+.B ledger
+(17x11in)
+and
+.B tabloid
+(11x17in)
+are also supported (these don't have rotated variants).
+.br
+Any of the above sizes may be preceded by a plus sign
+.RB (` + ');
+this causes the paper size given here to override any paper size given in the
+.I dvi
+file. The default paper size is @DEFAULT_PAGE_SIZE@.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-pause
+.RB ( .pause )
+This option provides a simple implementation of incremental
+(stepwise) display, which can be used for presentations.
+When this option is used,
+.B xdvi
+will pause the display of the current page whenever it encounters a
+special
+.I special-string
+.RI ( xdvi:pause
+by default; the string can be customized via
+.IR \-pausespecial ,
+see below), and the cursor will change its shape. The action
+.B unpause-or-next()
+(by default bound to the
+.B Space
+key) will display the next portion of the page up to the following
+.IR special-string ,
+or until the end of the page is reached.
+When the option is not used, specials containing
+.I special-string
+will be ignored.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-pausespecial " special-string"
+.RB ( .pauseSpecial )
+Sets the special string that causes xdvi to pause when the
+.I -pause
+option is active. The default value of
+.I special-string
+is
+.IR xdvi:pause .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifps
+.TP
+.BI \-postscript " flag"
+.RB ( .postscript )
+If
+.I flag = 0,
+rendering of PostScript<tm> specials is disabled; instead, bounding
+boxes will be displayed (if available). A value of
+.I 1
+(the default) switches PostScript<tm> specials on. With a value of
+.IR 2 ,
+the PostScript<tm> specials are displayed along with their
+bounding boxes; this allows you to visually check the correctness
+of the bounding boxes. The values can also be toggled at runtime
+with the
+.RB ` v '
+keystroke and the corresponding numerical prefix arguments 0, 1 and 2.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-ps2pdfpath " path"
+.RB ( .ps2pdfPath )
+Use
+.I path
+as a conversion program from Postscript to PDF. The program or script
+should accept two command-line arguments: The Postscript file as first
+argument, and the PDF output file as second argument.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-rulecolor " color"
+.RB ( .ruleColor )
+Determines the color of the rules used for the the magnifier
+(default: foreground color).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-q
+.RB ( .noInitFile )
+Ignore the
+.I $HOME/.xdvirc
+startup file (i.e. don't read it at startup, and don't write it
+at exit). This forces the defaults defined in
+.I $HOME/.Xdefaults
+to be used. See
+.B FILES
+for more information on
+.IR $HOME/.xdvirc .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-rv
+.RB ( .reverseVideo )
+Causes the page to be displayed with white characters on a black background,
+instead of vice versa.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-S " density"
+.RB ( .densityPercent )
+Same as
+.B \-density
+(which see).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-s " shrink"
+.RB ( .shrinkFactor )
+Defines the initial shrink factor. The default value is @SHRINK@. If
+.I shrink
+is given as 0, then the initial shrink factor is computed so that the
+page fits within the window (as if the `s' keystroke were given without
+a number).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-safer
+.RB ( .safer )
+This option turns on all available security options; it is designed for use when
+.B xdvi
+is called by a browser that obtains a
+.I dvi
+or \*(Te\& file from another site.
+#ifps
+This option selects
+#endif
+#ifghost
+.B +nogssafer
+and
+#endif
+#ifps
+.BR +allowshell .
+#endif
+#ifnops
+Otherwise, it has no effect, since
+.B xdvi
+has been compiled without support for PostScript specials.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-sidemargin " dimen"
+.RB ( .sideMargin )
+Specifies the side margin (see
+.BR \-margins ).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-sourceposition " line" [: col "][ ]" filename
+This option makes
+.B xdvi
+search in the
+.I dvi
+file for the place corresponding to the indicated line (and, optionally,
+column) in the .tex source file, and highlight the place found by drawing a
+rectangle in the
+.I highlight
+color (see the
+.B \-hl
+option) around the corresponding text. In addition, when run with this
+argument (and the
+.B \-nofork
+option is not given, which see),
+.B xdvi
+will always return immediately: if it finds another instance of
+.B xdvi
+already showing
+.I dvi_file,
+then it will cause that instance to raise its window and move to the given
+place in the
+.I dvi
+file; otherwise it will start up its own instance in the background.
+If several instances of xdvi are displaying the respective
+.I dvi
+file, the instance which was last raised to the foreground will be used.
+.sp
+The space before
+.I filename
+is only needed if the filename starts
+with a digit. When the space is used, the argument
+needs to be encosed in quotes to prevent the shell from
+misinterpreting the space as argument separator.
+.sp
+This option requires that
+.I dvi_file
+be prepared with source special information. See the section on SOURCE SPECIALS
+for details on how to do this.
+.sp
+Here is a more detailed description of how the filename in the
+.I \-sourceposition
+argument is matched with the filename in the source specials:
+.RS 7
+.TP 3
+1.
+If neither of the filenames contains a path name component, the filenames
+are compared ignoring the
+.RI ` .tex '
+extensions in both filenames.
+.TP
+2.
+Otherwise, if one of the filenames does contain a path component (e.g.:
+.IR ./test.tex ,
+.IR ../test.tex ,
+.IR /my/homedir/tex/test.tex
+or any combination of these), both filenames are expanded to a full path,
+with any occurences of
+.I ../
+and
+.I ./
+expanded, and multiple slashes removed.
+.br
+The pathname in the
+.I \-sourceposition
+is expanded relative to the current working directory of the
+.I xdvi \-sourceposition
+invocation, and the pathnames in the source specials are expanded
+relative to the path of the current DVI file being viewed.
+.br
+The path names are then compared ignoring the
+.RI ` .tex '
+extensions in both path names.
+.RE
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-statusline\fP
+.RB ( .statusline )
+This option is obsolete; use
+\fB\-expertmode \fP \fIflag\fP
+instead (which see).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-thorough
+.RB ( .thorough )
+.B Xdvi
+will usually try to ensure that overstrike characters
+.RI ( e.g. ,
+.BR \enotin )
+are printed correctly. On monochrome displays, this is always possible
+with one logical operation, either
+.I and
+or
+.IR or .
+On color displays, however, this may take two operations, one to set the
+appropriate bits and one to clear other bits. If this is the case, then
+by default
+.B xdvi
+will instead use the
+.I copy
+operation, which does not handle overstriking correctly. The
+.B \-thorough
+option chooses the slower but more correct choice. See also
+.BR \-copy .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-topmargin " dimen"
+.RB ( .topMargin )
+Specifies the top and bottom margins (see
+.BR \-margins ).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-unique
+.RB ( .unique )
+This option will make another instance of xdvi running on the same display
+act as a `server'. For example, the invocation
+.sp
+.B xdvi -unique +5 file.dvi
+.sp
+will cause this other instance to load
+.I file.dvi
+on page 5 in place of the file that it is currently displaying. If there is
+already another instance of xdvi already displaying the file
+.IR file.dvi ,
+then it will just jump to page 5.
+If the other instance of xdvi is displaying a different file, it will load
+.I file.dvi
+instead. Otherwise, if no other instance of
+xdvi is currently running on the display, this option instead
+starts a new instance of xdvi in the background (unless the
+.I \-nofork
+option is specified, which see) displaying page 5 of
+.IR file.dvi .
+.br
+The filename and the
+.B +n
+option for the page number are the only options available for
+controlling a remote instance of xdvi like this; all other options are
+currently ignored.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-useTeXpages
+Use logical \*(Te\& pages (the values of the
+.I \ecount0
+register) instead of physical pages for the pagelist lables and
+when jumping to a page in a document with the `g' keystroke (or the
+.B goto-page()
+action).
+This option can be toggled via the
+.RB ` T '
+keystroke.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-version
+Print information on the version of
+.BR xdvi .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-visitedlinkcolor
+.RB ( .visitedLinkColor )
+Color used for visited hyperlinks (`Purple4' by default). Hyperlinks become
+visited once you click on them. As for
+.BR linkColor ,
+the value should be either a valid X color name or a hexadecimal color string.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B \-warnspecials
+.RB ( .warnSpecials )
+Causes
+.B xdvi
+to issue warnings about
+.B \especial
+strings that it cannot process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-watchfile " n"
+.RB ( .watchFile )
+If this option is set to a value larger than 0, xdvi will check
+the DVI file for changes every
+.I n
+seconds. If the DVI file has been completely written by TeX, it will
+be reloaded automatically. Fractional values (e.g. `2.5') are
+possible. The default for this option is 0, i.e. no watching.
+.br
+Since xdvi cannot handle partial DVI files, it tries not to reload
+the file while it is being rewritten. However, use of the magnifier
+or switching of pages requires reading (a part of) the DVI file, and
+if the
+.B tempfile
+option is switched off, this will erase the current contents of the window
+until the DVI file can be read entirely.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-wheelunit " pixels"
+.RB ( .wheelUnit )
+Sets the number of pixels that a motion of a wheel mouse will move the
+image up or down. If set to zero, the wheel mouse functionality is disabled.
+The default value is 80.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-xoffset " dimen"
+.RB ( .xOffset )
+Specifies the size of the horizontal offset of the output on the page. See
+.BR \-offsets .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BI \-yoffset " dimen"
+.RB ( .yOffset )
+Specifies the size of the vertical offset of the output on the page. See
+.BR -offsets .
+.PP
+
+
+
+.SH KEYSTROKES
+.B Xdvi
+recognizes the following keystrokes when typed in its window.
+Each may optionally be preceded by a (positive or negative) number, a
+`prefix argument', whose interpretation will depend on the particular keystroke.
+This prefix argument can be discarded by pressing the ``Escape'' key.
+If present, the ``Help'', ``Prior'' and ``Next'' keys are synonyms for
+.RB ` ? ',
+.RB ` b ',
+and
+.RB ` f '
+keys, respectively.
+.PP
+The key bindings listed here are those that
+.B xdvi
+assigns by default. The names appearing in brackets at the beginning
+of the descriptions are the names of the actions associated with the
+keys; these can be used to customize the key bindings, as explained in
+more detail in the section
+.B CUSTOMIZATION
+below. If only a lowercase binding is listed, both upper- and lowercase
+keys will work for that binding.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"
+.\" SPECIAL KEYS
+.\"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR ESC " key"
+.RB [ discard-number() ]
+The escape key discards the numerical prefix for all actions
+(useful when you mistyped a number).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR Delete " key"
+.RB [ up-or-previous() ]
+Moves down two-thirds of a window-full, or to the top of the previous page
+if already at the bottom of the page. With a float argument, moves down the
+corresponding fraction of a window-full. By default, the
+.I Space
+key is bound to the action
+.B unpause-or-next()
+which does a similar thing; see there.
+.br
+The `keep' flag is ignored by these actions.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR Space " key"
+.RB [ unpause-or-next() ]
+Moves down two-thirds of a window-full, or to the next page if already at
+the bottom of the page.
+.br
+When the option
+.BI \-pause " special-string"
+is used and the display is currenlty paused, this key will instead
+display the next portion of the page until the next
+.I special-string
+or the end of the page is encountered. See the description of the
+.B \-pause
+option for details.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR Ctrl-Home " (Xaw), " Ctrl-osfBeginLine " (Motif)"
+.RB [ goto-page(1) ]
+Moves to the first page of the document.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR Ctrl-End " (Xaw), " Ctrl-osfEndLine " (Motif)"
+.RB [ goto-page() ]
+Moves to the last page of the document.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR Home " (Xaw), " osfBeginLine " (Motif)"
+.RB [ home-or-top() ]
+Move to the ``home'' position of the page, or to the top of the page if
+the
+.I keep
+flag is set (in this case, the page doesn't scroll horizontally).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR End " (Xaw), " osfEndLine " (Motif)"
+.RB [ end-or-bottom() ]
+Move to the ``end'' position of the page (the lower right-hand corner),
+or to the bottom of the page if the
+.I keep
+flag is set (in this case, the page doesn't scroll horizontally).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"
+.\" ARROW KEYS
+.\"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Down arrow
+.RB [ down(0.015) ]
+Scrolls page down.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Up arrow
+.RB [ up(0.015) ]
+Scrolls page up.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Right arrow
+.RB [ right(0.015) ]
+Scrolls page right.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Left arrow
+.RB [ left(0.015) ]
+Scrolls page left.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"
+.\" ORDINARY KEYS. Note that the special symbols ([ ] + - etc.) are not in
+.\" strict ASCII order (found that more intuitive). Sequence for each letter
+.\" is: Alt-Ctrl, Ctrl, uppercase, lowercase.
+.\"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Alt-Ctrl-+
+.RB [ change-density(25) ]
+Increase the darkness of the fonts in the DVI window by adding to the gamma value
+(see also the
+.RB ` S '
+keystroke).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Alt-Ctrl--
+.RB [ change-density(-25) ]
+Decrease the darkness of the fonts in the DVI window by subtracting from the gamma value
+(see also the
+.RB ` S '
+keystroke).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-+
+.RB [ set-shrink-factor(+) ]
+Increase the shrink factor (see also the
+.RB ` s '
+keystroke).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl--
+.RB [ set-shrink-factor(-) ]
+Decrease the shrink factor (see also the
+.RB ` s '
+keystroke).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctr-[
+.RB [ pagehistory-delete-backward() ]
+Delete the current item in the page history and move to the history
+item before the deleted one. With a prefix argument
+.BR n ,
+delete
+.B n
+previous history items. See
+.B PAGE HISTORY
+for details.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B [
+.RB [ pagehistory-back() ]
+Move back in the page history (see
+.B PAGE HISTORY
+for details). With a prefix argument
+.BR n ,
+move back
+.B n
+history items.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctr-]
+.RB [ pagehistory-delete-forward() ]
+Delete the current item in the page history and move to the history
+item after the deleted one. With a prefix argument
+.BR n ,
+delete
+.B n
+next history items. See
+.B PAGE HISTORY
+for details.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B ]
+.RB [ pagehistory-forward() ]
+Move forward in the page history (see
+.B PAGE HISTORY
+for details). With a prefix argument
+.BR n ,
+move forward
+.B n
+history items.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.BR ^
+.RB [ home() ]
+Move to the ``home'' position of the page. This is normally the upper
+left-hand corner of the page, depending on the margins as described in the
+.B \-margins
+option, above.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B ?
+.RB [ help() ]
+Same as the
+.B h
+key (which see).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B B
+.RB [ htex-back() ]
+This key jumps back to the previous hyperlink anchor. See the
+section
+.B HYPERLINKS
+for more information on navigating the links.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B b
+.RB [ back-page() ]
+Moves to the previous page (or back
+.I n
+pages). Synonyms are
+.RB ` p '
+and
+.BR Ctrl-h .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifcolor
+.TP
+.B C
+.RB [ set-color() ]
+This key toggles the use of color specials. The key sequences
+.RB ` 0C '
+and
+.RB ` 1C '
+turn interpretation of color specials off and on, respectively.
+See also the
+.B \-nocolor
+option.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B c
+.RB [ center() ]
+Moves the page so that the point currently beneath the mouse cursor is moved to
+the middle of the window, and warps the mouse cursor to the same place.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B d
+.RB [ down() ]
+Moves page down two thirds of a window-full. With a float argument to ``down'',
+moves down the corresponding fraction of a window-full.
+.\" Therefore, a more
+.\" ``smooth'' scrolling using the ``Up'' and ``Down'' keys can be
+.\" achieved by the the following setting:
+.\" .sp
+.\" xdvi.mainTranslations: #override\e
+.\" .br
+.\" <Key>Up:up(0.01)\en\e
+.\" .br
+.\" <Key>Down:down(0.01)\en
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-f
+.RB [ find() ]
+Pop up a window to search for a string in the DVI file. See the section
+.BR "STRING SEARCH" ,
+below, for more details.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B f
+.RB [ forward-page() ]
+Moves to the next page (or to the
+.IR n th
+next page if a number is given). Synonyms are
+.RB ` n ',
+Return, and Line Feed.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifgrey
+.TP
+.B G
+.RB [ set-greyscaling() ]
+This key toggles the use of greyscale anti-aliasing for displaying shrunken
+bitmaps. In addition, the key sequences
+.RB ` 0G '
+and
+.RB ` 1G '
+clear and set this flag, respectively. See also the
+.B \-nogrey
+option.
+.sp
+If given a numeric argument that is not 0 or 1, greyscale anti-aliasing is
+turned on, and the gamma resource is set to the value divided by
+100. E.g.,
+.RB ` 150G '
+turns on greyscale and sets gamma to 1.5.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-g
+.RB [ find-next() ]
+Find the next match string in the DVI file; this can be used instead
+of pressing the `Find' button in the search window.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B g
+.RB [ goto-page() ]
+Moves to the page with the given number. If no page number is given, xdvi jumps to the last page.
+.br
+If the option/resource
+.B useTeXpages
+is active, the numbers correspond the the actual page numbers in the TeX file;
+otherwise, absolute page numbers (starting from 1) are used. In the latter case,
+the page numbers can be changed with the
+.RB ` P '
+keystroke, below.
+Note that with the
+.B useTeXpages
+option it is possible that the same page number occurs multiple
+times; in such a case, xdvi will use the first page number that matches.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B h
+Pops up a help window with a short explanation of the most important key
+bindings and concepts.
+.\"
+.\" Ummh, surely nobody will use the following ...
+.\"
+.\" For I18n purposes, the help texts and menu entries are configurable
+.\" via the following X resources:
+.\" .BR helpGeneral ,
+.\" #ifhyper
+.\" .BR helpHypertex ,
+.\" #endif
+.\" .BR helpOthercommands ,
+.\" .BR helpMarking ,
+.\" .BR helpPagemotion ,
+.\" .BR helpMousebuttons ,
+.\" .BR helpRulermode ,
+.\" .BR helpSearch and
+.\" .BR helpSourcespecials .
+.\" The values of this resource should be a text string, the first line of
+.\" which should contain two fields separated by `\en'. The first field is
+.\" used as list entry for the list of help topics on the left of the help
+.\" window, and the second field is used as the heading on the right-hand side.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B k
+.RB [ set-keep-flag() ]
+Normally when
+.B xdvi
+switches pages, it moves to the home position as well. The
+.RB ` k '
+keystroke toggles a `keep-position' flag which, when set, will keep
+the same position when moving between pages. Also
+.RB ` 0k '
+and
+.RB ` 1k '
+clear and set this flag, respectively. See also the
+.B \-keep
+option.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-l
+.RB [ fullscreen(toggle) ]
+Toggles fullscreen mode (see the description of the
+.B \-fullscreen
+option for more information on this). This is even more flaky than
+using the command-line option: There is no universal standard
+how a window could change its own geometry or window decorations at
+run-time, so this will not work with most window managers or
+desktops. Generally, it's better to use the window manager controls to
+change the size or decorations of the xdvi window.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B l
+.RB [ left() ]
+Moves page left two thirds of a window-full.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B M
+.RB [ set-margins() ]
+Sets the margins so that the point currently under the mouse cursor defines
+the upper left-hand corner of the text in the page. Note that the command
+does
+.I not
+move the image, but only determines the margins
+for the page switching commands. For details on how the margins
+are used, see the
+.B \-margins
+option.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B m
+.RB [ toggle-mark() ]
+Toggles the mark for the current page in the page list. When a page
+is marked, it is displayed with a small star `*' next to the page number.
+The marked pages can then be printed or saved to a file.
+A page or several pages can also be marked by clicking or dragging
+.B Mouse-2
+in the page list.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-n
+.RB [ toggle-mark()forward-page() ]
+Toggles the mark for the current page in the page list, and moves to
+the next page. This lets you quickly mark a series of subsequent pages.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B n
+.RB [ forward-page() ]
+Moves to the next page (or to the
+.IR n th
+next page if a number is given). Synonyms are
+.RB ` f ',
+Return, and Line Feed.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-o
+.RB [ select-dvi-file() ]
+Read a new
+.I dvi
+file. A file-selection widget is popped up for you to choose the DVI
+file from. If a prefix argument
+.I n
+is given, the
+.I n th
+file from the file history is opened instead.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B P
+.RB [ declare-page-number() ]
+``This is page number
+.IR n .''
+This can be used to make the
+.RB ` g '
+keystroke refer to a different page number than the physical page.
+(If you want to use `logical' or \*(Te\& page numbers instead of physical pages,
+consider using the option
+.B \-useTeXpages
+instead.)
+The argument
+.I n
+should be given as prefix to this key.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-p
+.RB [ print() ]
+Opens a popup window for printing the DVI file, or parts of it.
+See the section
+.B PRINT DIALOG
+for an explanation of the options available, and the resources to customize
+the default behaviour.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B p
+.RB [ back-page() ]
+Moves to the previous page (or back
+.I n
+pages). Synonyms are
+.RB ` b '
+and
+.BR Ctrl-h .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B q
+.RB [ quit() ]
+Quits the program.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-r
+.RB [ forward-page(0) ]
+Redisplays the current page.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B R
+.RB [ reread-dvi-file() ]
+Forces the
+.I dvi
+file to be reread. This allows you to preview many versions of the same
+file while running
+.B xdvi
+only once.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B r
+.RB [ right() ]
+Moves page right two thirds of a window-full.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-s
+.RB [ save() ]
+Opens a popup window for saving the DVI file, or parts of it. See the section
+SAVE DIALOG below for more information on this.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B S
+.RB [ set-density() ]
+Sets the density factor to be used when shrinking bitmaps. This should
+be a number between 0 and 100; higher numbers produce lighter characters.
+#ifgrey
+If greyscaling mode is in effect, this changes the value of gamma instead.
+The new value of gamma is the given number divided by 100; negative values
+are allowed.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B s
+.RB [ set-shrink-factor() ]
+Changes the shrink factor to the given number. If no number is given, the
+smallest factor that makes the entire page fit in the window will be used.
+(Margins are ignored in this computation.)
+.\" NOTE: following only works in action string, not interactively!!!
+.\" Two special values are
+.\" .B +
+.\" and
+.\" .B -
+.\" which zoom in and out respectively, by decrementing/incrementing the
+.\" shrinkfactor by one step.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B T
+.RB [ use-tex-pages() ]
+Use logical \*(Te\& pages (the values of the
+.I \ecount0
+register) instead of physical pages for the pagelist labels and
+when jumping to a page in a document via
+.BR goto-page() .
+See also the
+.B \-useTeXpages
+option.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B t
+.RB [ switch-magnifier-units() ]
+Switches the units used for the magnifier tick marks, and for reporting
+the distance between the mouse pointer and the ruler centre in
+ruler mode (see the section
+.BR MODES ).
+The default value is specified by the X resource
+.B tickUnits
+(`mm' by default). The units toggle through the following
+values; except for `px', they all correspond to \*(Te\&'s units:
+.I mm
+(millimeters)
+.I pt
+(\*(Te\& points),
+.I in
+(inches),
+.I sp
+(scaled points, the unit used internally by \*(Te\&)
+.I bp
+(big points or `Postscript points'),
+.I cc
+(cicero points),
+.I dd
+(didot points),
+.I pc
+(pica), and
+.I px
+(screen pixels).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-u
+.RB [ back-page()toggle-mark() ]
+Moves to the previous page, and toggles the mark for that page. This
+is the dual action to
+.BR Ctrl-n .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B u
+.RB [ up() ]
+Moves page up two thirds of a window-full. With a float argument to ``up'',
+moves up the corresponding fraction of a window-full.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-v
+.RB [ show-source-specials() ]
+Show bounding boxes for every source special on the current page, and print
+the strings contained in these specials to stderr. With prefix 1,
+show every bounding box on the page. This is for debugging purposes mainly.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifghost
+.TP
+.B V
+.RB [ set-gs-alpha() ]
+This key toggles the anti-aliasing of PostScript<tm> specials when
+.B Ghostscript
+is used as renderer. In addition the key sequences
+.RB ` 0V '
+and
+.RB ` 1V '
+clear and set this flag, respectively. See also the
+.B \-gsalpha
+option.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifps
+.TP
+.B v
+.RB [ set-ps() ]
+This key toggles the rendering of PostScript<tm> specials between 3 states:
+.RS 7
+.TP 0
+.SB - specials (like EPS graphics) are displayed;
+.TP
+.SB - specials are displayed along with their bounding box (if available);
+.TP
+.SB - only the bounding box is displayed.
+.PP
+.sp
+The states can also be selected directly by using
+.RB ` 1v ',
+.RB ` 2v '
+and
+.RB ` 0v '
+respectively.
+See also the
+.B \-postscript
+option.
+.RE
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-x
+.RB [ source-what-special() ]
+Display information about the source special next to the mouse cursor in the
+statusline. This is the same special that would be found by
+.I source-special() ,
+but without invoking the editor. For debugging purposes.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B x
+.RB [ set-expert-mode() ]
+Toggles expert mode, in which
+the statusline, the scrollbars, the menu buttons, the toolbar (Motif only)
+and the page list are not shown.
+Typing
+.RB ` 1x '
+toggles the display of the statusline at the bottom of
+the window. Typing
+.RB ` 2x '
+toggles the scrollbars (if available). For Xaw,
+.RB ` 3x '
+toggles the menu buttons and the page list, for Motif,
+it toggles the page list. In Motif, the additional bindings
+.RB ` 4x '
+toggle the toolbar, and
+.RB ` 5x '
+the menu bar.
+.br
+Without a prefix argument, all of the mentioned GUI elements are either
+switched on (if they had been invisible before) or off.
+.br
+Toggling the scrollbars may behave erratically with the
+Xaw widgets; e.g. the scrollbars may reappear after
+resizing the window, and at certain window sizes one of the
+scrollbars may fail to disappear.
+.br
+See also the option
+.B \-expertmode
+(the numbers above correspond to the bits in the argument to
+.BR \-expertmode ).
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH MOUSE ACTIONS IN THE MAIN WINDOW
+.TP
+.B Mouse-1
+.RB [ do-href()magnifier(*1) ]
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Mouse-2
+.RB [ do-href-newwindow()magnifier(*2) ]
+Usually, if a binding specifies more then one action, all actions
+are executed in a sequence. The hyperlink bindings
+.B do-href()
+and
+.B do-href-newwindow()
+are special in that they are used as an
+.I alternative
+to other actions that might follow them
+.I if
+the mouse is currently located on a hyperlink.
+In this case, none of the other actions will be executed.
+Otherwise,
+.I only
+the other actions are executed.
+.br
+The action
+.B do-href()
+jumps to the link target in the current xdvi
+window (eventually switching to another page), and
+.B do-href-newwindow()
+opens a new instance of xdvi for the link target.
+In both cases, the location of the target is
+indicated by a small arrow drawn in the same color
+as a visited link
+in the left corner of the window.
+.TP
+.B Mouse-3
+.RB [ magnifier(*3) ]
+The actions
+.B magnifier(n)
+will pop up a ``magnifying glass'' which shows the unshrunk
+image of the region around the mouse pointer. The magnifier disappears when
+the mouse button is released. Moving the mouse cursor while holding the button down will move the
+magnifier.
+.br
+In \fB`Ruler Mode'\fR, the first button moves or sets a ruler cross instead;
+see the section
+.BR MODES ,
+below, for details.
+.br
+Different mouse buttons produce different sized
+windows, as indicated by the
+the argument of the
+.I magnifier()
+action. Its argument is either a string of the form
+.IR width x height ,
+as in the
+.BI \-mgs n
+command-line option, or one of the strings
+.B *1
+through
+.BR *5 ,
+referring to the value specified by the corresponding
+.BI \-mgs n
+option. Note that in order to assign magnifier actions to
+the buttons 4 or 5, you need to use the resource
+.B wheelTranslations
+(more about this resource below), e.g.:
+.sp
+xdvi.wheelTranslations: <Btn4Down>: magnifier(*4)\en\e
+ <Btn5Down>: magnifier(*5)\en
+.sp
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Shift-Mouse-1
+.RB [ drag(+) ]
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Shift-Mouse-2
+.RB [ drag(|) ]
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Shift-Mouse-3
+.RB [ drag(-) ]
+Drags the page with the mouse. Shift-Mouse 1 allows dragging in all directions,
+Shift-Mouse 2 allows vertical dragging only, and Shift-Mouse 3 allows
+horizontal dragging only. To access these actions via customization, use the
+.B drag
+action. This action should have one parameter, the character
+.RB `` | '',
+.RB `` - '',
+or
+.RB `` + '',
+indicating vertical dragging, horizontal dragging, or dragging in both
+directions.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Ctrl-Mouse-1
+.RB [ source-special() ]
+Holding down the
+.I Ctrl
+key and clicking mouse button 1 starts a ``reverse search'',
+opening the editor at the location in the \*(Te\& file corresponding
+to the pointer location in the DVI file.
+See the section on SOURCE SPECIALS, below, for more information on this.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH UNBOUND ACTIONS
+The following actions are not bound to a key by default, but are available
+for customization.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B quit-confirm()
+Pops up a confirmation window to quit xdvi. To bind it to the
+.RB ` q '
+key instead of the default `quit()' action, put the following into your
+.I ~/.Xdefaults
+file:
+.sp
+xdvi.mainTranslations: #override\e
+.br
+<Key>q: quit-confirm()\en
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B down-or-next()
+Similar to
+.IR unpause-or-next() :
+Moves down two-thirds of a window-full, or to the next page if already
+at the bottom of the page.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B shrink-to-dpi()
+This action takes one (required) argument. It sets the shrink factor to
+an integer so as to approximate the use of fonts with the corresponding
+number of dots per inch. If
+.B xdvi
+is using fonts scaled for
+.I p
+dots per inch, and the argument to
+.B shrink-to-dpi
+is
+.IR n ,
+then the corresponding shrink factor is the ratio
+.IR p / n ,
+rounded to the nearest integer.
+.PP
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH CUSTOMIZATION
+Key and mouse button assignments can be changed by setting the
+.B mainTranslations
+resource to a string of translations as defined in the documentation for the
+X toolkit. The actions should take the form of action names listed in the
+KEYSTROKES and MOUSE ACTIONS sections.
+.PP
+An exception to this are the Motif keys
+.IR osfPageUp " (" PgUp ),
+.IR osfPageDown " (" PgDown ),
+.IR osfBeginLine " (" Home )
+and
+.IR osfEndLine " (" End )
+which are currently not customizable in the Motif version.
+.PP
+Key actions will usually be without arguments; if they are passed an argument,
+it represents the optional number or `prefix argument' typed prior to the action.
+.PP
+Some key actions may take special arguments, as follows: The argument of
+.B goto-page
+may be the letter
+.RB ` e ',
+indicating the action of going to the end of the document.
+The argument of
+.B set-shrink-factor
+may be the letter
+.RB ` a ',
+indicating that the shrink factor should be set to the smallest value such that
+the page will fit in the window, or one of the signs
+.RB ` + '
+or
+.RB ` - ',
+indicating that the shrink factor should be increased or decreased, respectively.
+Finally, actions that would perform a toggle, such as
+.BR set-keep-flag ,
+may receive an argument
+.RB ` t ',
+indicating that the action should toggle regardless of the current prefix argument.
+.PP
+Mouse actions should refer only to
+.B ButtonPress
+events (e.g.,
+.BR "<Btn1Down>:magnifier(*1)" ).
+The corresponding motion and release events will be handled internally.
+A key action may be bound to a mouse event, but not vice versa.
+.PP
+Usually the string of translations should begin with
+.RB `` #override '',
+indicating that the default key and mouse button assignments should not
+be discarded.
+.PP
+When keys or mouse buttons involving modifiers (such as Ctrl or Shift)
+are customized together with their non-modified equivalents, the modified
+keys should come first, for example:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+xdvi.mainTranslations: #override \e
+Ctrl<Btn1Down>: magnifier(*3)\en\e
+Shift<Btn1Down>: magnifier(*2)\en\e
+<Btn1Down>: magnifier(*1)\en
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+Note: The additional `Modes' for Mouse-1 (Ruler Mode, Text Mode - see
+the section
+.BR MODES )
+only work if Mouse-1 has the magnifier() action bound to it.
+.PP
+Because
+.B xdvi
+needs to capture pointer motion events, and because the X Toolkit
+translations mechanism cannot accommodate both motion events and double-click
+events at the same time, it is not possible to specify double-click
+actions in
+.B xdvi
+customizations. For information on this and other aspects of translations,
+see the X Toolkit Intrinsics documentation.
+.PP
+There is no command-line option to set the
+.B mainTranslations
+resource, since changing this resource on the command line would be cumbersome.
+To set the resource for testing purposes, use the
+.B -xrm
+command-line option provided by the X toolkit. For example,
+\fBxdvi \-xrm 'XDvi.mainTranslations: #override "z":quit()' ...\fR
+or
+.B "xdvi \-xrm 'XDvi.mainTranslations: #override <Key>z:quit()' ..."
+will cause the key
+.RB ` z '
+to quit
+.BR xdvi .
+.PP
+Support of wheel mice is controlled by the
+.B wheelTranslations
+resource. Generally the only action routine called by this resource should be
+.BR wheel .
+The default value is
+``\fB<Btn4Down>:wheel(-1.)\en<Btn5Down>:wheel(1.)\fR''.
+Because this resource is implemented differently from the others, it should
+not begin with
+.RB ``#override '';
+when specifying a value for this resource, all wheel actions should be
+included.
+.\" #ifxaw
+.\" NOTE: following is different with Motif, and will change for Xaw too ...
+.\" removed for the time being.
+.\"
+.\" .PP
+.\" The menu entries and actions may also be customized, in a similar manner.
+.\" In this case the resource
+.\" .B menuTranslations
+.\" should consist of a string describing the pulldown menu names, submenu entries
+.\" and the associated actions. Currently, only one level of submenus is provided for.
+.\" The description consists of lines (substrings separated by the newline character
+.\" `\fB\\n\fP'),
+.\" where each line describes one menu entry. Each line consists of a colon-separated
+.\" list containing the following elements:
+.\" .RS 2
+.\" .TP 2
+.\" -
+.\" the name of the menu;
+.\" .TP
+.\" -
+.\" the name of the submenu;
+.\" .TP
+.\" -
+.\" an accelerator for the action (the accelerator is currently not displayed in the menu, but it might be in future versions);
+.\" .TP
+.\" -
+.\" one of the actions mentioned in the sections on KEYSTROKES above.
+.\" .RE
+.\" .PP
+.\" Instead of a submenu and an action, an entry may also contain the string
+.\" .RB `` SEP '' ;
+.\" in this case, a separator line is inserted after the preceding menu entry.
+.\" .PP
+.\" The default value of this resource is as follows:
+.\" .RS 5
+.\" .nf
+.\" .ft 3
+.\" .sp 1n
+.\" xdvi.menuTranslations: \e
+.\" File:Open ...:Ctrl-o:select-dvi-file()\en\e
+.\" File:Find ...:Ctrl-f:find()\en\e
+.\" File:Reload:R:reread-dvi-file()\en\e
+.\" File:Print ...:Ctrl-p:print()\en\e
+.\" File:Save as ...::save()\en\e
+.\" File:Quit:q:quit()\en\e
+.\" Navigate:First:1 g:goto-page(1)\en\e
+.\" Navigate:Page-10:10 p:back-page(10)\en\e
+.\" Navigate:Page-5:5 p:back-page(10)\en\e
+.\" Navigate:Prev:p:back-page(1)\en\e
+.\" Navigate:SEP:\en\e
+.\" Navigate:Next:n:forward-page(1)\en\e
+.\" Navigate:Page+5:5 n:forward-page(5)\en\e
+.\" Navigate:Page+10:10 n:forward-page(10)\en\e
+.\" Navigate:Last:g:goto-page()\en\e
+.\" Navigate:SEP:\en\e
+.\" Navigate:Back Hyperlink:B:htex-back()\en\e
+.\" Mark:Mark all:-1 m:toggle-mark(-1)\en\e
+.\" Mark:Unmark all:0 m:toggle-mark(0)\en\e
+.\" Mark:SEP:\en\e
+.\" Mark:Toggle odd:1 m:toggle-mark(1)\en\e
+.\" Mark:Toggle even:2 m:toggle-mark(2)\en\e
+.\" Mark:Toggle current:m:toggle-mark()\en\e
+.\" Zoom:Zoom in:Ctrl-+:set-shrink-factor(+)\en\e
+.\" Zoom:Zoom out:Ctrl--:set-shrink-factor(-)\en\e
+.\" Zoom:SEP:\en\e
+.\" Zoom:Fit in window:s:set-shrink-factor(a)\en\e
+.\" Zoom:SEP:\en\e
+.\" Zoom:$#:1 s:set-shrink-factor(1)\en\e
+.\" Zoom:$#:2 s:set-shrink-factor(2)\en\e
+.\" Zoom:$#:3 s:set-shrink-factor(3)\en\e
+.\" Zoom:$#:4 s:set-shrink-factor(4)\en\e
+.\" Zoom:$#:5 s:set-shrink-factor(5)\en\e
+.\" Zoom:$#:6 s:set-shrink-factor(6)\en\e
+.\" Zoom:$#:7 s:set-shrink-factor(7)\en\e
+.\" Zoom:$#:8 s:set-shrink-factor(8)\en\e
+.\" Zoom:$#:9 s:set-shrink-factor(9)\en\e
+.\" Options:View PS:1 v:set-ps(1)\en\e
+.\" Options:View PS + bbox:2 v:set-ps(2)\en\e
+.\" Options:No PS, bbox only:0 v:set-ps(0)\en\e
+.\" Options:SEP:\en\e
+.\" Options:Keep position:k:set-keep-flag(toggle)\en\e
+.\" Options:SEP:\en\e
+.\" Options:Fonts darker:Alt-Ctrl-+:change-density(25)\en\e
+.\" Options:Fonts lighter:Alt-Ctrl--:change-density(-25)\en\e
+.\" Help:About ...::help(helpGeneral)\en\e
+.\" Help:Page Motion ...::help(helpPagemotion)\en\e
+.\" Help:Other Commands ...::help(helpOthercommands)\en\e
+.\" Help:Mouse Buttons ...::help(helpMousebuttons)\en\e
+.\" Help:HyperTeX commands ...::help(helpHypertex)\en\e
+.\" Help:Source specials ...::help(helpSourcespecials)\en
+.\" .sp 1n
+.\" .ft
+.\" .fi
+.\" .RE
+.\" .PP
+.\" The label string may contain a colon if it is escaped by a backslash
+.\" (`\fB\\\fP'). (Note: Since the internal handling of menus requires
+.\" every menu label to be unique, xdvi's special strings for customizing
+.\" shrink factors in the buttons --
+.\" .RB ` $# ',
+.\" .RB ` $% '
+.\" and
+.\" .RB ' $_ '
+.\" -- are not supported by xdvik).
+.\" endif
+.PP
+Some resources are provided to allow customization of the geometry of
+the Xaw command buttons. Again, they are not changeable via command-line
+options, other than via the
+.B \-xrm
+option. All of these resources take integer values.
+.TP
+.B buttonSideSpacing
+The number of pixels to be placed on either side of the buttons.
+The default value is 6.
+.TP
+.B buttonTopSpacing
+The number of pixels between the top button and the top of the window.
+The default value is 50.
+.TP
+.B buttonBetweenSpacing
+The number of pixels between the buttons.
+The default value is 20.
+.TP
+.B buttonBetweenExtra
+The number of pixels of additional space to be inserted if the
+.B buttonTranslations
+resource string contains an extra newline character.
+The default value is 50.
+.TP
+.B buttonBorderWidth
+The border width of the button windows. The default value is 1.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH PAGE LIST
+The scrollable page list on the right of the main window allows you to
+jump directly to a page in the DVI file.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Mouse-1
+Jumps to the page the mouse is located on.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B Mouse-2
+.RB [ toggle-mark() ]
+Toggle the mark of the current page. The marks are used by the `Print'
+and `Save to file' dialogs to select only marked pages from the DVI file.
+.PP
+When the mouse pointer is inside the page list, the mouse wheel switches
+to the next or previous page.
+.PP
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SCROLLBARS
+The scrollbars (if present) behave in the standard way: pushing Button 2
+in a scrollbar moves the top or left edge of the scrollbar to that point
+and optionally drags it;
+pushing Button 1 moves the image up or right by an amount equal to the distance
+from the button press to the upper left-hand corner of the window; pushing
+Button 3 moves the image down or left by the same amount.
+.PP
+The scrollbars can be removed via the
+.I -expertmode
+flag/keystroke (which see).
+.PP
+Wheel mice are supported: motion of the wheel on such a mouse moves the
+image up or down by the number of pixels indicated by the
+.B \-wheelunit
+option. To access this option via customization, use the
+.B wheel
+action. This action takes one parameter, giving the distance to scroll
+the image. If the parameter contains a decimal point, the distance is given
+in wheel units; otherwise, pixels.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH MAGNIFIER
+By default, the mouse buttons 1 to 5 will pop up a ``magnifying glass''
+that shows an unshrunken image of the page (i.e. an image at the resolution
+determined by the option/X resource
+.B pixels
+or
+.BR mfmode )
+at varying sizes. When the magnifier is moved, small ruler-like
+tick marks are displayed at the edges of the magnifier (unless
+the X resource
+.B delayRulers
+is set to false, in which case the tick marks will always be displayed).
+The unit of the marks is determined by the X resource
+.B tickUnits
+(mm by default). This unit can be changed at runtime via the action
+.BR switch-magnifier-units() ,
+by default bound to the keystroke
+.RB ` t '
+(see the description of that key, and of switch-magnifier-units() for
+more details on the units available).
+.br
+The length of the tick marks can be changed via the X resource
+.B tickLength
+(4 by default). A zero or negative value suppresses the tick marks.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH PAGE HISTORY
+Xdvi keeps a history of viewed pages, and you can move through the history
+and delete items using the keys
+.B [
+.RI ( pagehistory-back() ),
+.B ]
+.RI ( pagehistory-forward() ),
+.B Ctr-[
+.RI ( pagehistory-delete-backward() )
+and
+.B Ctr-]
+.RI ( pagehistory-delete-forward() ).
+.PP
+When one of the history commands is used, the page history is displayed
+in the status line at the bottom of the window, with the current list
+item marked by square brackets `[', `]' and a left and right context of
+at most 10 items. File boundaries are marked by `#'.
+.PP
+The size of the history can be customized with the X resource
+.B pageHistorySize
+(the default size is 1000 items). If the size is set to 0, the
+history commands are disabled.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH HYPERLINKS
+The actions
+.B do-href()
+and
+.B do-href-newwindow()
+(by default bound to Mouse-1 and Mouse-2 if the pointer is currently located
+on a hyperlink) can be used to open the link target in the same window
+.RB ( do-href() )
+or in a new window
+.RB ( do-href-newwindow() ).
+.PP
+If the link target is not a file on the local disk,
+xdvi tries to launch a web browser (as specified by the
+.B -browser
+command line option, the
+.B BROWSER
+environment variable or the
+.B wwwBrowser
+X resource, in this order) to retrieve the document. See the description
+of the
+.B BROWSER
+environment variable, below, for an example setting.
+.PP
+If the file is a local file, xdvi tries to determine if it is a DVI
+file. If it is, xdvi will try to display the file; otherwise it will
+try to determine the MIME type of the file, and from that an
+application suitable for opening the file.
+This is done by parsing the files specified by the environment variable
+.B EXTENSIONMAPS
+for a mapping of filename extensions to MIME types,
+and the files determined by the environment variable
+.B MAILCAPS
+for a mapping of MIME types to application programs.
+See the descriptions of these variables in the section
+.BR ENVIRONMENT ,
+below, for a more detailed description and the default values of these
+variables. If no suitable files are found, a set of built-in default
+MIME types and applications is used.
+.PP
+Xdvi currently uses no heuristics apart from the filename suffix
+to determine the mime type of a file. If a filename has no suffix,
+the value of the resource
+.B noMimeSuffix
+is used (by default
+.IR application/x-unknown ).
+If the suffix doesn't match any of the suffixes in
+.BR mime.types ,
+the value of the resource
+.B unknownMimeSuffix
+is used (by default
+.IR application/x-unknown ).
+If the
+.B mailcap
+entries do not list a viewer for a given mime type, xdvi will show
+a warning popup. If you want to avoid this warning, and for example
+want to always use the netscape browser for unknown MIME types,
+you could add the following line to your ~/.mailcap file:
+.RS 4
+.nf
+.ft 3
+.sp 1n
+application/xdvi-unknown; \e
+ netscape -raise -remote 'openURL(%s,new-window)'
+.sp 1n
+.ft
+.fi
+.RE
+.\" As an example, consider the following settings, which are the default
+.\" settings for buttons 1 and 2:
+.\" .RS 5
+.\" .nf
+.\" .ft 3
+.\" .sp 1n
+.\" xdvi.mainTranslations: #override \e
+.\" <Btn1Down>: do-href()magnifier(*1)\en\e
+.\" <Btn2Down>: do-href-newwindow()magnifier(*2)\en\e
+.\" <Btn3Down>: magnifier(*3)\en
+.\" .sp 1n
+.\" .ft
+.\" .fi
+.\" .RE
+.\" .PP
+.\" If a link points to a file which is not a DVI file (e.g. HTML, or
+.\" PostScript), the files
+.\" .B mime.types
+.\" and
+.\" .B mailcap
+.\" are parsed to determine a suitable viewer; if no suitable
+.\" .B mailcap
+.\" entry was found, if the
+.\" .SB WWWBROWSER
+.\" environment variable is set, or
+.\" .B \-browser
+.\" was specified on the command line, the browser is launched to load the file.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH STRING SEARCH
+The keystroke
+.I Ctrl-f
+or the menu entry
+.I File > Find ...
+(or the `Binoculars' symbol in the toolbar, for Motif)
+opens a dialog window to search for a text string or
+a regular expression in the DVI file.
+The keystroke
+.I Ctrl-g
+jumps to the next match (like pressing the `Find' button in the search window).
+.PP
+By default, the matches are highlighted in inverted color.
+If the display isn't running in TrueColor, or if the X resouce
+.B matchHighlightInverted
+is set to false or the command-line option
+.B \-nomatchinverted
+is used, xdvi will instead draw a rectangle in
+.I highlight
+color (see the
+.B \-hl
+option) around the match.
+.PP
+If a match crosses a page boundary, only the part on the
+first page is highlighted.
+.B Xdvi
+will scan up to 2 adjacent pages to match strings crossing page
+boundaries; but note that header or footer
+lines, or intervening float pages will be treated as parts of the
+scanned text. Such text will usually cause multi-page matching to fail.
+.PP
+This emphasizes the fact that searching in the
+formatted text (the DVI output) works differently from
+searching in the source text: Searching in the DVI file makes it easier to
+skip formatting instructions, and makes it possible to search for e.g.
+hyphenation and equation numbers; but sometimes the
+formatting results can also get in the way, e.g. in the case of
+footnotes. In these cases it's better to search in the \*(Te\& source
+instead. The use of
+.I source specials
+will make switching between the
+xdvi display and the editor with the \*(Te\& source easier; see the
+section
+.B SOURCE SPECIALS
+below for more information on this.
+.PP
+The text extracted from the DVI file is in encoded in UTF-8
+(you can view that text by saving the file in UTF-8 format via the
+.I File > Save as ...
+menu item).
+If xdvi has been compiled with locale,
+.I nl_langinfo()
+and
+.I iconv
+support, the search term is converted from the character set
+specified by the current locale into UTF-8. (See the output of
+.B locale -a
+for a list of locale settings available on your system).
+If
+.I nl_langinfo()
+is not available, but
+.I iconv
+is, you can specify the input encoding for
+.I iconv
+via the X resource
+.I textEncoding
+(see the output of
+.B iconv -l
+for a list of valid encodings). If
+.I iconv
+support is not available, only the encodings
+.I ISO-8859-1
+and
+.I UTF-8
+are supported (these names are case-insensitive).
+.PP
+Ideographic characters from CJKV fonts are treated specially: All white space
+(spaces and newlines) before and after such characters is ignored in
+the search string and in the DVI file.
+.PP
+To match a newline character, use \fI\en\fR in the search string;
+to match the string \fI\en\fR, use \fI\e\en\fR.
+.PP
+If the checkbox
+.I Regular Expression
+is activated, the string is treated as a regular expression in
+extended POSIX syntax, with the following properties:
+.RS 2
+.TP 2
+-
+\fIa?\fR matches \fIa\fR zero or one times.
+.TP
+-
+\fIa*\fR matches \fIa\fR zero or more times.
+.TP
+-
+\fIa+\fR matches \fIa\fR one or more times.
+Note that \fI*\fR and \fI+\fR are greedy, i.e. they match the longest possible substring.
+.TP
+-
+The pattern \fI.\fR matches any character except for newline. To also match a newline, use `\fI(.|\en)\fR'.
+.TP
+-
+\fIa{n}\fR matches \fIa\fR exactly n times.
+.TP
+-
+\fIa{n,m}\fR matches \fIa\fR at least n and no more than m times.
+.TP
+-
+\fIa|b\fR matches \fIa\fR or \fIb\fR. Brackets can be used
+for grouping, e.g.: \fI(a|b)|c\fR.
+.TP
+-
+The string matched by the nth group can be referenced by \fI\en\fR, e.g. \fI\e1\fR refers to the
+first match.
+.TP
+-
+The characters \fI^\fR and \fI$\fR match the beginning and the end of a line, respectively.
+.TP
+-
+\fI[abc]\fR matches any of the letters a, b, c, and \fI[a-z]\fR matches all characters from a to z.
+.TP
+-
+Each item in a regular expression can also be one of the following POSIX
+character classes:
+.br
+.nf
+.I [[:alnum:]] [[:alpha:]] [[:blank:]] [[:cntrl:]] [[:digit:]]
+.I [[:graph:]] [[:lower:]] [[:print:]] [[:space:]] [[:upper:]]
+.fi
+
+
+These can be negated by inserting a \fI^\fR symbol after the first bracket:
+.I [^[:alpha:]]
+
+For more details on POSIX regular expressions, see e.g. the
+.B IEEE Std 1003.1
+standard definition available online from:
+
+.nf
+http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap09.html
+.fi
+.TP
+-
+As a non-standard extension, the following Perl-like abbreviations
+can be used instead of the POSIX classes:
+.nf
+.sp 1n
+.ta 1L +8L +30L
+Symbol Meaning POSIX Class
+
+ \fI\ew\fR an alphanumeric character \fI[[:alnum:]]\fR
+ \fI\eW\fR a non-alphanumeric character \fI[^[:alnum:]]\fR
+ \fI\ed\fR a digit character \fI[[:digit:]]\fR
+ \fI\eD\fR a non-digit character \fI[^[:digit:]]\fR
+ \fI\es\fR a whitespace character \fI[[:space:]]\fR
+ \fI\eS\fR a non-whitespace character \fI[^[:space:]]\fR
+.sp 1n
+.fi
+.TP
+-
+The following characters are special symbols; they need to be escaped
+with \fI\e\fR in order to match them literally: \fI ( ) [ ] . * ? + ^ $ \e\fR.
+.TP
+-
+Matches of length zero are silently skipped.
+.RE
+.PP
+The dialog also provides checkboxes to:
+.RS 2
+.TP 2
+-
+search backwards;
+.TP
+-
+match in a case-sensitive manner (the default is to ignore case, i.e. a search
+string
+.I Test
+will match both the strings
+.I test
+and
+.I TEST
+in the DVI file);
+.TP
+-
+ignore line breaks and hyphens: This removes all hyphens at the ends
+of lines and the following newline characters, and replaces all
+remaining newline characters by white spaces. So hyphenated words will
+appear as one word to the search, and a search for two words with a space
+in between will also match the words if they are separated by a linebreak.
+.br
+Note that the hyphen removal may cause unwanted side effects for compound words
+containing hyphens that are wrapped after the hyphen, and that replacing the
+newlines affects the interpretation of regular expressions as follows:
+The \fI.\fR pattern will also match newlines, and \fI^\fR and \fI$\fR won't match
+begin and end of lines any more. (Since currently there is no option for turning
+off the greediness of \fI*\fR and \fI+\fR, turing on this option will usually
+result in matches that are longer than desired.)
+.RE
+.PP
+The current checkbox settings are saved in the
+.I ~/.xdvirc
+file.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH PRINT DIALOG
+The print dialog window allows you to print all pages, marked pages
+(click or drag Mouse-2 in the page list to mark them), or a range
+of pages. Note that the page numbers always refer to physical pages,
+so if you're using the option `use TeX pages', you may want to disable
+it to make it easier to determine the correct page numbers (or avoid this
+problem altogether by marking the pages to be printed).
+.PP
+The value of the
+.B Printer
+text filed is passed to
+.B dvips
+via the
+.B -o!
+mechanism, as a single argument after the `!'. Any arguments
+listed in the
+.B Dvips options
+field are segmeted at whitespaces and passed as separate arguments to dvips.
+If you e.g. want to print the file 2-up, you should enter
+the following string into the
+.B Printer
+field:
+.RS 5
+.nf
+.sp 1n
+ \fIpsnup -2 -q | lpr -Plp\fP
+.sp 1n
+.fi
+.RE
+.PP
+There are several resources for customizing the behaviour and the default entries
+of the print dialog:
+.TP
+.B dvipsPrinterString
+.TP
+.B dvipsOptionsString
+These can be used to provide default entries for the
+.B Printer
+and the
+.B Dvips options
+text fields, respectively. If no paper size is specified in the DVI file
+(via e.g. \eusepackage[dvips]{geometry} - this is the preferred method),
+the input field is initialized with the current value of the
+command line option/X resource
+.BR paper .
+E.g., the option
+.I -paper a4r
+is translated into the dvips options
+.IR "-t a4 -t landscape" .
+Note that no check is performed whether dvips actually understands these
+options (it will ignore them if it can't); currently not all options
+used by xdvi are also covered by dvips.
+.TP
+.B dvipsHangTime
+.TP
+.B dvipsFailHangTime
+These specify the time (in milliseconds) that the printing progress window will
+stay open after the
+.B dvips
+process has terminated. The value of
+.BR dvipsHangTime
+is used if the process terminates successfully;
+.B dvipsFailHangTime
+is used if it terminates with an error. The default values are 1.5 and 5 seconds, respectively.
+If both values are negative, the window will stay open until it is closed by the user.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SAVE DIALOG
+This dialog allows you to save all or selected/marked pages in the current
+DVI file. You can save in one of the following formats:
+.RS 2
+.TP 2
+-
+Postscript (uses
+.B dvips
+to convert the DVI file to a Postscript file, just like when printing
+to a Postscript file).
+.TP
+-
+PDF (first uses
+.B dvips
+to convert the DVI file to a Postscript file, then uses
+.B ps2pdf
+to convert the Postscript file to PDF).
+.TP
+-
+Plain text in ISO-8859-1 or UTF-8 encoding (the latter will preserve more
+of the special LaTeX characters e.g. from mathematical mode).
+If a character cannot be displayed in the selected
+charset, it is replaced by `\e' followed by the hexadecimal character code.
+If a character is not recognized at all, it is replaced by `?'.
+If you think that xdvi should recognize a character but doesn't,
+please send a feature request to the address given in
+.B AUTHORS
+below. Likewise, if you observe spurious spaces or unwanted linebreaks in
+the output, please report this as a bug.
+.RE
+.PP
+The programs for Postscript and PDF conversion can be customized via
+the command line options or X resources
+.BR -dvipspath / .dvipsPath
+and
+.BR -ps2pdfpath / .ps2pdfPath ,
+respectively; see the explanation of these options above for more details.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH MODES
+The keystroke
+.B Ctrl-m
+[\fBswitch-mode()\fR]
+switches between three different bindings for
+.BR Mouse-1 ,
+which can also be activated via the
+.B Modes
+menu (in Motif, this is a submenu of the
+.B Options
+menu called
+.BR "Mouse Mode" ).
+The default mode at startup can be customized via the X resource
+.B mouseMode
+or the command-line option
+.BR \-mousemode .
+The default startup mode is Magnifier Mode.
+.PP
+.B Note:
+The modes are implemented by changing the
+.I magnifier()
+action. Switching the mode will not work if
+.B Mouse-1
+has been customized to an action sequence that does
+not contain the magnifier() action.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B "Magnifier Mode"
+In this mode, the mouse buttons 1 to 5 pop up a ``magnifying glass''
+that shows an unshrunken image of the page (i.e. an image at the resolution
+determined by the option/X resource
+.B pixels
+or
+.BR mfmode )
+at varying sizes. When the magnifier is moved, small ruler-like
+tick marks are displayed at the edges of the magnifier (unless
+the X resource
+.B delayRulers
+is set to false, in which case the tick marks are always displayed).
+The unit of the marks is determined by the X resource
+.B tickUnits
+(mm by default). This unit can be changed at runtime via the action
+.BR switch-magnifier-units() ,
+by default bound to the keystroke
+.RB ` t '
+(see the description of that key, and of switch-magnifier-units() for
+more details on the units available).
+.br
+The length of the tick marks can be changed via the X resource
+.B tickLength
+(4 by default). A zero or negative value suppresses the tick marks.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B "Text Selection Mode"
+This mode allows you to select a rectangular region of text in the DVI
+file by holding down
+.B Mouse-1
+and moving the mouse. The text is put into
+the X primary selection so that it can be pasted into other X applications
+with
+.B Mouse-2
+as usual.
+.br
+If xdvi has been compiled with locale,
+.I nl_langinfo()
+and
+.I iconv
+support, the selected text is converted into the character set of the
+current locale (see the output of
+.B locale -a
+for a list of locale settings available on your system).
+If
+.I nl_langinfo()
+is not available, but
+.I iconv
+is, you can specify the input encoding for
+.I iconv
+via the X resource
+.I textEncoding
+(see the output of
+.B iconv -l
+for a list of valid encodings). If
+.I iconv
+support is not available, only the encodings
+.I ISO-8859-1
+and
+.I UTF-8
+are supported (these names are case-insensitive).
+.br
+Note that UTF-8 is
+the only encoding that can render all characters (e.g. mathematical
+symbols) of a DVI file. If ISO-8859-1 is active, characters that cannot be displayed
+are replaced by `\e' followed by the hexadecimal character code.
+For other encodings, such characters may trigger iconv error messages.
+If a character is not recognized at all, it is replaced by `?'.
+.br
+To extract larger portions of text, you can alternatively
+save selected pages or the entire file in text format via the
+.B File > Save as ...
+menu.
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.B "Ruler Mode"
+This mode provides a simple way of measuring distances on the page.
+.br
+When this mode is activated, the mouse cursor changes into a
+thin cross, and a larger, cross-shaped ruler is drawn in the
+highlight color at the mouse location. The ruler doesn't have
+units attached to it; instead, the current distance between the
+ruler and the mouse cursor is continously printed to the
+statusline.
+.br
+When activating Ruler Mode, the ruler is at first attached to
+the mouse and can be moved around. It can then be positioned at
+a fixed place by clicking
+.BR Mouse-1 .
+After that, the mouse cursor
+can be moved to measure the horizontal
+.RI ( dx ),
+vertical
+.RI ( dy )
+and direct (shortest)
+.RI ( dr )
+distance between the ruler center point and the mouse.
+.br
+Clicking
+.B Mouse-1
+again will move the ruler to the current mouse
+position, and holding down
+.B Mouse-1
+will drag the ruler around.
+.br
+In Ruler Mode, the following special keybindings extend or
+replace the default bindings:
+.RS 7
+.TP 7
+.B o
+.RB [ ruler-snap-origin() ]
+Snap the ruler back to the origin coordinate (0,0).
+.TP
+.B t
+\fR[overrides \fBswitch-magnifier-units()\fP]
+Toggle between various ruler units, which can be specified by the X
+resource
+.B tickUnits
+(`mm' by default).
+.TP
+.B P
+\fR[overrides \fBdeclare-page-number()\fP]
+Print the distances shown in the statusline to standard output.
+.RE
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH TOOLBAR (Motif only)
+The Motif toolbar can also be customized. The XPM file used for the
+toolbar icons can be specified via the resource
+.BR toolbarPixmapFile ,
+which should contain a filename that can be found in one of
+.B XFILESEARCHPATH
+or
+.B XDVIINPUTS
+(see the section
+.B FILE SEARCHING
+below for more information on these variables).
+Xdvi will try to split this pixmap horizontally into
+.I n
+pieces, where each piece is as wide as the pixmap is high
+and is treated as an image for toolbar button
+.IR n .
+This means that each icon should be a square, and that the entire
+pixmap should have width
+\fIn\fR x \fIh\fR if \fIh\fR is the height of the pixmap.
+.PP
+The resource
+.B toolbarTranslations
+can be used to map icons/buttons to specific actions.
+The resource should contain a string separated by newline characters,
+similar to the resources
+.B mainTranslations
+and
+.BR menuTranslations .
+Every line must contain either a spacer definition, or an icon definition:
+.PP
+A spacer definition is a string \fBSPACER(\fIn\fB)\fR,
+where
+.I n
+is the number of pixels inserted as separator to the following button.
+.PP
+An icon definition is a colon-separated list containing the following elements:
+.RS 2
+.TP 2
+.SB - the index of an icon in the pixmap file (starting from zero);
+.TP
+.SB - a long tooltip string, displayed in the status area;
+.TP
+.SB - a short tooltip string, displayed as popup;
+.TP
+.SB - a sequence of actions to be performed when the corresponding toolbar button is pushed.
+.RE
+.PP
+To illustrate this, the default value of
+.B toolbarTranslations
+looks as follows:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+xdvi.toolbarTranslations: \e
+ SPACER(5)\en\e
+ 0:Open a new document (Key\e\e: Ctrl-f):\e
+ Open file:select-dvi-file()\en\e
+ SPACER(10)\en\e
+ 1:Reread this document (Key\e\e: R):\e
+ Reread file:reread-dvi-file()\en\e
+ SPACER(10)\en\e
+ 2:Go to the first page of this document (Key\e\e: 1g):\e
+ Go to first page:goto-page(1)\en\e
+ 3:Go to the previous page of this document (Key\e\e: p):\e
+ Go to previous page:back-page(1)\en\e
+ 4:Go to the next page of this document (Key\e\e: n):\e
+ Go to next page:forward-page(1)\en\e
+ 5:Go to the last page of this document (Key\e\e: g):\e
+ Go to last page:goto-page()\en\e
+ SPACER(10)\en\e
+ 6:Enlarge the display (Key\e\e: Ctrl-+):Zoom in:\e
+ set-shrink-factor(+)\en\e
+ 7:Shrink the display (Key\e\e: Ctrl--):Zoom out:\e
+ set-shrink-factor(-)\en\e
+ SPACER(10)\en\e
+ 8:Jump back to the previous hyperlink (Key\e\e: B):\e
+ Back hyperlink:htex-back()\en\e
+ SPACER(10)\en\e
+ 10:Print this document:Print:print()\en\e
+ SPACER(10)\en\e
+ 11:Toggle marks for odd pages (Key\e\e: 1m):\e
+ Toggle odd:toggle-mark(1)\en\e
+ 12:Toggle marks for even pages (Key\e\e: 2m):\e
+ Toggle even:toggle-mark(2)\en\e
+ 13:Toggle mark for current page (Key\e\e: 2m):\e
+ Toggle current:toggle-mark()\en\e
+ 14:Unmark all pages (Key\e\e: 0m):\e
+ Unmark all:toggle-mark(0)\en\e
+ SPACER(10)\en\e
+ 18:Display fonts darker (Key\e\e: Alt-Ctrl-+):\e
+ Fonts darker:change-density(5)\en\e
+ 19:Display fonts lighter (Key\e\e: Alt-Ctrl--):\e
+ Fonts lighter:change-density(-5)\en
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+When the mouse remains over a toolbar button for a certain period, a `tooltip'
+window is shown, describing what the button does using the
+.I short tooltip string
+from the above resource. At the same time, the
+.I long tooltip string
+is displayed in the statusline.
+The appearance and behaviour of these tooltips can be customized via
+the following resources:
+.TP
+.B tipShell.background
+Background color of the tooltip window.
+.TP
+.B tipShell.fontSet
+Font used for the tooltip.
+.TP
+.B tipShell.waitPeriod
+The time (in milliseconds) the mouse pointer needs to be over
+the button before the tooltip is shown. Set it to a negative value
+to suppress the tooltips altogether.
+
+#ifgrey
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH GREYSCALING AND COLORMAPS
+The greyscale anti-aliasing feature in
+.B xdvi
+will not work at its best if the display does not have enough colors available.
+This can happen if other applications are using most of the colormap
+(even if they are iconified). If this occurs, then
+.B xdvi
+will print an error message and turn on the
+.B -copy
+option. This will result in overstrike characters appearing wrong;
+it may also result in poor display quality if the number of available
+colors is very small.
+.PP
+Typically this problem occurs on displays that allocate eight bits
+of video memory per pixel. To see how many bits per pixel your display
+uses, type
+.B xwininfo
+in an
+.B xterm
+window, and then click the mouse on the root window when asked. The
+``Depth:'' entry will tell you how many bits are allocated per pixel.
+.PP
+Displays using at least 15 bits per pixel are typically
+.B TrueColor
+visuals, which do not have this problem, since their colormap is
+permanently allocated and available to all applications. (The visual
+class is also displayed by
+.BR xwininfo .)
+For more information on visual classes see the documentation for the
+X Window System.
+.PP
+To alleviate this problem, therefore, one may (a) run with more bits
+per pixel (this may require adding more video memory or replacing the video
+card), (b) shut down other applications that may be using much of the colormap
+and then restart
+.BR xdvi ,
+or (c) run
+.B xdvi
+with the
+.B \-install
+option.
+.PP
+One application which is often the cause of this problem is
+.BR Netscape .
+In this case there are two more alternatives to remedying the situation.
+One can run
+.RB `` "netscape -install" ''
+to cause
+.B Netscape
+to install a private colormap. This can cause colors to change in
+bizarre ways when the mouse is moved to a different window.
+Or, one can run
+.RB `` "netscape -ncols 220" ''
+to limit
+.B Netscape
+to a smaller number of colors. A smaller number will ensure that
+other applications have more colors available, but will degrade the
+color quality in the
+.B Netscape
+window.
+#endif
+
+#ifps
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH HANDLING OF POSTSCRIPT FIGURES
+.B Xdvi
+can display Encapsulated PostScript (EPS) files included in the
+.I dvi
+file. Such files are first searched for in the directory where the
+.I dvi
+file is, and then using normal
+.B Kpathsea
+rules. There is an exception to this, however: if the file name begins
+with a backtick
+.RB ( ` ),
+then the remaining characters in the file name give a shell command (often
+.BR zcat )
+which is executed; its standard output is then sent to be interpreted as
+PostScript.
+Since the execution of arbitrary shell commands with the user's
+permissions is a huge security risk, evaluation of these backtick
+commands is disabled by default. It needs to be activated via the
+.B \-allowshell
+command-line option.
+.B NOTE:
+You should never use this option when viewing documents that you
+didn't compile yourself. The backtick specials are not needed for
+uncompressing gzipped Postscript files, since
+.B xdvi
+can do that on the fly if the filename ends with
+.I .eps.gz
+or
+.I .eps.Z
+(and if the first bytes of the file indicate that the file is indeed
+compressed). This is both safer and more flexible than the backtick
+approach, since the default file searching rules will apply to such
+filenames too.
+#endif
+#ift1
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH T1LIB
+Using T1Lib, a library written by Rainer Menzner
+(see ftp://sunsite.unc.edu/pub/Linux/libs/graphics/),
+.B xdvi
+can render Postscript<tm> Type1 fonts directly, without the
+route via \*(Te\& pixel (pk)
+fonts. The advantage of this is that only one size of each font needs
+to be stored on disk.
+Unless the
+.B -not1lib
+option is used,
+.B xdvi
+will try to render every font using T1Lib. Only as a fallback it will
+invoke an external program (like
+.BR mktexpk ,
+which in turn may invoke utilities like
+.B ps2pk
+or
+.BR gsftopk )
+to generate a pixel font from the Type1 source. The direct rendering
+of the
+.B Computer Modern
+fonts should work out-of-the box, whereas other Type1 fonts such as
+the 35 `standard' Postscript<tm> fonts resident in printers may need
+to be made accessible for use with xdvi, unless your system
+administrator or TeX distribution has already done so (which is the case
+e.g. for current teTeX systems). The
+.B xdvik
+distribution comes with a utility called
+.B t1mapper
+to make these fonts available for xdvi;
+see the manual page for t1mapper(1) for usage details.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SPECIALS (GENERALLY)
+Any of the specials used by
+.B xdvi
+may be preceded by the characters
+.RB `` xdvi: ''.
+Doing so does not change the behavior of the special under
+.BR xdvi ,
+but it tells other dvi drivers (such as e.g. dvips) to ignore the special.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SOURCE SPECIALS
+Some \*(Te\& implementations or macro packages provide the facility to
+automatically include so-called `source specials' into a DVI file.
+These contain the line number, eventually a column number, and the
+filename of the .tex source. This makes it possible to jump from a .dvi
+file to the corresponding place in the .tex source and vice versa (also
+called `inverse search' - jumping from the DVI file to the TeX file is
+also known as `reverse search', and jumping from the TeX file to the
+DVI file as `forward search').
+.P
+To be usable with
+.BR xdvi ,
+source specials in the
+.I dvi
+file must have one of the following formats:
+.RS 5
+.nf
+.sp 1n
+ \fBsrc:\fP\fIline\fP[ ]\fIfilename\fP
+ \fBsrc:\fP\fIline\fP\fB:\fP\fIcol\fP[ ]\fIfilename\fP
+ \fBsrc:\fP\fIline\fP
+ \fBsrc:\fP\fIline\fP\fB:\fP\fIcol\fP
+ \fBsrc::\fP\fIcol\fP
+.sp 1n
+.fi
+.RE
+If
+.I filename
+or
+.I line
+are omitted, the most recent values are used. The first source special on
+each page must be in one of the first two forms, since defaults are not
+inherited across pages.
+.sp
+You will need a \*(Te\& implementation that provides an appropriate
+switch (e.g.
+.IR -src )
+or a macro package
+(such as
+.I srcltx.sty
+or
+.IR srctex.sty ,
+available from CTAN:macros/latex/contrib/supported/srcltx/)
+to insert such source specials into the DVI file.
+.sp
+For reverse search, the combination
+.I Ctrl-Mouse 1
+will make xdvi open an editor (the value of the
+.I \-editor
+command line option) with the file and the line number of the .tex
+source. See the description of the
+.I \-editor
+option for more information
+and example settings.
+.P
+For forward search,
+.B xdvi
+has a
+.I \-sourceposition
+option that makes
+.B xdvi
+jump to the page in
+the DVI file corresponding to the given line (or the closest
+line having a source special) of the specified file and highlight
+the found region. See the description of the
+.I \-sourceposition
+option for more details.
+.PP
+More information on setting up various editors for use with source
+specials can be found at:
+.RS 5
+.nf
+.sp 1n
+http://xdvi.sourceforge.net/inverse-search.html
+.sp 1n
+.fi
+.RE
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH PAPERSIZE SPECIALS
+.B xdvi
+accepts specials to set the paper size for the document. These specials
+should be of the form
+.RS 5
+.nf
+.sp 1n
+ \fBpapersize=\fP[\fB*\fP]\fIwidth\fP,\fIheight\fP
+.sp 1n
+.fi
+.RE
+.PP
+where
+.I width
+and
+.I height
+give the width and height of the paper, respectively. Each of these should
+appear in the form of a decimal number followed by any of the two-letter
+abbreviations for units accepted by \*(Te\&
+.RB ( pt ,
+.BR pc ,
+.BR in ,
+.BR bp ,
+.BR cm ,
+.BR mm ,
+.BR dd ,
+.BR cc ,
+or
+.BR sp ).
+If an asterisk
+.RB ( * )
+appears just before the width, then the measurements refer to the document
+dimensions (e.g.,
+.B pt
+as opposed to
+.BR truept ).
+This allows a macro package to vary the page size according to elements
+of the document; e.g.,
+.RS 5
+.ft 3
+.nf
+.sp 1n
+\especial{xdvi: papersize=*\enumber\ewd\emybox sp,
+ \enumber\eht\emybox sp}
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+Except for the asterisk, this format is compatible with
+.BR dvips .
+.P
+The last
+.B papersize
+special on a page determines the size of that page. If there is no such
+special on a given page, the most recent
+.B papersize
+is used, or, if there are no
+.B papersize
+specials on any preceding page, then the value of the
+.B paper
+resource (or
+.B \-paper
+option on the command line) is used. Thus the paper size may vary for
+different pages of the
+.I dvi
+file.
+.P
+If the
+.B paper
+resource (or
+.B \-paper
+command-line option) begins with a plus sign
+.RB (` + '),
+then all
+.B papersize
+specials in the
+.I dvi
+file are ignored.
+#ifcolor
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH COLOR SPECIALS
+The color specials supported by
+.B xdvi
+are the same as those supported by
+.BR dvips ,
+except that the literal PostScript color specification (as in the
+.B AggiePattern
+example in the
+.B dvips
+documentation) is not supported.
+There are also some restrictions due to the way xdvi's drawing routines
+are implemented; e.g. the \ecolorbox and \efcolorbox macros don't work
+with xdvi. See the section LIMITATIONS below for more information on these
+restrictions.
+Xdvi supports the same list of named colors as with
+.BR dvips ,
+namely:
+.P
+.BR Apricot ,
+.BR Aquamarine ,
+.BR Bittersweet ,
+.BR Black ,
+.BR Blue ,
+.BR BlueGreen ,
+.BR BlueViolet ,
+.BR BrickRed ,
+.BR Brown ,
+.BR BurntOrange ,
+.BR CadetBlue ,
+.BR CarnationPink ,
+.BR Cerulean ,
+.BR CornflowerBlue ,
+.BR Cyan ,
+.BR Dandelion ,
+.BR DarkOrchid ,
+.BR Emerald ,
+.BR ForestGreen ,
+.BR Fuchsia ,
+.BR Goldenrod ,
+.BR Gray ,
+.BR Green ,
+.BR GreenYellow ,
+.BR JungleGreen ,
+.BR Lavender ,
+.BR LimeGreen ,
+.BR Magenta ,
+.BR Mahogany ,
+.BR Maroon ,
+.BR Melon ,
+.BR MidnightBlue ,
+.BR Mulberry ,
+.BR NavyBlue ,
+.BR OliveGreen ,
+.BR Orange ,
+.BR OrangeRed ,
+.BR Orchid ,
+.BR Peach ,
+.BR Periwinkle ,
+.BR PineGreen ,
+.BR Plum ,
+.BR ProcessBlue ,
+.BR Purple ,
+.BR RawSienna ,
+.BR Red ,
+.BR RedOrange ,
+.BR RedViolet ,
+.BR Rhodamine ,
+.BR RoyalBlue ,
+.BR RoyalPurple ,
+.BR RubineRed ,
+.BR Salmon ,
+.BR SeaGreen ,
+.BR Sepia ,
+.BR SkyBlue ,
+.BR SpringGreen ,
+.BR Tan ,
+.BR TealBlue ,
+.BR Thistle ,
+.BR Turquoise ,
+.BR Violet ,
+.BR VioletRed ,
+.BR White ,
+.BR WildStrawberry ,
+.BR Yellow ,
+.BR YellowGreen ,
+.BR YellowOrange .
+.P
+Note that these names are case sensitive.
+.P
+The documentation of the La\*(Te\&
+.B color
+package provides more details on how to use such specials with
+La\*(Te\&; see the
+.B dvips
+documentation for a detailed description of the
+syntax and semantics of the color specials.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SIGNALS
+When
+.B xdvi
+receives a
+.SB SIGUSR1
+signal, it rereads the
+.I dvi
+file.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ENVIRONMENT
+.B Xdvik
+uses the same environment variables and algorithms for searching for
+font files as \*(Te\& and friends. See the documentation for the
+.B Kpathsea
+library,
+.BR kpathsea.dvi ,
+for a detailed description of these.
+.PP
+In addition,
+.B xdvik
+accepts the following variables:
+.TP
+.SB DISPLAY
+Specifies which graphics display terminal to use.
+#ifnokpathsea
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.SB XDVISIZES
+A list of font resolutions separated by colons. If a font cannot be found
+or made at its stated size, then these sizes are tried as a fallback.
+See the `Fallback font' section in the
+.B Kpathsea
+manual for more details.
+.B xdvi
+tries the actual size of the font before trying any of the given sizes.
+Each font resolution should be a positive integer, specifying the number
+of dots per inch, or a string of the form
+.BR magstep\fIn\fP ,
+where
+.I n
+is a number -9.5, -9, -8.5, ..., 8, 8.5, 9, or 9.5. The string
+.B magstep
+may be shortened to any non-empty initial substring (so that
+.B magstep0.5
+may be shortened to
+.B mag0.5
+or
+.B m0.5
+(but not
+.BR mag.5 )).
+The entries
+.BI magstep n
+signify the current pixels-per-inch value, multiplied by 1.2 raised to the
+.IR n th
+power, and rounded to the nearest integer.
+If the list begins with a colon, the system default sizes are used, as well.
+Sizes are expressed in dots per inch and must be integers.
+The current default set of sizes is @DEFAULT_FONT_SIZES@.
+#endif
+.TP
+.SB KPATHSEA_DEBUG
+Trace
+.B Kpathsea
+lookups; set it to
+.B -1
+(= all bits on) for complete tracing.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.SB EXTENSIONMAPS
+A list of files to be searched for mime types entries (as for Acrobat Reader).
+Earlier entries in one of these files override later ones.
+If this variable is not set, the following default path is used:
+.RS 7
+.nf
+.ft 3
+.sp 1n
+$HOME/.mime.types:/etc/mime.types:\e
+ /usr/etc/mime.types:/usr/local/etc/mimetypes
+.sp 1n
+.ft
+.fi
+.RE
+
+.TP
+.SB MAILCAPS
+A list of files to be searched for mailcap entries, as defined by RFC
+1343. See this RFC or the
+.BR mailcap (4)
+manual page for a detailed description of the mailcap file format.
+Currently, only the following mailcap features are supported:
+.RS 7
+.TP 7
+.BI test= command
+The entry is only used if
+.I command
+can be executed via the
+.B system()
+call and if the system() call returns with value 0 (success).
+The
+.I command
+string may contain the format string
+.IR %s ,
+which will be replaced by the file name.
+.TP
+.BI needsterminal
+If this flag is used, the command will be executed in a new xterm
+window by prepending
+.RI `` "xterm -e "''
+to the command string.
+.RE
+.PP
+.RS 7
+All other fields in the mailcap entry are ignored by xdvi.
+Earlier entries in one of these files override later ones.
+If the variable is not defined, the following default path is used:
+.RS 4
+.nf
+.ft 3
+.sp 1n
+$HOME/.mailcap:/etc/mailcap:/usr/etc/mailcap:\e
+ /usr/local/etc/mailcap
+.sp 1n
+.ft
+.fi
+.RE
+.br
+For security reasons, some special characters (i.e.: ( ) ` \e ;)
+are escaped in the argument before passing it to
+.BR system() .
+.RE
+.TP
+.SB BROWSER
+Determines the web browser used to open external links (i.e., all URLs that don't
+start with the
+.RI ` file: '
+scheme and are not relative links in the local DVI file), and to open links
+for which no viewer has been specified in the
+.B mailcap
+files. The value of this variable is a colon-separated list of commands. Xdvi
+will try each of them in sequence until one succeeds (i.e. doesn't immediately
+return with status 0). This allows you to
+specify your favourite browser at the beginning,
+and fallback browsers at the end. Every occurrence of
+.I %s
+in the string is replaced by the target URL; every occurrence of
+.I %%
+is replaced by a single
+.IR % .
+If no
+.I %s
+is present, the URL string is added as an extra argument.
+.br
+An example setting is:
+.RS 7
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP 7
+.SB "netscape -raise -remote 'openURL(%s,new-window)':xterm -e lynx %s:xterm -e wget %s:lynx %s:wget %s"
+.TP
+See
+.TP
+.SB http://www.catb.org/~esr/BROWSER/
+.PP
+for more details on the
+.B BROWSER
+environment variable.
+.RE
+#ifps
+.TP
+.SB TMPDIR
+The directory to use for storing temporary files created when uncompressing
+PostScript files.
+#endif
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.SB XEDITOR
+Determines the editor command used for source special `reverse
+search', if neither the
+.I \-editor
+command-line option
+nor the
+.I .editor
+resource are specified. See the description of the
+.I \-editor
+command line option for details on the format.
+.TP
+.SB VISUAL
+Determines an editor to be opened in an xterm
+window if neither of
+.IR -editor ,
+.IR .editor ,
+or
+.I XEDITOR
+is specified.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.SB EDITOR
+Determines an editor to be opened in an xterm
+window if neither of
+.IR -editor ,
+.IR .editor ,
+.I XEDITOR
+or
+.I VISUAL
+is specified.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.TP
+.SB WWWBROWSER
+Obsolete; use
+.B BROWSER
+instead.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+#ifps
+.SH LIMITATIONS
+.B xdvi
+accepts many but not all types of PostScript specials accepted by
+.BR dvips .
+For example, it accepts most specials generated by
+.B epsf
+and
+.BR psfig .
+It does not, however, support
+.B bop\-hook
+or
+.BR eop\-hook ,
+nor does it allow PostScript commands to affect the rendering of things that
+are not PostScript (for example, the ``NEAT'' and rotated ``A'' examples in the
+.B dvips
+manual). These restrictions are due to the design of
+.BR xdvi ;
+in all likelihood they will always remain.
+.PP
+La\*(Te\&2e rotation specials are currently not supported.
+.PP
+.B MetaPost
+files containing included text are not supported.
+.PP
+.BR Xdvi 's
+color handling doesn't support the
+.B \ecolorbox
+and
+.B \efcolorbox
+macros; this is not likely to change in the near future. This also
+means that e.g. colored tables (as created by the
+.I colortbl
+package) may render incorrectly: Text in colors different from the
+default foreground color may not not be displayed. When the page is
+redrawn (e.g. after using the magnifier), the background color of the
+cells may overdraw the text.
+#endif
+.SH FILES
+.TP
+.SB $HOME/.xdvirc
+A file that holds all settings that the user changed via the keys, the `Options'
+and the Xaw `Modes' menu and the dialogs, as X resources. These resources override the
+settings in
+.BR $HOME/.Xdefaults .
+This file is ignored if the
+.B \-q
+option is used or the
+.B noInitFile
+X resource is set.
+.TP
+.SB xdvi.cfg
+A configuration file for the T1 font setup which needs to be supplied
+in the directory determined by the
+.B XDVIINPUTS
+environment variable. Please see the file
+.B http://xdvi.sourceforge.net/README.t1fonts
+if that file is missing.
+.SH SEE ALSO
+.BR X (1),
+.BR dvips (1),
+.BR mktexpk (1),
+.BR ps2pk (1),
+.BR gsftopk (1),
+.BR t1mapper (1),
+.BR mailcap (4),
+the
+.B Kpathsea
+documentation,
+and the Xdvik home page at
+.BR http://xdvi.sourceforge.net/ .
+.SH AUTHORS
+Eric Cooper, CMU, did a version for direct output to a QVSS. Modified
+for X by Bob Scheifler, MIT Laboratory for Computer Science. Modified
+for X11 by Mark Eichin, MIT SIPB. Additional enhancements by many
+others.
+.PP
+The current maintainer of the original
+.B xdvi
+is Paul Vojta, U.C. Berkeley.
+.PP
+Code for the xdvik variant has been contributed
+by many people, whose names are scattered across the
+source files. Xdvik is hosted on
+.B CTAN:dviware/xdvik
+and on SourceForge; for the most up-to-date information, please
+visit:
+.PP
+.B http://xdvi.sourceforge.net
+.PP
+Please report all bugs to the SourceForge bug tracker:
+.PP
+.nf
+.B http://sourceforge.net/tracker/?func=add&group_id=23164&atid=377580
+.PP
+
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;
+}
+
+
diff --git a/Build/source/texk/xdvik/xdvi.h b/Build/source/texk/xdvik/xdvi.h
new file mode 100644
index 00000000000..d029b887adf
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi.h
@@ -0,0 +1,1128 @@
+/*========================================================================*\
+
+Copyright (c) 1990-2004 Paul Vojta
+
+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
+in xdvi.c.
+
+\*========================================================================*/
+
+/*
+ * Original version by Eric C. Cooper, CMU
+ */
+
+#ifndef XDVI_H_
+#define XDVI_H_
+
+#include "xdvi-config.h"
+
+/* headers used by all modules */
+#include "xdvi-debug.h"
+#include "c-auto.h"
+
+#include "kpathsea/c-auto.h" /* kpathsea definitions */
+#include "kpathsea/config.h"
+
+/********************************
+ * The C environment *
+ *******************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+/* in case stdlib.h doesn't define these ... */
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+#ifdef HAVE_WORKING_NL_LANGINFO_CODESET
+# define USE_LANGINFO 1
+#else
+# define USE_LANGINFO 0
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(status) (((status) & 255) == 0)
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(status) ((unsigned)(status) >> 8)
+#endif
+#ifndef WIFSIGNALED
+# ifndef WIFSTOPPED
+# define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+# endif
+# define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
+#endif
+#ifndef WTERMSIG
+# define WTERMSIG(status) ((status) & 0x7f)
+#endif
+
+/*
+ * If this is set to 1, xdvi will explicitly clear the internal GS
+ * buffer after every page that contained a PS special (figure etc.)
+ * to avoid artifacts with later PS specials (overlapping lines etc.);
+ * see also bug #633420. This workaround will slow down the drawing of
+ * the next page considerably. Currently xdvi also sometimes dies with
+ * `Internal error in beginheader_gs()'
+ * when paging quickly through a file with this hack enabled.
+ * Set to 0 to disable the hack.
+ */
+#define GS_PIXMAP_CLEARING_HACK 1
+
+#ifdef __hpux
+/* On HP-UX 10.10 B and 20.10, compiling with _XOPEN_SOURCE + ..._EXTENDED
+ * leads to poll() not realizing that a file descriptor is writable in psgs.c.
+ */
+# define _HPUX_SOURCE 1
+#else
+# ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+# endif
+# define _XOPEN_SOURCE_EXTENDED 1
+# define __EXTENSIONS__ 1 /* needed to get struct timeval on SunOS 5.5 */
+# define _SVID_SOURCE 1 /* needed to get S_IFLNK in glibc */
+# define _BSD_SOURCE 1 /* needed to get F_SETOWN in glibc-2.1.3 */
+#endif
+
+/* Some O/S dependent kludges. */
+#ifdef _AIX
+# define _ALL_SOURCE 1
+#endif
+
+/* just a kludge, no real portability here ... */
+#define DIR_SEPARATOR '/'
+
+#if STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+/* the following works around the wchar_t problem */
+# include <X11/X.h>
+# if HAVE_X11_XOSDEFS_H
+# include <X11/Xosdefs.h>
+# endif
+# ifdef X_NOT_STDC_ENV
+# undef X_NOT_STDC_ENV
+# undef X_WCHAR
+# include <X11/Xlib.h>
+# define X_NOT_STDC_ENV
+# endif
+#endif /* STDC_HEADERS */
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+/* For wchar_t et al., that the X files might want. */
+#include "kpathsea/systypes.h"
+#include "kpathsea/c-memstr.h"
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h> /* this should define MAXPATHLEN */
+#endif
+#include "kpathsea/c-pathmx.h" /* get fallback for PATH_MAX if all else fails */
+
+#include <X11/Xlib.h> /* include Xfuncs.h, if available */
+#include <X11/Xutil.h> /* needed for XDestroyImage */
+#include <X11/Xos.h>
+
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else
+# define MAXPATHLEN 1024
+# endif
+#endif
+
+#if defined(CFG2RES) && !defined(SELFAUTO)
+# define SELFAUTO 1
+#endif
+
+#if defined(SELFAUTO) && !defined(DEFAULT_CONFIG_PATH)
+# define DEFAULT_CONFIG_PATH "$SELFAUTODIR:$SELFAUTOPARENT"
+#endif
+
+/* NOTE: we don't use CFGFILE */
+
+typedef char Bool3; /* Yes/No/Maybe */
+
+#define True 1
+#define False 0
+#define Maybe 2
+
+
+#ifdef DEBUG
+#include<asm/msr.h>
+extern unsigned long time_start, time_end;
+#endif
+
+#include <X11/Xmd.h> /* get WORD64 and LONG64 */
+
+#ifndef WORD64
+# ifdef LONG64
+typedef unsigned int xuint32;
+# else
+typedef unsigned long xuint32;
+# endif
+#endif
+
+/* for unused parameters */
+#ifndef UNUSED
+#define UNUSED(x) ((void)(x))
+#endif
+
+#include <string.h>
+
+#ifdef VMS
+#define index strchr
+#define rindex strrchr
+#define bzero(a, b) (void) memset ((void *) (a), 0, (size_t) (b))
+#define bcopy(a, b, c) (void) memmove ((void *) (b), (void *) (a), (size_t) (c))
+#endif
+
+#include <stdio.h>
+#include <setjmp.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* all of these are POSIX and should have been defined by unistd.h: */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+/* see C FAQ; additional +1 for '\0' */
+#define LENGTH_OF_INT ((sizeof(int) * CHAR_BIT + 2) / 3 + 1 + 1)
+#define LENGTH_OF_LONG ((sizeof(long) * CHAR_BIT + 2) / 3 + 1 + 1)
+#define LENGTH_OF_ULONG ((sizeof(unsigned long) * CHAR_BIT + 2) / 3 + 1 + 1)
+
+#include "kpathsea/c-dir.h" /* dirent.h, NAMLEN */
+
+extern KPSEDLL char *kpathsea_version_string;
+
+#ifndef NeedFunctionPrototypes
+# if __STDC__
+# define NeedFunctionPrototypes 1
+# else
+# define NeedFunctionPrototypes 0
+# endif
+#endif
+
+#ifndef NeedWidePrototypes
+# define NeedWidePrototypes NeedFunctionPrototypes
+#endif
+
+#ifndef NeedVarargsPrototypes
+# define NeedVarargsPrototypes NeedFunctionPrototypes
+#endif
+
+#include "kpathsea/c-vararg.h"
+
+#ifndef _XFUNCPROTOBEGIN
+# define _XFUNCPROTOBEGIN
+# define _XFUNCPROTOEND
+#endif
+
+
+/* If xmkmf is broken and there's a symlink from /usr/include/X11 to the right
+ * place, then there will be no -I... argument on the cc command line for the
+ * X include files. Since gcc version 3 and higher sets __STDC__ to 0 when
+ * including system header files on some platforms, we may end up with
+ * NeedFunctionPrototypes set to 0 when it should be 1. So, let's force the
+ * issue.
+ */
+#if __STDC__ && !defined(FUNCPROTO)
+/* FUNCPROTO is a bitmask specifying ANSI conformance (see Xfuncproto.h).
+ The single bits specify varargs, const availability, prototypes etc.;
+ we enable everything here. */
+# define FUNCPROTO (-1)
+#endif
+
+#ifndef VOLATILE
+# if __STDC__ || (defined(__stdc__) && defined(__convex__))
+# define VOLATILE volatile
+# else
+# define VOLATILE /* as nothing */
+# endif
+#endif
+
+#ifndef NORETURN
+# ifdef __GNUC__
+# ifndef __STRICT_ANSI__
+# define NORETURN volatile
+# else
+# define NORETURN /* as nothing */
+# endif
+# else
+# define NORETURN /* as nothing */
+# endif
+#endif
+
+#ifndef OPEN_MODE
+/*
+ * SU, 2001/01/07: xdvi defines OPEN_MODE as "r" or as "r", "ctx=stm" (for VMS),
+ * but we use the definition of FOPEN_R_MODE from kpathsea/c-fopen.h instead:
+ */
+# define OPEN_MODE FOPEN_R_MODE
+#endif /* OPEN_MODE */
+
+#ifndef VMS
+# define OPEN_MODE_ARGS const char *
+#else
+# define OPEN_MODE_ARGS const char *, const char *
+#endif
+
+#ifndef __LINE__
+# define __LINE__ 0
+#endif
+
+#ifndef __FILE__
+# define __FILE__ "?"
+#endif
+
+#define MAXDIM 32767
+
+typedef unsigned char ubyte;
+
+#if NeedWidePrototypes
+typedef unsigned int wide_ubyte;
+typedef int wide_bool;
+#else
+typedef ubyte wide_ubyte;
+typedef Boolean wide_bool;
+#endif
+
+#if defined(MAKEPK) && !defined(MKTEXPK)
+# define MKTEXPK 1
+#endif
+
+#define spell_conv0(n, f) ((long) (n * f))
+#define spell_conv(n) spell_conv0(n, dimconv)
+
+typedef BMTYPE bmTypeT;
+typedef unsigned BMTYPE bmUnitT;
+/* #define BMUNIT unsigned BMTYPE */
+#define BMBITS (8 * BMBYTES) /* number of bits in a bmTypeT */
+
+#define ADD(a, b) ((bmUnitT *) (((char *) a) + b))
+#define SUB(a, b) ((bmUnitT *) (((char *) a) - b))
+
+extern bmUnitT bit_masks[BMBITS + 1];
+
+/* for safely printing char *s that might be NULL */
+#define STRING_OR_NULL(x) ((x == NULL ? "<NULL>" : x))
+
+#define INSIDE_MANE_WIN ((currwin.win == mane.win))
+#define MAGNIFIER_ACTIVE ((magnifier.win != 0))
+
+#define mane_base_x 0
+#define mane_base_y 0
+
+
+struct frame {
+ /* dvi_h and dvi_v is the horizontal and vertical baseline position;
+ it is the responsability of the set_char procedure to update
+ them. */
+ struct framedata {
+ long dvi_h, dvi_v, w, x, y, z;
+ int pxl_v;
+ } data;
+ struct frame *next, *prev;
+};
+
+#ifdef TEXXET
+typedef void setcharRetvalT;
+#else
+typedef long setcharRetvalT;
+#endif
+
+typedef setcharRetvalT (*set_char_proc) (
+#ifdef TEXXET
+ wide_ubyte cmd,
+#endif
+ wide_ubyte ch);
+
+#define ROUNDUP(x,y) (((x)+(y)-1)/(y))
+
+#ifndef BDPI
+#define BDPI 600
+#endif
+
+#if defined(GS_PATH) && !defined(PS_GS)
+# define PS_GS 1
+#endif
+
+#if defined(PS_DPS) || defined(PS_NEWS) || defined(PS_GS)
+# define PS 1
+#else
+# define PS 0
+#endif
+
+typedef enum {
+ XPRT_SHOW_NONE = 0U,
+ XPRT_SHOW_STATUSLINE = 1,
+ XPRT_SHOW_SCROLLBARS = 2,
+#ifdef MOTIF
+ XPRT_SHOW_PAGELIST = 4,
+ XPRT_SHOW_TOOLBAR = 8,
+ XPRT_SHOW_MENUBAR = 16,
+ XPRT_SHOW_ALL = 31
+#else
+ XPRT_SHOW_BUTTONS = 4,
+ XPRT_SHOW_ALL = 7
+#endif
+} expertFlagT;
+
+typedef enum {
+ MOUSE_MAGNIFIER_MODE,
+ MOUSE_TEXT_MODE,
+ MOUSE_RULER_MODE,
+ MOUSE_MAX_MODE
+} mouseModeT;
+
+/* SUBPIXEL_NONE for no subpixel rendering, otherwise order of subpixels
+ (from option/resource subPixels) */
+typedef enum { SUBPIXEL_NONE, SUBPIXEL_RGB, SUBPIXEL_BGR } subpixelOrderT;
+
+/*
+ * X resources.
+ */
+extern struct x_resources {
+ /* NOTE: we don't use CFGFILE */
+ Boolean no_init_file;
+ Boolean regression;
+ const char *geometry;
+ const char *windowsize;
+ Boolean remember_windowsize;
+ int app_defaults_fileversion;
+ int mouse_mode;
+ Boolean use_tex_pages;
+ int shrinkfactor;
+ const char *main_translations;
+ const char *wheel_translations;
+ int wheel_unit;
+ int density;
+ Boolean omega;
+#ifdef GREY
+ float gamma;
+/* float inverted_factor; */
+#endif
+ int pixels_per_inch;
+ Boolean delay_rulers;
+ int tick_length;
+ char *tick_units;
+ const char *sidemargin;
+ int sidemargin_int;
+ const char *topmargin;
+ int topmargin_int;
+ const char *xoffset;
+ int xoffset_int;
+ const char *yoffset;
+ int yoffset_int;
+ Boolean use_current_offset; /* only used internally */
+ const char *paper;
+ Boolean paper_landscape; /* only used internally */
+ const char *alt_font;
+#ifdef MKTEXPK
+ Boolean makepk;
+#endif
+ const char *mfmode;
+ const char *editor;
+#ifdef MOTIF
+ char *prefs_editor_list;
+#endif
+ Boolean t1lib;
+ const char *src_pos;
+ const char *find_string;
+ const char *text_encoding;
+ Boolean src_fork;
+ const char *sub_pixels;
+ const char *file_history;
+ int file_history_size;
+ Boolean no_file_arg_use_history;
+ subpixelOrderT subpixel_order;
+ float subpixel_energy[3];
+ Boolean unique;
+ Boolean list_fonts;
+ Boolean reverse;
+ Boolean warn_spec;
+ Boolean hush_chars;
+ Boolean hush_chk;
+ Boolean hush_stdout;
+ Boolean safer;
+#ifdef VMS
+ const char *fore_color;
+ const char *back_color;
+#endif
+ Pixel fore_Pixel;
+ Pixel back_Pixel;
+ /* Pixel brdr_Pixel; */
+ Pixel hl_Pixel;
+ Pixel cr_Pixel;
+ const char *icon_geometry;
+ Boolean keep_flag;
+ Boolean copy;
+ Boolean thorough;
+ Boolean pause;
+ const char *pause_special;
+ Boolean fullscreen;
+#ifdef PS
+ int postscript;
+ Boolean allow_shell;
+# ifdef PS_DPS
+ Boolean useDPS;
+# endif
+# ifdef PS_NEWS
+ Boolean useNeWS;
+# endif
+# ifdef PS_GS
+ Boolean useGS;
+ Boolean gs_safer;
+ Boolean gs_alpha;
+ const char *gs_path;
+ const char *gs_palette;
+ int gs_timeout;
+# endif
+# ifdef MAGICK
+ Boolean useMAGICK;
+ const char *magick_cache;
+# endif
+#endif /* PS */
+ Boolean prescan;
+ Boolean use_temp_fp;
+ const char *debug_arg;
+ const char *menu_translations;
+ Boolean expert;
+ float watch_file; /* check DVI file every so often, in seconds */
+ int expert_mode;
+#ifndef MOTIF
+ Dimension btn_side_spacing;
+ Dimension btn_top_spacing;
+ Dimension btn_between_spacing;
+ /* ignored, only for backwards compatibility */
+ Dimension btn_between_extra;
+ Dimension btn_border_width;
+#else /* MOTIF */
+ const char *toolbar_translations;
+#endif /* MOTIF */
+ Boolean statusline;
+#ifdef MOTIF
+ /* not a user-level resource; indicates a problem with the toolbar, in
+ which case the toolbar is disabled. */
+ Boolean toolbar_unusable;
+ const char *toolbar_pixmap_file;
+ Boolean toolbar_buttons_raised;
+ Boolean tooltips_in_statusline;
+ int tooltips_wait_period; /* used for communication with Tip.c */
+ int tooltips_wait_period_bak; /* uncustomized value */
+ Boolean show_tooltips;
+#endif
+ Boolean pagelist_highlight_current;
+ Dimension pagelist_width;
+ const char *mg_arg[5];
+#if COLOR
+ Boolean use_color;
+#endif
+#ifdef GREY
+ Boolean use_grey;
+ Bool3 install;
+#endif
+ Boolean match_highlight_inverted;
+ const char *dvips_path;
+ const char *ps2pdf_path;
+ int dvips_hang;
+ int dvips_fail_hang;
+ const char *dvips_printer_str;
+ const char *dvips_options_str;
+ int default_saving_format;
+ int default_printing_target;
+ char *rule_color;
+ Pixel rule_pixel;
+ int link_style;
+ char *link_color;
+ char *visited_link_color;
+ char *browser;
+#ifdef MOTIF
+ char *prefs_browser_list;
+#endif
+ char *unknown_mime_suffix;
+ char *no_mime_suffix;
+ char *anchor_pos;
+ /* bitmask of current search window settings */
+ unsigned int search_window_defaults;
+ /* char * _scroll_pages; */
+ char *help_general;
+ char *help_hypertex;
+ char *help_othercommands;
+ char *help_pagemotion;
+ char *help_marking;
+ char *help_modes;
+ char *help_search;
+ char *help_mousebuttons;
+ char *help_sourcespecials;
+ int page_history_size;
+} resource;
+
+extern void reload_app_resources(void);
+
+
+struct WindowRec {
+ Window win;
+ int shrinkfactor;
+ int base_x;
+ int base_y;
+ unsigned int width;
+ unsigned int height;
+ /* for pending expose events */
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+};
+
+struct event_info {
+ int flags;
+ VOLATILE int ctr;
+ jmp_buf canit;
+ jmp_buf next; /* to skip next event */
+};
+
+struct pause_info {
+ int num;
+ int *num_save;
+ Boolean flag;
+};
+
+struct gc_info {
+ GC rule;
+ GC fore;
+ GC inverted;
+ GC high;
+ GC linkcolor;
+ GC visited_linkcolor;
+ GC fore2;
+ GC fore2_bak;
+ GC fore2_bak1;
+ GC copy;
+ GC ruler;
+ Boolean do_copy;
+};
+
+/* values of cursor flags */
+#define CURSOR_LINK 1
+#define CURSOR_MAG 2
+/* flags for drag cursors */
+#define CURSOR_DRAG_V 4
+#define CURSOR_DRAG_H 8
+#define CURSOR_DRAG_A 16
+#define CURSOR_CORRUPTED 32 /* if file is corrupted */
+#define CURSOR_TEXT 64
+
+struct cursor_info {
+ Cursor wait;
+ Cursor ready;
+ Cursor corrupted;
+ Cursor link;
+ Cursor rule;
+ Cursor mag;
+ /* horizontal/vertical/all directions drag */
+ Cursor drag_h;
+ Cursor drag_v;
+ Cursor drag_a;
+ /* support for `pause' feature */
+ Cursor pause;
+ /* text selection */
+ Cursor text;
+
+ /* one of the flags defined above */
+ unsigned long flags;
+};
+
+struct window_expose_info {
+ int min_x, max_x, min_y, max_y;
+};
+
+/* for communication with forward search in dvi-draw.c */
+struct src_info {
+ int fwd_box_page;
+ const char *fwd_string;
+};
+
+struct widget_info {
+ Widget top_level;
+ Widget draw_widget, draw_background, clip_widget;
+ Widget x_bar, y_bar;
+#ifdef MOTIF
+ Widget main_window, main_row, tool_bar, top_row, menu_bar;
+#else
+ Widget vport_widget, form_widget, paned;
+#endif
+};
+
+struct page_info {
+ unsigned int w, h;
+ unsigned int unshrunk_w, unshrunk_h;
+};
+
+struct dvi_file_info {
+ char *dirname;
+ size_t dirlen;
+ FILE *bak_fp;
+ time_t time; /* last file modification time */
+};
+
+/* struct to hold global settings that can't go into the resources,
+ * as a replacement for global variables:
+ */
+extern struct program_globals {
+ const char *program_name; /* argv[0] without the directory part */
+ const char *xdvi_dir; /* directory where xdvi is running in (for childs who need to change back to it) */
+ char *dvi_name; /* dvi file name, fully expanded with REALPATH */
+ Boolean load_init_file; /* whether to read/save ~/.xdvirc */
+ char *orig_locale; /* original locale we are running in */
+ unsigned long debug; /* debugging option */
+
+ /* for older Motif versions or LessTif, which have broken
+ handling of Act_motion() / Act_release() events */
+ Boolean broken_motif_event_handling;
+
+ /* offset from c-style (0 based) numbers to real pagenumbers;
+ also contains the offset that user has set via Act_declare_page_number() */
+ int pageno_correct;
+
+ /* whether we warn about unrecognized specials. Copy of resource.warn_spec value,
+ set to False in the drawing routine to reduce the amount of warnings given.
+ Better maybe replace with hash lookup similar to fonts warnings? */
+ Boolean warn_spec_now;
+
+ /* used to save X resource values */
+ char *curr_paper;
+ char *curr_editor;
+ char *curr_browser;
+ float curr_gamma;
+ Boolean curr_use_color;
+
+
+ /* forward search info */
+ struct src_info src;
+
+ /* event information */
+ struct event_info ev;
+
+ /* support for `-pause' feature */
+ struct pause_info pausing;
+
+ /* window expose information */
+ struct window_expose_info win_expose;
+
+ struct gc_info gc;
+
+ /* cursor information */
+ struct cursor_info cursor;
+
+ /* widget information */
+ struct widget_info widgets;
+
+ /* page size info */
+ struct page_info page;
+
+ /* DVI file and modification time info */
+ struct dvi_file_info dvi_file;
+
+} globals;
+
+
+/* TODO: put these into globals as well */
+extern struct WindowRec mane;
+extern struct WindowRec currwin;
+extern struct WindowRec magnifier;
+
+#ifdef MOTIF
+#include <Xm/Xm.h>
+extern XmStringCharSet G_charset;
+#endif
+
+extern XtAppContext app;
+extern char *dvi_property; /* for setting in window */
+extern size_t dvi_property_length;
+extern XImage *G_image;
+extern int G_backing_store;
+/* extern int home_x, home_y; */
+
+extern Display *DISP;
+extern Screen *SCRN;
+
+extern XtAccelerators G_accels_cr;
+#ifdef GREY
+extern Visual *G_visual;
+extern unsigned int G_depth;
+extern Colormap G_colormap;
+#else
+# define G_depth (unsigned int) DefaultDepthOfScreen(SCRN)
+# define G_visual DefaultVisualOfScreen(SCRN)
+# define G_colormap DefaultColormapOfScreen(SCRN)
+#endif
+
+
+#define TNTABLELEN 30 /* length of TeXnumber array (dvi file) */
+#define VFTABLELEN 5 /* length of TeXnumber array (virtual fonts) */
+
+extern struct font *tn_table[TNTABLELEN];
+extern struct font *font_head;
+extern struct tn *tn_head;
+extern wide_ubyte maxchar;
+extern unsigned short current_timestamp;
+
+extern int current_page;
+extern int total_pages;
+
+extern unsigned long magnification;
+extern double dimconv;
+extern double tpic_conv;
+
+/* whether this file contains source specials, so that we need to
+ update the `windows' property for forward search on expose events:
+*/
+extern Boolean have_src_specials;
+
+extern Boolean dragcurs; /* whether drag cursor is active; needed by hypertex.c */
+extern int drag_flags; /* 1 = vert, 2 = horiz; also needed by hypertex.c */
+
+typedef void (*mouse_proc) (XEvent *);
+extern mouse_proc mouse_motion;
+extern mouse_proc mouse_release;
+
+#if GREY
+extern Pixel plane_masks[4];
+#endif
+
+#if GREY || COLOR
+extern XColor color_data[2];
+#endif
+
+#if COLOR
+struct rgb {
+ unsigned short r, g, b;
+};
+
+struct pagecolor {
+ struct rgb bg;
+ unsigned int stacksize;
+ struct rgb *colorstack;
+};
+struct pagecolor_info {
+ /* different from non-k xdvi, we also need the allocated stack size,
+ since it might differ from the number of pages (e.g. when loading
+ a new file). */
+ size_t size;
+ /* this is const in non-k xdvi, but some instances of it may ultimately
+ get free()d in full_reset_colors(), so it's not *really* const ...
+ */
+ struct pagecolor *stack;
+};
+
+/* Information on background color and initial color stack for each page. */
+extern struct pagecolor_info page_colors;
+
+/* The initial color stack is obtained from the pagecolor record for a page. */
+extern struct rgb *color_bottom;
+extern unsigned int color_bot_size; /* number of entries */
+
+/* Additions to the runtime color stack on a given page are stored in a linked
+ list. "struct colorframe" is defined in special.c. */
+extern struct colorframe *rcs_top;
+
+/* Color states. */
+
+/*
+ * For each (foreground, background) color pair, we keep information (depending
+ * on the color model). It is organized as a linked list of linked lists,
+ * with background color more significant.
+ */
+
+struct bgrec {
+ struct bgrec *next;
+ struct rgb color;
+ struct fgrec *fg_head;
+ Boolean pixel_good; /* if the pixel entry is valid */
+ Pixel pixel;
+};
+
+struct fgrec {
+ struct fgrec *next;
+ struct rgb color;
+ Boolean pixel_good; /* if the pixel entry is valid */
+ Pixel pixel;
+#if GREY
+ Boolean palette_good; /* if the palette entry is valid */
+ Pixel palette[16]; /* non-TrueColor only */
+#endif
+};
+
+extern struct rgb fg_initial; /* Initial fg (from command line) */
+extern struct rgb bg_initial; /* Initial bg */
+extern struct bgrec *bg_head; /* head of list */
+extern struct bgrec *bg_current; /* current bg value */
+extern struct fgrec *fg_current; /* current fg value */
+extern struct fgrec *fg_active; /* where the GCs are */
+
+/* List of allocated colors (to be deallocated upon document change) */
+extern Pixel *color_list; /* list of colors */
+extern unsigned int color_list_len; /* current len of list */
+extern unsigned int color_list_max; /* allocated size */
+
+/* Whether the color situation has been warned about. */
+extern Boolean color_warned;
+#endif /* COLOR */
+
+extern Boolean dvi_file_corrupted;
+
+extern short magnifier_stat; /* 1 = wait for expose, -1 = destroy upon expose */
+
+/*
+ ================================================================================
+ globals from dvi-draw.c
+ ================================================================================
+*/
+
+/*
+ * The following is set when we're prescanning before opening up the windows,
+ * and we hit a PostScript header file. We can't start up gs until we get
+ * a window to associate the process to, so we have to prescan twice.
+ */
+#if PS_GS
+extern Boolean gs_postpone_prescan;
+#endif
+
+#if PS
+extern int scanned_page_ps; /* last page scanned for PS specials */
+extern int scanned_page_ps_bak; /* save the above if PS is turned off */
+#endif
+
+#if COLOR
+extern int scanned_page_color; /* last page scanned for color spcls */
+#endif /* COLOR */
+
+extern int scanned_page; /* last page prescanned */
+extern int scanned_page_reset; /* number to reset the above to */
+extern ubyte *G_dvi_buf_ptr;
+extern struct drawinf currinf;
+extern Boolean drawing_mag;
+extern Boolean htex_inside_href;
+
+/* globals from hypertex.h */
+/* current anchor to search for, either from command-line or from clicking mouse */
+extern char *g_anchor_pos;
+extern size_t g_anchor_len;
+
+extern char *g_link_color_rgb;
+extern char *g_visited_link_color_rgb;
+
+/* globals from special.h */
+/*
+ * If we're in the middle of a PSFIG special.
+ */
+extern Boolean psfig_begun;
+/*
+ * Set if the -paper option overrides papersize specials.
+ */
+extern Boolean ignore_papersize_specials;
+extern Boolean have_raw_postscript;
+#if PS
+extern struct psprocs psp, no_ps_procs;
+#ifdef PS_GS
+extern Boolean had_ps_specials;
+#endif
+#endif
+
+#ifdef MAGICK
+/* TODO: put access functions for these in special.c */
+extern int bbox_angle;
+extern Boolean bbox_valid;
+extern unsigned int bbox_width;
+extern unsigned int bbox_height;
+extern int bbox_voffset;
+#endif
+
+/* globals from statusline.h */
+extern int global_statusline_h; /* height of statusline, or 0 */
+extern Widget statusline;
+
+
+/*
+ * The cursor shape in the magnifying glass is determined by which
+ * window received the button press event. Under Motif, it's mane.win,
+ * under XAW, it's the parent of mane.win.
+ */
+#ifdef MOTIF
+# define CURSORWIN mane.win
+#else
+/* # define CURSORWIN XtWindow(globals.widgets.form_widget) */
+# define CURSORWIN mane.win
+#endif
+
+
+/*
+ * This was MOTIF_TIMERS in the non-k xdvi version, but since xdvik
+ * also uses XtAppAddTimeOut() for Xaw, we always need to define it.
+ * See the comment in events.c for further explanations.
+ */
+#if LD_ALLOWS_MULTIPLE_DEFINITIONS
+# define XDVI_XT_TIMER_HACK 1
+#else
+# define XDVI_XT_TIMER_HACK 0
+#endif
+
+/* globally used GUI stuff */
+#ifdef MOTIF
+#include <Xm/Xm.h>
+/* Note: non-k xdvi has MOTIF_TIMERS here, we use XDVI_XT_TIMER_HACK instead (see above) */
+
+# ifndef DDIST
+# define DDIST 4
+# endif
+# ifndef DDIST_MAJOR
+# define DDIST_MAJOR 10
+# endif
+# ifndef DDIST_MINOR
+# define DDIST_MINOR 5
+# endif
+#endif
+
+extern const char **get_paper_types(void);
+extern size_t get_paper_types_size(void);
+
+extern size_t get_magglass_items(void);
+extern int get_magglass_width(int idx);
+extern int get_magglass_height(int idx);
+
+
+#ifdef STATUSLINE
+/* this is only for the initialization; the statusline will reset it to a more adequate value: */
+# define XTRA_H 17
+#endif
+
+/*
+ * Generic structure for DVI scans; contains a buffer for longjmp()ing
+ * out of the scanning process if it's interrupted by the user (ugh ...)
+ * and a generic `void *' to scan-specific info.
+ */
+struct scan_info {
+ jmp_buf done_env;
+ void (*geom_special)(struct scan_info *info, const char *str, int str_len);
+ void *data;
+};
+
+/*
+ * Used by the geometry-scanning routines.
+ * It passes pointers to routines to be called at certain
+ * points in the dvi file, and other information.
+ */
+struct geom_info {
+ void (*geom_box)(struct scan_info *, long, long, long, long);
+ void *geom_data;
+};
+
+#ifdef CFG2RES
+struct cfg2res {
+ const char *cfgname; /* name in config file */
+ const char *resname; /* name of resource */
+ Boolean numeric; /* if numeric */
+};
+#endif
+
+#define get_byte(fp) ((unsigned char)getc(fp))
+#define get_lbyte(fp) ((long)get_byte(fp))
+
+extern void get_icon_and_title(const char *filename, char **icon_name, char **title_name);
+extern void set_icon_and_title(const char *icon_name, const char *title_name);
+extern void reconfigure_window(Boolean fullsize, Dimension w, Dimension h,
+ Boolean save_position);
+extern void set_windowsize(Dimension *ret_w, Dimension *ret_h, int add_w, int add_h, Boolean override);
+
+#ifdef MOTIF
+extern void motif_translations_hack(void);
+#endif
+
+#ifndef MAX
+# define MAX(i, j) ((i) > (j) ? (i) : (j))
+#endif
+
+#ifndef MIN
+# define MIN(i, j) ((i) < (j) ? (i) : (j))
+#endif
+
+#ifndef ABS
+# define ABS(x) (((x) < 0) ? (-(x)) : (x))
+#endif
+
+#define REPORT_XDVI_BUG_TEMPLATE "Please report this as a bug to:\n\
+ http://sourceforge.net/tracker/?group_id=23164&atid=377580\n"
+
+#if HAVE_ICONV && HAVE_ICONV_H
+#undef HAVE_ICONV_H
+#define HAVE_ICONV_H 1
+#else
+#undef HAVE_ICONV_H
+#define HAVE_ICONV_H 0
+#endif
+
+
+#if HAVE_GOOD_SETSID_VFORK
+# if HAVE_VFORK_H
+# include <vfork.h>
+# endif
+#else /* HAVE_GOOD_SETSID_VFORK */
+/* Mac OS X 10.3 (Panther) (11/2003) doesn't allow setsid() within vfork() */
+# undef vfork
+# define vfork fork
+#endif /* HAVE_GOOD_SETSID_VFORK */
+
+/* enable following if you get unresolved messages about `iconv_open' etc.: */
+#if 0
+#define LIBICONV_PLUG
+#define iconv_open libiconv_open
+#define iconv_close libiconv_close
+#define iconv libiconv
+#endif /* 0 */
+
+typedef ICONV_CHAR_PPTR_TYPE iconv_char_pptrT;
+
+#define DEVEL_MODE 0
+
+#endif /* XDVI_H_ */
diff --git a/Build/source/texk/xdvik/xdvi.icon b/Build/source/texk/xdvik/xdvi.icon
new file mode 100644
index 00000000000..dcfd263510f
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvi.icon
@@ -0,0 +1,27 @@
+#define xdvi_width 48
+#define xdvi_height 48
+static const unsigned char xdvi_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x00, 0x00, 0x01, 0x00, 0x00, 0xa2, 0xe0, 0x44, 0x38, 0x95, 0x13,
+ 0x9e, 0x17, 0x45, 0x45, 0x55, 0xf4, 0x82, 0xf0, 0x28, 0x3d, 0xd5, 0x13,
+ 0x82, 0x10, 0x28, 0x05, 0x55, 0x10, 0x82, 0xe0, 0x10, 0x39, 0x8a, 0x13,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x1f, 0x00,
+ 0x79, 0x18, 0x18, 0x13, 0x16, 0x00, 0x69, 0x10, 0x18, 0x0e, 0x16, 0x00,
+ 0xcf, 0x20, 0x1c, 0x0e, 0xd6, 0x00, 0xe9, 0xc3, 0x7b, 0x84, 0x3f, 0x01,
+ 0x09, 0x00, 0x00, 0x00, 0x30, 0x00, 0x08, 0x00, 0x00, 0x00, 0x70, 0xcc,
+ 0x08, 0x00, 0x00, 0x00, 0x30, 0x52, 0x0a, 0x00, 0x00, 0x00, 0x30, 0x52,
+ 0x0a, 0xc0, 0xff, 0x03, 0x30, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0xc0, 0xff, 0x03, 0x10, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf0, 0x17,
+ 0x0b, 0x0c, 0x3c, 0xc0, 0x93, 0x20, 0x0c, 0x0e, 0x43, 0x20, 0x96, 0x40,
+ 0x0c, 0x8e, 0x81, 0x10, 0x96, 0xbe, 0x0a, 0x8d, 0x81, 0x19, 0x90, 0x82,
+ 0x8a, 0x8c, 0x81, 0x0d, 0x90, 0x42, 0x48, 0x8c, 0x81, 0xed, 0x91, 0x3e,
+ 0x6a, 0x0c, 0xc3, 0x1d, 0x96, 0x12, 0x38, 0x0c, 0xbc, 0x0d, 0x1c, 0x02,
+ 0xf8, 0x3f, 0x80, 0x0d, 0x1c, 0x3e, 0x0b, 0x0c, 0x80, 0x0c, 0x1c, 0x00,
+ 0x0b, 0x0c, 0xc3, 0x18, 0x1c, 0x00, 0x0a, 0x0c, 0x63, 0x10, 0x16, 0x00,
+ 0x89, 0x3f, 0x1e, 0xe0, 0x11, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x1f, 0xae, 0x0f, 0x00, 0x80, 0x84, 0x0a, 0xae,
+ 0x87, 0x64, 0x86, 0x84, 0x08, 0x42, 0x42, 0x45, 0xe2, 0x1c, 0x07, 0x42};
diff --git a/Build/source/texk/xdvik/xdvizilla b/Build/source/texk/xdvik/xdvizilla
new file mode 100755
index 00000000000..54f4b03ddfe
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvizilla
@@ -0,0 +1,134 @@
+#! /bin/sh
+#
+# This is a kludge to fix helper apps in mozilla. See mozilla bugs #57420
+# and also #78919.
+#
+# It's also useful for tar files with Netscape 4.x
+#
+# Copyright (c) 2002-2004 Paul Vojta
+#
+# 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 OR CONTRIBUTOR TO
+# 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.
+
+# Some changes suggested by Thomas Esser included by
+# <stefanulrich@users.sourceforge.net>.
+
+IN_FILE=
+NO_RM=
+TMP_DIR=
+progname=xdvizilla
+
+do_cleanup()
+{
+ exitval=$?
+ if [ -z "$NO_RM" -a -n "$IN_FILE" ] ; then
+ rm -f "$IN_FILE"
+ fi
+ test -n "$TMP_DIR" && rm -rf "$TMP_DIR"
+ exit $exitval
+}
+
+do_abort()
+{
+ xmessage -nearmouse "$progname: $1"
+ do_cleanup
+ exit 1
+}
+
+usage()
+{
+ xmessage -nearmouse "Usage: $progname [-no-rm] <file>"
+ do_cleanup
+ exit 1
+}
+
+trap 'do_cleanup' 1 2 3 7 13 15
+
+### create a temporary directory only read/writable by user
+TMP_DIR=${TMPDIR-${TEMP-${TMP-/tmp}}}/$progname.$$
+(umask 077; mkdir "$TMP_DIR") || do_abort "Could not create directory \`$TMP_DIR'"
+
+if [ $# -gt 1 -a "x$1" = "x-no-rm" ]; then
+ NO_RM=y
+ shift
+fi
+
+if [ $# -ne 1 ]; then
+ usage
+fi
+
+DIR=`dirname "$0"`
+
+if [ "$DIR" = . ]; then
+ DIR=
+elif [ -f "$DIR"/xdvi -a -x "$DIR"/xdvi ]; then
+ DIR="$DIR"/
+else
+ DIR=
+fi
+
+# need to preserve IN_FILE for eventual deletion
+IN_FILE="$1"
+TMP_FILE="$IN_FILE"
+
+while [ 1 ]; do
+ [ -f "$TMP_FILE" ] || do_abort "$TMP_FILE: File not found."
+ FILETYPE=`file "$TMP_FILE"`
+ case "$FILETYPE" in
+ *"gzip compressed data"*)
+ out="$TMP_DIR"/tmp-gz
+ gunzip -c "$TMP_FILE" > "$out"
+ TMP_FILE="$out"
+ ;;
+ *"compressed data"* | *"compress'd data"*)
+ out="$TMP_DIR"/tmp-compress
+ uncompress -c "$TMP_FILE" > "$out"
+ TMP_FILE="$out"
+ ;;
+ "$TMP_FILE: empty")
+ do_abort "$TMP_FILE is an empty file
+(probably a bug in Mozilla?)"
+ ;;
+ *" tar archive")
+ ### do sanity checks on the tar archive, to avoid overwriting user files:
+ dangerous=`tar tf "$TMP_FILE" | egrep '^(/|.*\.\./)'`
+ [ -z "$dangerous" ] || do_abort "Tar file contains files with absolute paths or \`../' components,
+which may overwrite user files. Not unpacking it."
+ ### also check for gzipped DVI files inside the archive ...
+ out="$TMP_DIR"/`tar tf "$TMP_FILE" | egrep '\.(dvi|dvi.gz|dvi.Z)$' | head -1`
+ if [ -z "$out" ]; then
+ do_abort "Tar file does not contain a dvi file."
+ else
+ cat "$TMP_FILE" | (cd "$TMP_DIR"; tar xf -)
+ TMP_FILE="$out"
+ fi
+ ;;
+ *"DVI file"*)
+ "$DIR"xdvi -safer "$TMP_FILE"
+ break
+ ;;
+ *)
+ do_abort "$TMP_FILE: Unrecognized file format!"
+ ;;
+ esac
+done
+
+do_cleanup
+
+exit 0
diff --git a/Build/source/texk/xdvik/xdvizilla.1 b/Build/source/texk/xdvik/xdvizilla.1
new file mode 100644
index 00000000000..62b0d91c2de
--- /dev/null
+++ b/Build/source/texk/xdvik/xdvizilla.1
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2002-2004 Paul Vojta
+.\"
+.\" 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 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.
+.\"
+.TH XDVIZILLA 1 "11 October 2002" "X Version 11"
+.SH NAME
+xdvizilla \- Helper application for running xdvi
+.SH SYNOPSIS
+.B xdvizilla
+[\fB\-no\-rm\fP]
+.I file
+.SH DESCRIPTION
+Presently (October 2002), Mozilla has some bugs with helper applications:
+it passes gzipped
+.RB ( .gz )
+files directly to the helper application without uncompressing, and it
+passes compressed
+.RB ( .Z )
+files as empty files.
+.PP
+To work around these problems,
+.B xdvizilla
+was written to look at files and decompress them correctly (depending on
+their file types).
+.PP
+In addition, some sites produced tarred
+.I dvi
+files (including the
+.I dvi
+file as well as some included figures), and
+.B xdvizilla
+correctly handles those files as well.
+.SH OPTIONS
+Only one option is supported:
+.TP
+.B \-no\-rm
+Normally
+.B xdvizilla
+will remove
+.I file
+before finishing. This option inhibits this behavior.
+.SH INSTALLATION
+In addition to installing
+.B xdvizilla
+in a directory on the default search path, it is necessary to set it up
+as a helper application within the browser.
+.PP
+For
+.BR "Netscape 4.x" ,
+add the following lines to the
+.B mailcap
+file:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+application/x-dvi; xdvi -safer %s
+application/x-dvi-tar; xdvizilla -no-rm %s
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+For
+.BR "Netscape 6.x" ,
+.BR "Netscape 7.x" ,
+or
+.BR "Mozilla 1.x" ,
+add the following lines to the
+.B mailcap
+file:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+application/x-dvi; xdvizilla %s
+application/x-dvi-tar; xdvizilla %s
+.sp 1n
+.ft
+.fi
+.RE
+.PP
+In addition, it would be useful to check that the following line is included
+in the
+.B mime.types
+file:
+.RS 5
+.nf
+.ft 3
+.sp 1n
+type=application/x-dvi exts="dvi" desc="TeX dvi file"
+.sp 1n
+.ft
+.fi
+.RE
+.SH SEE ALSO
+.BR X (1),
+.BR xdvi (1).
+.SH AUTHOR
+Paul Vojta, U.C. Berkeley.
diff --git a/Build/source/texk/xdvik/xserver-info.c b/Build/source/texk/xdvik/xserver-info.c
new file mode 100644
index 00000000000..328df938161
--- /dev/null
+++ b/Build/source/texk/xdvik/xserver-info.c
@@ -0,0 +1,283 @@
+/* Xserver debugging functions, lifted from X11 R6.6's xdpyinfo.c.
+ Original copyright follows:
+*/
+
+/*
+Copyright 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+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 THE
+OPEN GROUP 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.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include "xdvi.h"
+#include "xserver-info.h"
+
+#ifdef XSERVER_INFO
+
+static void
+print_display_info (dpy)
+ Display *dpy;
+{
+ char dummybuf[40];
+ char *cp;
+ int minkeycode, maxkeycode;
+ int i, n;
+ /* long req_size; */
+ XPixmapFormatValues *pmf;
+ Window focuswin;
+ int focusrevert;
+
+ printf("name of display: %s\n", DisplayString (dpy));
+ printf("version number: %d.%d\n",
+ ProtocolVersion (dpy), ProtocolRevision (dpy));
+ printf("vendor string: %s\n", ServerVendor (dpy));
+ printf("vendor release number: %d\n", VendorRelease (dpy));
+ /* apparently AIX 3 does not have XExtendedMaxRequestSize.
+ We don't really need it either.
+ */
+ /* req_size = XExtendedMaxRequestSize (dpy); */
+ /* if (!req_size) req_size = XMaxRequestSize (dpy); */
+ /* printf("maximum request size: %ld bytes\n", req_size * 4); */
+ /* printf("motion buffer size: %lu\n", XDisplayMotionBufferSize (dpy)); */
+
+ switch (BitmapBitOrder (dpy)) {
+ case LSBFirst: cp = "LSBFirst"; break;
+ case MSBFirst: cp = "MSBFirst"; break;
+ default:
+ sprintf(dummybuf, "unknown order %d", BitmapBitOrder (dpy));
+ cp = dummybuf;
+ break;
+ }
+ printf("bitmap unit: %d, bit order: %d (%s), padding: %d\n",
+ BitmapUnit (dpy), BitmapBitOrder(dpy), cp, BitmapPad (dpy));
+
+ switch (ImageByteOrder (dpy)) {
+ case LSBFirst: cp = "LSBFirst"; break;
+ case MSBFirst: cp = "MSBFirst"; break;
+ default:
+ sprintf(dummybuf, "unknown order %d", ImageByteOrder (dpy));
+ cp = dummybuf;
+ break;
+ }
+ printf("image byte order: %d (%s)\n", ImageByteOrder(dpy), cp);
+
+ pmf = XListPixmapFormats (dpy, &n);
+ printf("number of supported pixmap formats: %d\n", n);
+ if (pmf) {
+ printf("supported pixmap formats:\n");
+ for (i = 0; i < n; i++) {
+ printf(" depth %d, bits_per_pixel %d, scanline_pad %d\n",
+ pmf[i].depth, pmf[i].bits_per_pixel, pmf[i].scanline_pad);
+ }
+ XFree ((char *) pmf);
+ }
+
+
+ /*
+ * when we get interfaces to the PixmapFormat stuff, insert code here
+ */
+
+ XDisplayKeycodes (dpy, &minkeycode, &maxkeycode);
+ printf("keycode range: minimum %d, maximum %d\n",
+ minkeycode, maxkeycode);
+
+ XGetInputFocus (dpy, &focuswin, &focusrevert);
+ printf("focus: ");
+ switch (focuswin) {
+ case PointerRoot:
+ printf("PointerRoot\n");
+ break;
+ case None:
+ printf("None\n");
+ break;
+ default:
+ printf("window 0x%lx, revert to ", focuswin);
+ switch (focusrevert) {
+ case RevertToParent:
+ printf("Parent\n");
+ break;
+ case RevertToNone:
+ printf("None\n");
+ break;
+ case RevertToPointerRoot:
+ printf("PointerRoot\n");
+ break;
+ default: /* should not happen */
+ printf("%d\n", focusrevert);
+ break;
+ }
+ break;
+ }
+
+ /* print_extension_info (dpy); */
+
+ printf("default screen number: %d\n", DefaultScreen (dpy));
+ printf("number of screens: %d\n", ScreenCount (dpy));
+}
+
+static void
+print_visual_info (vip)
+ XVisualInfo *vip;
+{
+ char errorbuf[40]; /* for sprintfing into */
+ char *class = NULL; /* for printing */
+
+ switch (vip->class) {
+ case StaticGray: class = "StaticGray"; break;
+ case GrayScale: class = "GrayScale"; break;
+ case StaticColor: class = "StaticColor"; break;
+ case PseudoColor: class = "PseudoColor"; break;
+ case TrueColor: class = "TrueColor"; break;
+ case DirectColor: class = "DirectColor"; break;
+ default:
+ sprintf(errorbuf, "unknown class %d", vip->class);
+ class = errorbuf;
+ break;
+ }
+
+ printf(" visual:\n");
+ printf(" visual id: 0x%lx\n", vip->visualid);
+ printf(" class: %s\n", class);
+ printf(" depth: %d plane%s\n", vip->depth,
+ vip->depth == 1 ? "" : "s");
+ if (vip->class == TrueColor || vip->class == DirectColor)
+ printf(" available colormap entries: %d per subfield\n",
+ vip->colormap_size);
+ else
+ printf(" available colormap entries: %d\n",
+ vip->colormap_size);
+ printf(" red, green, blue masks: 0x%lx, 0x%lx, 0x%lx\n",
+ vip->red_mask, vip->green_mask, vip->blue_mask);
+ printf(" significant bits in color specification: %d bits\n",
+ vip->bits_per_rgb);
+}
+
+static void
+print_screen_info (dpy, scr)
+ Display *dpy;
+ int scr;
+{
+ Screen *s = ScreenOfDisplay (dpy, scr); /* opaque structure */
+ XVisualInfo viproto; /* fill in for getting info */
+ XVisualInfo *vip; /* retured info */
+ int nvi; /* number of elements returned */
+ int i; /* temp variable: iterator */
+ /* char eventbuf[80]; */ /* want 79 chars per line + nul */
+ static char *yes = "YES", *no = "NO", *when = "WHEN MAPPED";
+ double xres, yres;
+ int ndepths = 0, *depths = NULL;
+ unsigned int width, height;
+
+
+ /*
+ * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
+ *
+ * dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
+ * = N pixels / (M inch / 25.4)
+ * = N * 25.4 pixels / M inch
+ */
+
+ xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) /
+ ((double) DisplayWidthMM(dpy,scr)));
+ yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) /
+ ((double) DisplayHeightMM(dpy,scr)));
+
+ printf("\n");
+ printf("screen #%d:\n", scr);
+ printf(" dimensions: %dx%d pixels (%dx%d millimeters)\n",
+ DisplayWidth (dpy, scr), DisplayHeight (dpy, scr),
+ DisplayWidthMM(dpy, scr), DisplayHeightMM (dpy, scr));
+ printf(" resolution: %dx%d dots per inch\n",
+ (int) (xres + 0.5), (int) (yres + 0.5));
+ depths = XListDepths (dpy, scr, &ndepths);
+ if (!depths) ndepths = 0;
+ printf(" depths (%d): ", ndepths);
+ for (i = 0; i < ndepths; i++) {
+ printf("%d", depths[i]);
+ if (i < ndepths - 1) {
+ putchar (',');
+ putchar (' ');
+ }
+ }
+ putchar ('\n');
+ if (depths) XFree ((char *) depths);
+ printf(" root window id: 0x%lx\n", RootWindow (dpy, scr));
+ printf(" depth of root window: %d plane%s\n",
+ DisplayPlanes (dpy, scr),
+ DisplayPlanes (dpy, scr) == 1 ? "" : "s");
+ printf(" number of colormaps: minimum %d, maximum %d\n",
+ MinCmapsOfScreen(s), MaxCmapsOfScreen(s));
+ printf(" default colormap: 0x%lx\n", DefaultColormap (dpy, scr));
+ printf(" default number of colormap cells: %d\n",
+ DisplayCells (dpy, scr));
+ printf(" preallocated pixels: black %lu, white %lu\n",
+ BlackPixel (dpy, scr), WhitePixel (dpy, scr));
+ printf(" options: backing-store %s, save-unders %s\n",
+ (DoesBackingStore (s) == NotUseful) ? no :
+ ((DoesBackingStore (s) == Always) ? yes : when),
+ DoesSaveUnders (s) ? yes : no);
+ XQueryBestSize (dpy, CursorShape, RootWindow (dpy, scr), 65535, 65535,
+ &width, &height);
+ if (width == 65535 && height == 65535)
+ printf(" largest cursor: unlimited\n");
+ else
+ printf(" largest cursor: %dx%d\n", width, height);
+ printf(" current input event mask: 0x%lx\n", EventMaskOfScreen (s));
+ /* (void) print_event_mask (eventbuf, 79, 4, EventMaskOfScreen (s)); */
+
+
+ nvi = 0;
+ viproto.screen = scr;
+ vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
+ printf(" number of visuals: %d\n", nvi);
+ printf(" default visual id: 0x%lx\n",
+ XVisualIDFromVisual (DefaultVisual (dpy, scr)));
+ for (i = 0; i < nvi; i++) {
+ print_visual_info (vip+i);
+ }
+ if (vip) XFree ((char *) vip);
+}
+
+
+/*
+ public function: when DBG_ALL is enabled, dump info on Xserver
+ to stdout.
+*/
+void
+print_xserver_info(void)
+{
+ int i;
+ if (globals.debug & DBG_PK) {
+ puts("========== Xserver properties info begin ==========\n");
+ print_display_info(DISP);
+ for (i = 0; i < ScreenCount(DISP); i++) {
+ print_screen_info(DISP, i);
+ }
+ puts("========== Xserver properties info end ==========\n");
+ }
+}
+
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* XSERVER_INFO */
diff --git a/Build/source/texk/xdvik/xserver-info.h b/Build/source/texk/xdvik/xserver-info.h
new file mode 100644
index 00000000000..d9e9d1d2c1f
--- /dev/null
+++ b/Build/source/texk/xdvik/xserver-info.h
@@ -0,0 +1,10 @@
+#ifndef XSERVER_INFO_H_
+#define XSERVER_INFO_H_
+
+#ifdef XSERVER_INFO
+
+extern void print_xserver_info(void);
+
+#endif /* XSERVER_INFO */
+
+#endif /* XSERVER_INFO_H_ */