diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/xdvik | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvik')
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, ®ex)) + 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(®ex, &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_ */ |