summaryrefslogtreecommitdiffstats
path: root/src/devices/xditview
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/xditview')
-rw-r--r--src/devices/xditview/ChangeLog556
-rw-r--r--src/devices/xditview/DESC.in9
-rw-r--r--src/devices/xditview/Dvi.c603
-rw-r--r--src/devices/xditview/Dvi.h46
-rw-r--r--src/devices/xditview/DviP.h235
-rw-r--r--src/devices/xditview/FontMap-X1117
-rw-r--r--src/devices/xditview/GXditview-color.ad15
-rw-r--r--src/devices/xditview/GXditview.ad71
-rw-r--r--src/devices/xditview/Menu.h46
-rw-r--r--src/devices/xditview/README13
-rw-r--r--src/devices/xditview/TODO21
-rw-r--r--src/devices/xditview/ad2c64
-rw-r--r--src/devices/xditview/device.c565
-rw-r--r--src/devices/xditview/device.h21
-rw-r--r--src/devices/xditview/draw.c709
-rw-r--r--src/devices/xditview/draw.h18
-rw-r--r--src/devices/xditview/font.c446
-rw-r--r--src/devices/xditview/font.h6
-rw-r--r--src/devices/xditview/gray1.bm4
-rw-r--r--src/devices/xditview/gray2.bm4
-rw-r--r--src/devices/xditview/gray3.bm4
-rw-r--r--src/devices/xditview/gray4.bm4
-rw-r--r--src/devices/xditview/gray5.bm4
-rw-r--r--src/devices/xditview/gray6.bm4
-rw-r--r--src/devices/xditview/gray7.bm4
-rw-r--r--src/devices/xditview/gray8.bm4
-rw-r--r--src/devices/xditview/gxditview.1.man815
-rw-r--r--src/devices/xditview/lex.c100
-rw-r--r--src/devices/xditview/lex.h1
-rw-r--r--src/devices/xditview/page.c86
-rw-r--r--src/devices/xditview/page.h5
-rw-r--r--src/devices/xditview/parse.c343
-rw-r--r--src/devices/xditview/parse.h1
-rw-r--r--src/devices/xditview/xdit.bm14
-rw-r--r--src/devices/xditview/xdit_mask.bm14
-rw-r--r--src/devices/xditview/xditview.am130
-rw-r--r--src/devices/xditview/xditview.c684
37 files changed, 5686 insertions, 0 deletions
diff --git a/src/devices/xditview/ChangeLog b/src/devices/xditview/ChangeLog
new file mode 100644
index 0000000..a33297b
--- /dev/null
+++ b/src/devices/xditview/ChangeLog
@@ -0,0 +1,556 @@
+2004-05-29 Werner LEMBERG <wl@gnu.org>
+
+ gxditview and xtotroff have been integrated into the normal groff
+ directory structure; future changes are logged in the main
+ ChangeLog file.
+
+2004-05-13 Werner LEMBERG <wl@gnu.org>
+
+Version 1.19.1 released
+=======================
+
+2004-04-17 Werner LEMBERG <wl@gnu.org>
+
+ * device.c (scale_round): Round correctly for negative values
+ (this is the same function as in src/libs/libgroff/font.c).
+ Found by Paul Eggert.
+
+2003-11-10 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile.in: s/@top_srcdir@/@abs_top_srcdir@/,
+ s/@groff_top_builddir@/@abs_top_builddir@/.
+
+Version 1.19 released
+=====================
+
+2003-03-03 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile.in (extraclean): Added gxditview._man.
+
+2003-01-28 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile.in (SEP): New variable; set to @PATH_SEPARATOR@.
+ (GROFF_FONTPATH): Use it.
+
+2003-01-07 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (Adobe_Symbol_map): Add `sqrt'.
+
+2003-01-06 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (Adobe_Symbol_map): Add `integral'.
+
+2002-12-29 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (ISO_8859_1_map): Remove `ap' and `eq'.
+
+2002-12-20 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (Adobe_Symbol_map): Don't include `or'.
+ * draw.c (AdjustCharDeltas): Apply correction only if nadj > 1.
+ (DoCharacter): Call FlushCharCache if font size and font number
+ differ.
+ Reset `dw->dvi.cache.adjustable' properly.
+
+2002-12-09 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (ISO_8859_1_map): Use `tno' symbol instead of `no'.
+
+2002-12-01 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile.in: Use `InstallAppDefaultsLong' instead of
+ `InstallAppDefaults' to make it work if build directory isn't
+ $srcdir.
+
+2002-11-24 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (Adobe_Symbol_map): Add glyph `braceex'.
+
+2002-11-14 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (ISO_8859_1_map): Don't include `or'.
+
+Version 1.18.1 released
+=======================
+
+2002-09-16 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile.in (GROFF_LOCALFONTDIR): New variable.
+ (GROFF_FONTPATH): Use it.
+ Remove /usr/local/lib/font.
+
+Version 1.18.0 released
+=======================
+
+2002-06-22 Werner LEMBERG <wl@gnu.org>
+
+ * gxditview.c (main): Handle `-help' and `--help' correctly.
+
+2002-06-17 Colin Watson <cjwatson@debian.org>
+
+ * Imakefile.in: s/@top_builddir@/@groff_top_builddir@/.
+
+2002-04-06 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (ISO_8859_1_map, Adobe_Symbol_map): Remove all
+ characters > 0x80.
+ * parse.c (ParseInput): Ignore `m' command.
+ (ParseDrawFunction): Don't move for unknown drawing functions.
+ Don't move for `f' drawing function.
+
+2002-03-25 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (ISO_8859_1_map): Use `t+-', `tmu', and `tdi' symbols
+ instead of `+-', `mu', and `di', respectively.
+
+2002-02-23 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c (ISO_8859_1_map): Add `mc' symbol.
+
+2001-09-22 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile.in: Redefine `ProgramTargetHelper' as
+ `ProgramTargetHelperNoMan' and add a call to `InstallManPageLong'
+ to make the `install.man' target work if the build directory isn't
+ $srcdir.
+
+Version 1.17.2 released
+=======================
+
+Version 1.17.1 released
+=======================
+
+2001-04-21 Albert Chin-A-Young <china@thewrittenword.com>
+
+ * Imakefile.in: Add support for recent HP architectures.
+
+Version 1.17 released
+=====================
+
+2001-01-04 Rob Daasch <daasch@ece.pdx.edu>
+
+ * parse.c (ParseInput): Added 'F' to command switch to swallow
+ filename strings as ignored comments.
+
+2000-12-02 Werner LEMBERG <wl@gnu.org>
+
+ * device.c (find_file): Remove home directory in search path.
+
+2000-11-14 Werner LEMBERG <wl@gnu.org>
+
+ * device.c (open_device_file): Remove `path' parameter.
+ (find_file): Construct font path similar to groff: First the contents
+ of GROFF_FONT_PATH, then the home directory, and finally the default
+ font path.
+ * Imakefile.in: Fix GROFF_DATAPROGRAMDIR and GROFF_FONTPATH.
+
+2000-10-23 Werner LEMBERG <wl@gnu.org>
+
+ Change installation structure for data files from .../groff/... to
+ .../groff/<version><revision>/... to be conform with other GNU
+ programs.
+
+ * Imakefile.in: Implement it.
+
+Version 1.16.1 released
+=======================
+
+Version 1.16 released
+=====================
+
+2000-05-18 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c: Adding `cq' as an alias for "'" in latin-1 map.
+
+2000-05-03 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c: Adding `dq' as an alias for `"' in latin-1 map.
+
+2000-04-28 Werner LEMBERG <wl@gnu.org>
+
+ * DviChar.c: Replacing `md' glyph name with `pc' in latin-1 map to
+ make it distinct from the `md' glyph in the symbol font.
+
+2000-03-03 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile replaced with Imakefile.in which will be configured by
+ the main configure script of groff. This will set the correct font
+ path, and it will make it possible to build xditview in a directory
+ different from $srcdir.
+
+2000-03-01 Colin Phipps <crp22@cam.ac.uk>
+
+ * Dvi.c (OpenFile): Use tmpdir() for security reasons.
+ * xtotroff.c (MapFont): Avoid race while opening file.
+
+2000-02-06 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile: Adapted to new directory structure.
+
+ * README: Updated.
+
+Version 1.15 released
+=====================
+
+1999-12-21 Werner LEMBERG <wl@gnu.org>
+
+ * README: Fixed ftp GNU address.
+
+1999-12-13 Werner LEMBERG <wl@gnu.org>
+
+ * device.c: Use extern declarations of strtok(), strchr(), and
+ getenv() only if not defined as macros.
+
+1999-11-18 Larry Jones <larry.jones@sdrc.com>
+
+ * xditview.c: Add fallback_resources to allow running without
+ access to the app-defaults file.
+
+ * Imakefile: Added rule to create app-defaults to a C header file.
+
+ * GXditview-ad.h: New file containing fallback default resources.
+
+ * ad2c: New file to do the app-defaults -> C header file
+ conversion.
+
+1999-10-27 Larry Jones <larry.jones@sdrc.com>
+
+ * font.c (DisposeFontSizes): If there's a problem loading a font,
+ xditview will fall-back and use the default font, but it hasn't
+ checked before unloading fonts which could result in unloading the
+ default font (possibly multiple times) and then X errors.
+
+1999-09-13 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile (extraclean): Added Makefile.
+
+ * xditview.c (main, MakePrompt): Fixing compilation warnings.
+
+ * TODO: Imakefile should be replaced with a configure script.
+
+1999-09-13 Werner LEMBERG <wl@gnu.org>
+
+ * Makefile: Removed.
+
+1999-09-12 Werner LEMBERG <wl@gnu.org>
+
+ * Imakefile (GROFF_FONTPATH): Another addition.
+
+ * device.c (FONTPATH): Update to match current groff version.
+
+1999-09-11 Larry Jones <larry.jones@sdrc.com>
+
+ * Imakefile (GROFF_LIBDIR, GROFF_FONTPATH): Update to match
+ current groff version.
+
+ * Dvi.c (Realize, Destroy), DviP.h, draw.c (setFillGC), gray*.bm:
+ Allow 8 levels of gray rather than just 1.
+
+ * draw.c (DrawFilledCircle, DrawFilledEllipse, DrawFilledPolygon):
+ Draw outlines to prevent gaps between abutting figures.
+
+1999-05-27 Werner LEMBERG <wl@gnu.org>
+
+ * xtotroff.c (usage): Fixed typo.
+
+Mon Sep 11 10:40:33 1995 James Clark <jjc@jclark.com>
+
+ * device.c (INT_MIN, INT_MAX): Don't define if already defined.
+
+Mon Aug 8 11:14:11 1994 James Clark (jjc@jclark.com)
+
+ * DviChar.c (Adobe_Symbol_map): Use \(nb for notsubset.
+
+Tue Apr 19 04:41:16 1994 James Clark (jjc@jclark.com)
+
+ * Dvi.c (resources): Change default for background and foreground
+ to "XtDefaultBackground" and "XtDefaultForeground".
+
+Sat Feb 12 10:38:47 1994 James Clark (jjc@jclark.com)
+
+ * DviChar.c (Adobe_Symbol_map): Rename radicalex to rn.
+
+Thu May 27 20:30:12 1993 James Clark (jjc@jclark.com)
+
+ * device.c (isascii): Define if necessary.
+ (canonicalize_name): Cast argument to isdigit() to unsigned char.
+
+Thu Apr 29 18:36:57 1993 James Clark (jjc at jclark.com)
+
+ * xditview.c: Include <X11/Xos.h>.
+ (NewFile): Don't declare rindex(). Use strrchr() rather than
+ rindex().
+
+Tue Mar 30 15:12:09 1993 James Clark (jjc at jclark)
+
+ * draw.c (charExists): Check that fi->per_char is not NULL.
+
+Sat Dec 12 17:42:40 1992 James Clark (jjc at jclark)
+
+ * Dvi.c (SetGeometry): Cast XtMakeGeometryRequest arguments.
+
+ * draw.c (DrawPolygon, DrawFilledPolygon): Cast Xtfree argument.
+
+ * font.c (DisposeFontSizes): Add declaration.
+
+ * draw.c (FakeCharacter): Add declaration.
+
+Wed Oct 28 13:24:00 1992 James Clark (jjc at jclark)
+
+ * Imakefile (install.dev): Deleted.
+ (fonts): New target.
+
+Mon Oct 12 10:50:44 1992 James Clark (jjc at jclark)
+
+ * Imakefile (install.dev): Say when we're installing devX*-12.
+
+ * Imakefile (install.dev): Depends on DESC and FontMap.
+
+Thu Oct 1 20:03:45 1992 James Clark (jjc at jclark)
+
+ * xditview.c (Syntax): Mention -filename option.
+
+Sat Aug 15 12:56:39 1992 James Clark (jjc at jclark)
+
+ * GXditview.ad: Bind space and return to NextPage. Bind backspace
+ and delete to previous page.
+
+ * DviChar.c (Adobe_Symbol_map): Add `an'.
+
+ * DviChar.c (Adobe_Symbol_map): Add arrowvertex, arrowverttp, and
+ arrowvertbt.
+
+Mon Aug 10 11:54:27 1992 James Clark (jjc at jclark)
+
+ * FontMap: Add m/p fields to the fonts names.
+
+Sat Aug 8 12:00:28 1992 James Clark (jjc at jclark)
+
+ * DESC: Leave font positions 5-9 blank.
+
+Tue Jul 28 11:37:05 1992 James Clark (jjc at jclark)
+
+ * Imakefile: Don't use gendef. Pass definition of FONTPATH using
+ DEFINES.
+ (path.h): Deleted.
+ (device.c): Don't include path.h. Provide default definition of
+ FONTPATH.
+
+Mon Jul 6 14:06:53 1992 James Clark (jjc at jclark)
+
+ * Imakefile: Don't install tmac.X and tmac.Xps.
+ * tmac.X, tmac.Xps: Moved to ../macros.
+
+ * Imakefile: Don't install eqnchar.
+ * eqnchar: Deleted.
+
+Sun Jun 14 12:55:02 1992 James Clark (jjc@jclark)
+
+ * tmac.Xps: Handle OE, oe, lq, rq.
+ * draw.c (FakeCharacter): Don't handle these.
+
+ * draw.c (FakeCharacter): Don't handle f/.
+
+Mon Jun 8 11:46:37 1992 James Clark (jjc@jclark)
+
+ * tmac.X: Translate char160 to space.
+
+Sun Jun 7 14:39:53 1992 James Clark (jjc@jclark)
+
+ * tmac.X: Do `mso tmac.psic' before restoring compatibility mode.
+
+ * tmac.X: Add \(OE, \(oe, \(ah, \(ao, \(ho.
+
+ * tmac.Xps: Make it work in compatibility mode.
+ Redo existing character definitions with .Xps-char.
+ Add more character definitions.
+ (Xps-char): New macro.
+
+Sat Jun 6 21:46:03 1992 James Clark (jjc@jclark)
+
+ * DviChar.c (Adobe_Symbol_map): Add +h, +f, +p, Fn, lz.
+ * tmac.X: Add \(bq, \(Bq, \(aq.
+ * tmac.Xps: Handle \(aq, \(bq, \(Bq, \(Fn.
+
+Wed Jun 3 11:11:15 1992 James Clark (jjc@jclark)
+
+ * DviChar.c (Adobe_Symbol_map): Add wp.
+
+Tue Apr 21 09:21:59 1992 James Clark (jjc at jclark)
+
+ * GXditview.ad: Bind n, p, q keys to NextPage, PreviousPage and
+ Quit actions.
+
+ * xditview.c (RerasterizeAction): New function.
+ (xditview_actions): Add RerasterizeAction.
+ * GXditview.ad: Bind r key to Rerasterize action.
+
+Fri Apr 17 08:25:36 1992 James Clark (jjc at jclark)
+
+ * xditview.c: Add -filename option.
+ (main): Copy any -filename argument into current_file_name.
+
+Mon Mar 16 10:21:58 1992 James Clark (jjc at jclark)
+
+ * tmac.X: Load tmac.pspic.
+
+Sun Mar 8 11:27:19 1992 James Clark (jjc at jclark)
+
+ * Lex.c (GetLine, GetWord, GetNumber): Rewrite.
+
+Sat Oct 12 22:58:52 1991 James Clark (jjc at jclark)
+
+ * Dvi.c (SetDevice): If the size change request is refused but a
+ larger geometry is offered, request that.
+
+Wed Oct 9 12:27:48 1991 James Clark (jjc at jclark)
+
+ * font.c (InstallFontSizes): Ignore FontNameAverageWidth component.
+
+ * Dvi.c (default_font_map): Add `adobe' to font names to avoid
+ ambiguity.
+
+ * FontMap: New file.
+ * FontMap.X100, FontMap.X75: Deleted.
+ * xtotroff.c (main, usage): Add -s and -r options.
+ (MapFont): Change the font pattern to have the selected resolution and
+ size.
+ * Imakefile (install.dev): Use FontMap and supply appropriate -s
+ and -r options.
+
+ * xtotroff.c (MapFont): Check for ambiguity by comparing canonicalized
+ font names.
+
+ * DviP.h (DviFontList): Add initialized and scalable members.
+ (font.c): Add support for scalable fonts based on R5 xditview.
+
+ * DviChar.c: Use xmalloc rather than malloc.
+ * xditview.c (xmalloc): New function.
+ * xtotroff.c (xmalloc): New function.
+ * other files: Use XtMalloc and XtFree instead of malloc and free.
+
+Thu Aug 29 20:15:31 1991 James Clark (jjc at jclark)
+
+ * draw.c (setGC): Do multiplication in floating point to avoid
+ overflow.
+
+Tue Aug 13 12:04:41 1991 James Clark (jjc at jclark)
+
+ * draw.c (FakeCharacter): Remove casts in definition of pack2.
+
+Tue Jul 30 11:42:39 1991 James Clark (jjc at jclark)
+
+ * tmac.Xps: New file.
+ * Imakefile (install): Install tmac.Xps.
+
+Tue Jul 2 09:31:37 1991 James Clark (jjc at jclark)
+
+ * xtotroff.c (main): Pass argv[0] to usage().
+
+Sun Jun 30 12:34:06 1991 James Clark (jjc at jclark)
+
+ * xtotroff.c (MapFont): Handle the case where XLoadQueryFont
+ returns NULL.
+
+Sat Jun 29 12:32:52 1991 James Clark (jjc at jclark)
+
+ * Imakefile: Use ../gendef to generate path.h.
+
+Sun Jun 16 13:26:34 1991 James Clark (jjc at jclark)
+
+ * Imakefile (depend.o): Change to device.o.
+
+Sun Jun 2 12:17:56 1991 James Clark (jjc at jclark)
+
+ * Imakefile: Remove spaces from the beginning of variable
+ assignment lines.
+
+Sun May 26 14:14:01 1991 James Clark (jjc at jclark)
+
+ * xditview.c (Syntax): Update.
+
+ * Dvi.c (DviSaveToFile, SaveToFile): New functions.
+ (FindPage): Check that we're not readingTmp before checking for
+ end of file of normal input file.
+ (ClassPartInitialize): New function.
+ * Dvi.h: Add declaration of DviSaveToFile.
+ * DviP.h: Add save method to DviClassPart. Declare
+ InheritSaveToFile.
+ * xditview.c (DoPrint, Print, PrintAction): New functions.
+ * xditview.c: Add print menu entry.
+ * xditview.c: Provide printCommand application resource.
+ * lex.c: Don't output EOF to temporary file.
+
+ * Dvi.c (QueryGeometry): Check request->request_mode.
+
+ * Dvi.c (SetDevice): New function.
+ (SetDeviceResolution): Deleted.
+
+ * Dvi.c: Add resolution resource.
+ * DviP.h: Add definitions of XtNResolution and XtCResolution.
+ * xditview.c: Add -resolution argument.
+ * GXditview.ad: Add default for GXditview.height.
+ * Dvi.c (Initialize, SetDevice): Use default_resolution.
+
+ * Dvi.c: Make MY_HEIGHT and MY_WIDTH use the paperlength and
+ paperwidth commands in the DESC file.
+
+ * Dvi.c: Add SS font to default font map.
+
+ * draw.c: Rewritten so as not to assume device and display
+ resolution is the same.
+ * DviP.h: Include device.h. Add device_font member to DviFontList.
+ Add adjustable array to DviCharCache. Add text_x_width,
+ text_device_width, word_flag, device_font, device_font_number,
+ device, native, device_resolution, display_resolution,
+ paperlength, paperwidth, scale_factor, sizescale members.
+ * Dvi.c (Initialize): Initialize new variable used by draw.c.
+ (Destroy): Call device_destroy.
+ * font.c (MaxFontPosition): New function.
+ (LookupFontSizeBySize): Handle sizescale.
+ (InstallFont): Load the device font.
+ (ForgetFonts): New function.
+ (QueryDeviceFont): New function.
+ * parse.c (ParseInput): Handle t and u commands. Split off
+ character output into draw.c.
+ (ParseDeviceControl): Ignore res command. Use the device argument
+ to the T command.
+
+ * font.c (MapXNameToDviName): Ifdefed out.
+
+ * path.h: New file.
+ * device.c, device.h: New files.
+
+ * DviChar.c: Add entries for lB, rB, oq, lC, rC, md.
+
+ * INSTALL: New file.
+
+ * libxdvi: Merged into main directory.
+ * xtotroff.c, xditview.c: Change includes accordingly.
+
+ * devX75, devX100: Merged into main directory.
+ * xditview.man: Renamed to gxditview.man.
+
+ * Xditview.ad: Renamed to GXditview.ad.
+ * xditview.c (main): Use class of GXditview rather than xditview.
+
+ * Imakefile: New file.
+ * Makefile: Deleted.
+
+ * xtotroff.c (MapFont): Unlink output file before opening it.
+
+ * Started separate ChangeLog.
+
+________________________________________________________________________
+
+Copyright 1991-2020 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+
+Local Variables:
+version-control: never
+mode: change-log
+coding: latin-1
+End:
diff --git a/src/devices/xditview/DESC.in b/src/devices/xditview/DESC.in
new file mode 100644
index 0000000..172170c
--- /dev/null
+++ b/src/devices/xditview/DESC.in
@@ -0,0 +1,9 @@
+styles R I B BI
+fonts 6 0 0 0 0 0 S
+sizes 8 10 12 14 18 24 0
+res 75
+X11
+hor 1
+vert 1
+unitwidth 10
+postpro gxditview
diff --git a/src/devices/xditview/Dvi.c b/src/devices/xditview/Dvi.c
new file mode 100644
index 0000000..3520676
--- /dev/null
+++ b/src/devices/xditview/Dvi.c
@@ -0,0 +1,603 @@
+#include <config.h>
+
+#ifndef SABER
+#ifndef lint
+static char Xrcsid[] = "$XConsortium: Dvi.c,v 1.9 89/12/10 16:12:25 rws Exp $";
+#endif /* lint */
+#endif /* SABER */
+
+/*
+ * Dvi.c - Dvi display widget
+ *
+ */
+
+#define XtStrlen(s) ((s) ? strlen(s) : 0)
+
+ /* The following are defined for the reader's convenience. Any
+ Xt..Field macro in this code just refers to some field in
+ one of the substructures of the WidgetRec. */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/Converters.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "DviP.h"
+#include "font.h"
+#include "page.h"
+#include "parse.h"
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* Private Data */
+
+static char default_font_map_1[] = "\
+TR -adobe-times-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+TI -adobe-times-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\
+TB -adobe-times-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+TBI -adobe-times-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\
+CR -adobe-courier-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+CI -adobe-courier-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\
+CB -adobe-courier-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+CBI -adobe-courier-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\
+";
+static char default_font_map_2[] = "\
+HR -adobe-helvetica-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+HI -adobe-helvetica-medium-o-normal--*-100-*-*-*-*-iso8859-1\n\
+HB -adobe-helvetica-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+HBI -adobe-helvetica-bold-o-normal--*-100-*-*-*-*-iso8859-1\n\
+";
+static char default_font_map_3[] = "\
+NR -adobe-new century schoolbook-medium-r-normal--*-100-*-*-*-*-iso8859-1\n\
+NI -adobe-new century schoolbook-medium-i-normal--*-100-*-*-*-*-iso8859-1\n\
+NB -adobe-new century schoolbook-bold-r-normal--*-100-*-*-*-*-iso8859-1\n\
+NBI -adobe-new century schoolbook-bold-i-normal--*-100-*-*-*-*-iso8859-1\n\
+S -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\
+SS -adobe-symbol-medium-r-normal--*-100-*-*-*-*-adobe-fontspecific\n\
+";
+
+#define offset(field) XtOffset(DviWidget, field)
+
+#define MY_WIDTH(dw) ((int)(dw->dvi.paperwidth * dw->dvi.scale_factor + .5))
+#define MY_HEIGHT(dw) ((int)(dw->dvi.paperlength * dw->dvi.scale_factor + .5))
+
+static XtResource resources[] = {
+ {(String)XtNfontMap, (String)XtCFontMap, (String)XtRString,
+ sizeof (char *), offset(dvi.font_map_string),
+ (String)XtRString, NULL /* set in code */},
+ {(String)XtNforeground, (String)XtCForeground, (String)XtRPixel,
+ sizeof (unsigned long), offset(dvi.foreground),
+ (String)XtRString, (XtPointer)"XtDefaultForeground"},
+ {(String)XtNbackground, (String)XtCBackground, (String)XtRPixel,
+ sizeof (unsigned long), offset(dvi.background),
+ (String)XtRString, (XtPointer)"XtDefaultBackground"},
+ {(String)XtNpageNumber, (String)XtCPageNumber, (String)XtRInt,
+ sizeof (int), offset(dvi.requested_page),
+ (String)XtRString, (XtPointer)"1"},
+ {(String)XtNlastPageNumber, (String)XtCLastPageNumber, (String)XtRInt,
+ sizeof (int), offset (dvi.last_page),
+ (String)XtRString, (XtPointer)"0"},
+ {(String)XtNfile, (String)XtCFile, (String)XtRFile,
+ sizeof (FILE *), offset (dvi.file),
+ (String)XtRFile, (XtPointer)0},
+ {(String)XtNseek, (String)XtCSeek, (String)XtRBoolean,
+ sizeof (Boolean), offset(dvi.seek),
+ (String)XtRString, (XtPointer)"false"},
+ {(String)XtNfont, (String)XtCFont, (String)XtRFontStruct,
+ sizeof (XFontStruct *), offset(dvi.default_font),
+ (String)XtRString, (XtPointer)"xtdefaultfont"},
+ {(String)XtNbackingStore, (String)XtCBackingStore, (String)XtRBackingStore,
+ sizeof (int), offset(dvi.backing_store),
+ (String)XtRString, (XtPointer)"default"},
+ {(String)XtNnoPolyText, (String)XtCNoPolyText, (String)XtRBoolean,
+ sizeof (Boolean), offset(dvi.noPolyText),
+ (String)XtRString, (XtPointer)"false"},
+ {(String)XtNresolution, (String)XtCResolution, (String)XtRInt,
+ sizeof(int), offset(dvi.default_resolution),
+ (String)XtRString, (XtPointer)"75"},
+};
+
+#undef offset
+
+static void ClassInitialize (void);
+static void ClassPartInitialize(WidgetClass);
+static void Initialize(Widget, Widget, ArgList, Cardinal *);
+static void Realize (Widget, XtValueMask *, XSetWindowAttributes *);
+static void Destroy (Widget);
+static void Redisplay (Widget, XEvent *, Region);
+static Boolean SetValues (Widget, Widget, Widget,
+ ArgList, Cardinal *);
+static Boolean SetValuesHook (Widget, ArgList, Cardinal *);
+static XtGeometryResult QueryGeometry (Widget, XtWidgetGeometry *,
+ XtWidgetGeometry *);
+static void ShowDvi (DviWidget);
+static void CloseFile (DviWidget);
+static void OpenFile (DviWidget);
+static void FindPage (DviWidget);
+
+static void SaveToFile (Widget, FILE *);
+
+DviClassRec dviClassRec = {
+{
+ &widgetClassRec, /* superclass */
+ (String)"Dvi", /* class_name */
+ sizeof(DviRec), /* size */
+ ClassInitialize, /* class_initialize */
+ ClassPartInitialize, /* class_part_initialize */
+ FALSE, /* class_inited */
+ Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ Realize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* resource_count */
+ NULLQUARK, /* xrm_class */
+ FALSE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ Destroy, /* destroy */
+ NULL, /* resize */
+ Redisplay, /* expose */
+ SetValues, /* set_values */
+ SetValuesHook, /* set_values_hook */
+ NULL, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ 0, /* tm_table */
+ QueryGeometry, /* query_geometry */
+ NULL, /* display_accelerator */
+ NULL /* extension */
+},{
+ SaveToFile, /* save */
+},
+};
+
+WidgetClass dviWidgetClass = (WidgetClass) &dviClassRec;
+
+static void ClassInitialize (void)
+{
+ int len1 = strlen(default_font_map_1);
+ int len2 = strlen(default_font_map_2);
+ int len3 = strlen(default_font_map_3);
+ char *dfm = XtMalloc(len1 + len2 + len3 + 1);
+ char *ptr = dfm;
+ strcpy(ptr, default_font_map_1); ptr += len1;
+ strcpy(ptr, default_font_map_2); ptr += len2;
+ strcpy(ptr, default_font_map_3);
+ resources[0].default_addr = dfm;
+
+ XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
+ NULL, 0 );
+}
+
+/****************************************************************
+ *
+ * Private Procedures
+ *
+ ****************************************************************/
+
+/* ARGSUSED */
+static void Initialize(Widget request, Widget new_wd,
+ ArgList args, Cardinal *num_args)
+{
+ DviWidget dw = (DviWidget) new_wd;
+
+ dw->dvi.current_page = 0;
+ dw->dvi.font_map = 0;
+ dw->dvi.cache.index = 0;
+ dw->dvi.text_x_width = 0;
+ dw->dvi.text_device_width = 0;
+ dw->dvi.word_flag = 0;
+ dw->dvi.file = 0;
+ dw->dvi.tmpFile = 0;
+ dw->dvi.state = 0;
+ dw->dvi.readingTmp = 0;
+ dw->dvi.cache.char_index = 0;
+ dw->dvi.cache.font_size = -1;
+ dw->dvi.cache.font_number = -1;
+ dw->dvi.cache.adjustable[0] = 0;
+ dw->dvi.file_map = 0;
+ dw->dvi.fonts = 0;
+ dw->dvi.seek = False;
+ dw->dvi.device_resolution = dw->dvi.default_resolution;
+ dw->dvi.display_resolution = dw->dvi.default_resolution;
+ dw->dvi.paperlength = dw->dvi.default_resolution*11;
+ dw->dvi.paperwidth = (dw->dvi.default_resolution*8
+ + dw->dvi.default_resolution/2);
+ dw->dvi.scale_factor = 1.0;
+ dw->dvi.sizescale = 1;
+ dw->dvi.line_thickness = -1;
+ dw->dvi.line_width = 1;
+ dw->dvi.fill = DVI_FILL_MAX;
+ dw->dvi.device_font = 0;
+ dw->dvi.device_font_number = -1;
+ dw->dvi.device = 0;
+ dw->dvi.native = 0;
+
+ request = request; /* unused; suppress compiler warning */
+ args = args;
+ num_args = num_args;
+}
+
+#include "gray1.bm"
+#include "gray2.bm"
+#include "gray3.bm"
+#include "gray4.bm"
+#include "gray5.bm"
+#include "gray6.bm"
+#include "gray7.bm"
+#include "gray8.bm"
+
+static void
+Realize (Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs)
+{
+ DviWidget dw = (DviWidget) w;
+ XGCValues values;
+
+ if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) {
+ attrs->backing_store = dw->dvi.backing_store;
+ *valueMask |= CWBackingStore;
+ }
+ XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent,
+ *valueMask, attrs);
+ values.foreground = dw->dvi.foreground;
+ values.cap_style = CapRound;
+ values.join_style = JoinRound;
+ values.line_width = dw->dvi.line_width;
+ dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w),
+ GCForeground|GCCapStyle|GCJoinStyle
+ |GCLineWidth,
+ &values);
+ dw->dvi.gray[0] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray1_bits,
+ gray1_width, gray1_height);
+ dw->dvi.gray[1] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray2_bits,
+ gray2_width, gray2_height);
+ dw->dvi.gray[2] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray3_bits,
+ gray3_width, gray3_height);
+ dw->dvi.gray[3] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray4_bits,
+ gray4_width, gray4_height);
+ dw->dvi.gray[4] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray5_bits,
+ gray5_width, gray5_height);
+ dw->dvi.gray[5] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray6_bits,
+ gray6_width, gray6_height);
+ dw->dvi.gray[6] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray7_bits,
+ gray7_width, gray7_height);
+ dw->dvi.gray[7] = XCreateBitmapFromData(XtDisplay (w), XtWindow (w),
+ gray8_bits,
+ gray8_width, gray8_height);
+ values.background = dw->dvi.background;
+ values.stipple = dw->dvi.gray[5];
+ dw->dvi.fill_GC = XCreateGC (XtDisplay (w), XtWindow (w),
+ GCForeground|GCBackground|GCStipple,
+ &values);
+
+ dw->dvi.fill_type = 9;
+
+ if (dw->dvi.file)
+ OpenFile (dw);
+ ParseFontMap (dw);
+}
+
+static void
+Destroy(Widget w)
+{
+ DviWidget dw = (DviWidget) w;
+
+ XFreeGC (XtDisplay (w), dw->dvi.normal_GC);
+ XFreeGC (XtDisplay (w), dw->dvi.fill_GC);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[0]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[1]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[2]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[3]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[4]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[5]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[6]);
+ XFreePixmap (XtDisplay (w), dw->dvi.gray[7]);
+ DestroyFontMap (dw->dvi.font_map);
+ DestroyFileMap (dw->dvi.file_map);
+ device_destroy (dw->dvi.device);
+}
+
+/*
+ * Repaint the widget window
+ */
+
+/* ARGSUSED */
+static void
+Redisplay(Widget w, XEvent *event, Region region)
+{
+ DviWidget dw = (DviWidget) w;
+ XRectangle extents;
+
+ XClipBox (region, &extents);
+ dw->dvi.extents.x1 = extents.x;
+ dw->dvi.extents.y1 = extents.y;
+ dw->dvi.extents.x2 = extents.x + extents.width;
+ dw->dvi.extents.y2 = extents.y + extents.height;
+ ShowDvi (dw);
+
+ event = event; /* unused; suppress compiler warning */
+}
+
+/*
+ * Set specified arguments into widget
+ */
+/* ARGSUSED */
+static Boolean
+SetValues (Widget wcurrent, Widget wrequest, Widget wnew,
+ ArgList args, Cardinal *num_args)
+{
+ Boolean redisplay = FALSE;
+ char *new_map;
+ int cur, req;
+ DviWidget current = (DviWidget)wcurrent;
+ DviWidget request = (DviWidget)wrequest;
+ DviWidget new_wd = (DviWidget)wnew;
+
+ if (current->dvi.font_map_string != request->dvi.font_map_string) {
+ new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1);
+ if (new_map) {
+ redisplay = TRUE;
+ strcpy (new_map, request->dvi.font_map_string);
+ new_wd->dvi.font_map_string = new_map;
+ if (current->dvi.font_map_string)
+ XtFree (current->dvi.font_map_string);
+ current->dvi.font_map_string = 0;
+ ParseFontMap (new_wd);
+ }
+ }
+
+ req = request->dvi.requested_page;
+ cur = current->dvi.requested_page;
+ if (cur != req) {
+ if (!request->dvi.file)
+ req = 0;
+ else {
+ if (req < 1)
+ req = 1;
+ if (current->dvi.last_page != 0 &&
+ req > current->dvi.last_page)
+ req = current->dvi.last_page;
+ }
+ if (cur != req)
+ redisplay = TRUE;
+ new_wd->dvi.requested_page = req;
+ if (current->dvi.last_page == 0 && req > cur)
+ FindPage (new_wd);
+ }
+
+ args = args; /* unused; suppress compiler warning */
+ num_args = num_args;
+
+ return redisplay;
+}
+
+/*
+ * use the set_values_hook entry to check when
+ * the file is set
+ */
+
+static Boolean
+SetValuesHook (Widget wdw, ArgList args, Cardinal *num_argsp)
+{
+ Cardinal i;
+ DviWidget dw = (DviWidget)wdw;
+
+ for (i = 0; i < *num_argsp; i++) {
+ if (!strcmp (args[i].name, XtNfile)) {
+ CloseFile (dw);
+ OpenFile (dw);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void CloseFile (DviWidget dw)
+{
+ if (dw->dvi.tmpFile)
+ fclose (dw->dvi.tmpFile);
+ ForgetPagePositions (dw);
+}
+
+static void OpenFile (DviWidget dw)
+{
+ dw->dvi.tmpFile = 0;
+ if (!dw->dvi.seek)
+ dw->dvi.tmpFile = tmpfile();
+ dw->dvi.requested_page = 1;
+ dw->dvi.last_page = 0;
+}
+
+static XtGeometryResult
+QueryGeometry (Widget w, XtWidgetGeometry *request,
+ XtWidgetGeometry *geometry_return)
+{
+ XtGeometryResult ret;
+ DviWidget dw = (DviWidget) w;
+
+ ret = XtGeometryYes;
+ if (((request->request_mode & CWWidth)
+ && request->width < MY_WIDTH(dw))
+ || ((request->request_mode & CWHeight)
+ && request->height < MY_HEIGHT(dw)))
+ ret = XtGeometryAlmost;
+ geometry_return->width = MY_WIDTH(dw);
+ geometry_return->height = MY_HEIGHT(dw);
+ geometry_return->request_mode = CWWidth|CWHeight;
+ return ret;
+}
+
+void
+SetDevice (DviWidget dw, const char *name)
+{
+ XtWidgetGeometry request, reply;
+ XtGeometryResult ret;
+
+ ForgetFonts (dw);
+ dw->dvi.device = device_load (name);
+ if (!dw->dvi.device)
+ return;
+ dw->dvi.sizescale = dw->dvi.device->sizescale;
+ dw->dvi.device_resolution = dw->dvi.device->res;
+ dw->dvi.native = dw->dvi.device->X11;
+ dw->dvi.paperlength = dw->dvi.device->paperlength;
+ dw->dvi.paperwidth = dw->dvi.device->paperwidth;
+ if (dw->dvi.native) {
+ dw->dvi.display_resolution = dw->dvi.device_resolution;
+ dw->dvi.scale_factor = 1.0;
+ }
+ else {
+ dw->dvi.display_resolution = dw->dvi.default_resolution;
+ dw->dvi.scale_factor = ((double)dw->dvi.display_resolution
+ / dw->dvi.device_resolution);
+ }
+ request.request_mode = CWWidth|CWHeight;
+ request.width = MY_WIDTH(dw);
+ request.height = MY_HEIGHT(dw);
+ ret = XtMakeGeometryRequest ((Widget)dw, &request, &reply);
+ if (ret == XtGeometryAlmost
+ && reply.height >= request.height
+ && reply.width >= request.width) {
+ request.width = reply.width;
+ request.height = reply.height;
+ XtMakeGeometryRequest ((Widget)dw, &request, &reply);
+ }
+}
+
+static void
+ShowDvi (DviWidget dw)
+{
+ if (!dw->dvi.file) {
+ static char Error[] = "No file selected";
+
+ XSetFont (XtDisplay(dw), dw->dvi.normal_GC,
+ dw->dvi.default_font->fid);
+ XDrawString (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ 20, 20, Error, strlen (Error));
+ return;
+ }
+
+ FindPage (dw);
+
+ dw->dvi.display_enable = 1;
+ ParseInput (dw);
+ if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page)
+ dw->dvi.requested_page = dw->dvi.last_page;
+}
+
+static void
+FindPage (DviWidget dw)
+{
+ int i;
+ long file_position;
+
+ if (dw->dvi.requested_page < 1)
+ dw->dvi.requested_page = 1;
+
+ if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page)
+ dw->dvi.requested_page = dw->dvi.last_page;
+
+ file_position = SearchPagePosition (dw, dw->dvi.requested_page);
+ if (file_position != -1) {
+ FileSeek(dw, file_position);
+ dw->dvi.current_page = dw->dvi.requested_page;
+ } else {
+ for (i=dw->dvi.requested_page; i > 0; i--) {
+ file_position = SearchPagePosition (dw, i);
+ if (file_position != -1)
+ break;
+ }
+ if (file_position == -1)
+ file_position = 0;
+ FileSeek (dw, file_position);
+
+ dw->dvi.current_page = i;
+
+ dw->dvi.display_enable = 0;
+ while (dw->dvi.current_page != dw->dvi.requested_page) {
+ dw->dvi.current_page = ParseInput (dw);
+ /*
+ * at EOF, seek back to the beginning of this page.
+ */
+ if (!dw->dvi.readingTmp && feof (dw->dvi.file)) {
+ file_position = SearchPagePosition (dw,
+ dw->dvi.current_page);
+ if (file_position != -1)
+ FileSeek (dw, file_position);
+ dw->dvi.requested_page = dw->dvi.current_page;
+ break;
+ }
+ }
+ }
+}
+
+void DviSaveToFile(Widget w, FILE *fp)
+{
+ XtCheckSubclass(w, dviWidgetClass, NULL);
+ (*((DviWidgetClass) XtClass(w))->command_class.save)(w, fp);
+}
+
+static
+void SaveToFile(Widget w, FILE *fp)
+{
+ DviWidget dw = (DviWidget)w;
+ long pos;
+ int c;
+
+ if (dw->dvi.tmpFile) {
+ pos = ftell(dw->dvi.tmpFile);
+ if (dw->dvi.ungot) {
+ pos--;
+ dw->dvi.ungot = 0;
+ /* The ungot character is in the tmpFile, so we don't
+ want to read it from file. */
+ (void)getc(dw->dvi.file);
+ }
+ }
+ else
+ pos = ftell(dw->dvi.file);
+ FileSeek(dw, 0L);
+ while (DviGetC(dw, &c) != EOF)
+ if (putc(c, fp) == EOF) {
+ /* XXX print error message */
+ break;
+ }
+ FileSeek(dw, pos);
+}
+
+static
+void ClassPartInitialize(WidgetClass widget_class)
+{
+ DviWidgetClass wc = (DviWidgetClass)widget_class;
+ DviWidgetClass super = (DviWidgetClass) wc->core_class.superclass;
+ if (wc->command_class.save == InheritSaveToFile)
+ wc->command_class.save = super->command_class.save;
+}
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/src/devices/xditview/Dvi.h b/src/devices/xditview/Dvi.h
new file mode 100644
index 0000000..bf97374
--- /dev/null
+++ b/src/devices/xditview/Dvi.h
@@ -0,0 +1,46 @@
+/*
+* $XConsortium: Dvi.h,v 1.4 89/07/21 14:22:06 jim Exp $
+*/
+
+#ifndef _XtDvi_h
+#define _XtDvi_h
+
+/***********************************************************************
+ *
+ * Dvi Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background pixel White
+ foreground Foreground Pixel Black
+ fontMap FontMap char * ...
+ pageNumber PageNumber int 1
+*/
+
+#define XtNfontMap (String)"fontMap"
+#define XtNpageNumber (String)"pageNumber"
+#define XtNlastPageNumber (String)"lastPageNumber"
+#define XtNnoPolyText (String)"noPolyText"
+#define XtNseek (String)"seek"
+#define XtNresolution (String)"resolution"
+
+#define XtCFontMap (String)"FontMap"
+#define XtCPageNumber (String)"PageNumber"
+#define XtCLastPageNumber (String)"LastPageNumber"
+#define XtCNoPolyText (String)"NoPolyText"
+#define XtCSeek (String)"Seek"
+#define XtCResolution (String)"Resolution"
+
+typedef struct _DviRec *DviWidget; /* completely defined in DviP.h */
+typedef struct _DviClassRec *DviWidgetClass; /* completely defined in DviP.h */
+
+extern WidgetClass dviWidgetClass;
+
+void DviSaveToFile(Widget, FILE *);
+
+#endif /* _XtDvi_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/src/devices/xditview/DviP.h b/src/devices/xditview/DviP.h
new file mode 100644
index 0000000..8b71c69
--- /dev/null
+++ b/src/devices/xditview/DviP.h
@@ -0,0 +1,235 @@
+/*
+ * $XConsortium: DviP.h,v 1.5 89/07/22 19:44:08 keith Exp $
+ */
+
+/*
+ * DviP.h - Private definitions for Dvi widget
+ */
+
+#ifndef _XtDviP_h
+#define _XtDviP_h
+
+#include "Dvi.h"
+#include "DviChar.h"
+#include "device.h"
+
+/***********************************************************************
+ *
+ * Dvi Widget Private Data
+ *
+ ***********************************************************************/
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+/* Type for save method. */
+
+typedef void (*DviSaveProc)(Widget, FILE *);
+
+/*
+ * New fields for the Dvi widget class record
+ */
+
+
+typedef struct _DviClass {
+ DviSaveProc save;
+} DviClassPart;
+
+/*
+ * Full class record declaration
+ */
+
+typedef struct _DviClassRec {
+ CoreClassPart core_class;
+ DviClassPart command_class;
+} DviClassRec;
+
+extern DviClassRec dviClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+/*
+ * a list of fonts we've used for this widget
+ */
+
+typedef struct _dviFontSizeList {
+ struct _dviFontSizeList *next;
+ int size;
+ char *x_name;
+ XFontStruct *font;
+ int doesnt_exist;
+} DviFontSizeList;
+
+typedef struct _dviFontList {
+ struct _dviFontList *next;
+ char *dvi_name;
+ char *x_name;
+ int dvi_number;
+ Boolean initialized;
+ Boolean scalable;
+ DviFontSizeList *sizes;
+ DviCharNameMap *char_map;
+ DeviceFont *device_font;
+} DviFontList;
+
+typedef struct _dviFontMap {
+ struct _dviFontMap *next;
+ char *dvi_name;
+ char *x_name;
+} DviFontMap;
+
+#define DVI_TEXT_CACHE_SIZE 256
+#define DVI_CHAR_CACHE_SIZE 1024
+
+typedef struct _dviCharCache {
+ XTextItem cache[DVI_TEXT_CACHE_SIZE];
+ char adjustable[DVI_TEXT_CACHE_SIZE];
+ char char_cache[DVI_CHAR_CACHE_SIZE];
+ int index;
+ int max;
+ int char_index;
+ int font_size;
+ int font_number;
+ XFontStruct *font;
+ int start_x, start_y;
+ int x, y;
+} DviCharCache;
+
+typedef struct _dviState {
+ struct _dviState *next;
+ int font_size;
+ int font_number;
+ int x;
+ int y;
+} DviState;
+
+typedef struct _dviFileMap {
+ struct _dviFileMap *next;
+ long position;
+ int page_number;
+} DviFileMap;
+
+/*
+ * New fields for the Dvi widget record
+ */
+
+typedef struct {
+ /*
+ * resource specifiable items
+ */
+ char *font_map_string;
+ unsigned long foreground;
+ unsigned long background;
+ int requested_page;
+ int last_page;
+ XFontStruct *default_font;
+ FILE *file;
+ Boolean noPolyText;
+ Boolean seek; /* file is 'seekable' */
+ int default_resolution;
+ /*
+ * private state
+ */
+ FILE *tmpFile; /* used when reading stdin */
+ char readingTmp; /* reading now from tmp */
+ char ungot; /* have ungetc'd a char */
+ GC normal_GC;
+ GC fill_GC;
+ DviFileMap *file_map;
+ DviFontList *fonts;
+ DviFontMap *font_map;
+ int current_page;
+ int font_size;
+ int font_number;
+ DeviceFont *device_font;
+ int device_font_number;
+ Device *device;
+ int native;
+ int device_resolution;
+ int display_resolution;
+ int paperlength;
+ int paperwidth;
+ double scale_factor; /* display res / device res */
+ int sizescale;
+ int line_thickness;
+ int line_width;
+
+#define DVI_FILL_MAX 1000
+
+ int fill;
+#define DVI_FILL_WHITE 0
+#define DVI_FILL_GRAY 1
+#define DVI_FILL_BLACK 2
+ int fill_type;
+ Pixmap gray[8];
+ int backing_store;
+ XFontStruct *font;
+ int display_enable;
+ struct ExposedExtents {
+ int x1, y1, x2, y2;
+ } extents;
+ DviState *state;
+ DviCharCache cache;
+ int text_x_width;
+ int text_device_width;
+ int word_flag;
+} DviPart;
+
+int DviGetAndPut(DviWidget, int *);
+#define DviGetIn(dw,cp)\
+ (dw->dvi.tmpFile ? (\
+ DviGetAndPut (dw, cp) \
+ ) :\
+ (*cp = getc (dw->dvi.file))\
+)
+
+#define DviGetC(dw, cp)\
+ (dw->dvi.readingTmp ? (\
+ ((*cp = getc (dw->dvi.tmpFile)) == EOF) ? (\
+ fseek (dw->dvi.tmpFile, 0l, 2),\
+ (dw->dvi.readingTmp = 0),\
+ DviGetIn (dw,cp)\
+ ) : (\
+ *cp\
+ )\
+ ) : (\
+ DviGetIn(dw,cp)\
+ )\
+)
+
+#define DviUngetC(dw, c)\
+ (dw->dvi.readingTmp ? (\
+ ungetc (c, dw->dvi.tmpFile)\
+ ) : ( \
+ (dw->dvi.ungot = 1),\
+ ungetc (c, dw->dvi.file)))
+
+/*
+ * Full widget declaration
+ */
+
+typedef struct _DviRec {
+ CorePart core;
+ DviPart dvi;
+} DviRec;
+
+#define InheritSaveToFile ((DviSaveProc)_XtInherit)
+
+XFontStruct *QueryFont (DviWidget, int, int);
+
+DviCharNameMap *QueryFontMap (DviWidget, int);
+
+DeviceFont *QueryDeviceFont (DviWidget, int);
+
+char *GetWord(DviWidget, char *, int);
+char *GetLine(DviWidget, char *, int);
+
+void SetDevice (DviWidget dw, const char *name);
+#endif /* _XtDviP_h */
diff --git a/src/devices/xditview/FontMap-X11 b/src/devices/xditview/FontMap-X11
new file mode 100644
index 0000000..90911f0
--- /dev/null
+++ b/src/devices/xditview/FontMap-X11
@@ -0,0 +1,17 @@
+TR -adobe-times-medium-r-normal--*-*-*-*-p-*-iso8859-1
+TI -adobe-times-medium-i-normal--*-*-*-*-p-*-iso8859-1
+TB -adobe-times-bold-r-normal--*-*-*-*-p-*-iso8859-1
+TBI -adobe-times-bold-i-normal--*-*-*-*-p-*-iso8859-1
+CR -adobe-courier-medium-r-normal--*-*-*-*-m-*-iso8859-1
+CI -adobe-courier-medium-o-normal--*-*-*-*-m-*-iso8859-1
+CB -adobe-courier-bold-r-normal--*-*-*-*-m-*-iso8859-1
+CBI -adobe-courier-bold-o-normal--*-*-*-*-m-*-iso8859-1
+HR -adobe-helvetica-medium-r-normal--*-*-*-*-p-*-iso8859-1
+HI -adobe-helvetica-medium-o-normal--*-*-*-*-p-*-iso8859-1
+HB -adobe-helvetica-bold-r-normal--*-*-*-*-p-*-iso8859-1
+HBI -adobe-helvetica-bold-o-normal--*-*-*-*-p-*-iso8859-1
+NR -adobe-new century schoolbook-medium-r-normal--*-*-*-*-p-*-iso8859-1
+NI -adobe-new century schoolbook-medium-i-normal--*-*-*-*-p-*-iso8859-1
+NB -adobe-new century schoolbook-bold-r-normal--*-*-*-*-p-*-iso8859-1
+NBI -adobe-new century schoolbook-bold-i-normal--*-*-*-*-p-*-iso8859-1
+S -adobe-symbol-medium-r-normal--*-*-*-*-p-*-adobe-fontspecific
diff --git a/src/devices/xditview/GXditview-color.ad b/src/devices/xditview/GXditview-color.ad
new file mode 100644
index 0000000..61abd8f
--- /dev/null
+++ b/src/devices/xditview/GXditview-color.ad
@@ -0,0 +1,15 @@
+
+#include "GXditview"
+
+GXditview.paned.viewport.Scrollbar.background: Thistle
+GXditview.paned.viewport.Scrollbar.foreground: Orchid
+GXditview.paned.viewport.Scrollbar.thumb: None
+GXditview.paned.viewport.dvi.background: LemonChiffon
+GXditview.paned.viewport.background: Thistle
+GXditview.paned.label.background: PeachPuff
+GXditview.menu.background: Gold
+GXditview.promptShell.promptDialog*background: Gold
+GXditview.promptShell.promptDialog.accept.background: DarkOliveGreen1
+GXditview.promptShell.promptDialog.cancel.background: RosyBrown1
+GXditview.promptShell.promptDialog.value.background: Khaki
+
diff --git a/src/devices/xditview/GXditview.ad b/src/devices/xditview/GXditview.ad
new file mode 100644
index 0000000..549f0d7
--- /dev/null
+++ b/src/devices/xditview/GXditview.ad
@@ -0,0 +1,71 @@
+
+GXditview*shapeStyle: rectangle
+
+GXditview.paned.allowResize: true
+GXditview.paned.label.skipAdjust: true
+GXditview.paned.viewport.skipAdjust: false
+GXditview.paned.viewport.showGrip: false
+GXditview.paned.viewport.allowVert: true
+GXditview.paned.viewport.allowHoriz: true
+GXditview.paned.viewport.forceBars: true
+! viewport size = papersize * resol + scrollbarthickness + 1
+! letter size paper
+!GXditview.paned.viewport.width: 652
+!GXditview.paned.viewport.height: 840
+! a4 size paper
+! 865 is wide enough for a page of X100-12.
+GXditview.paned.viewport.width: 865
+GXditview.paned.viewport.height: 892
+GXditview.paned.viewport.Scrollbar.thickness: 14
+
+GXditview.geometry: 865x892
+
+GXditview.paned.translations: #augment \
+ <Key>Next: NextPage()\n\
+ <Key>n: NextPage()\n\
+ <Key>space: NextPage()\n\
+ <Key>Return: NextPage()\n\
+ <Key>Prior: PreviousPage()\n\
+ <Key>p: PreviousPage()\n\
+ <Key>b: PreviousPage()\n\
+ <Key>BackSpace: PreviousPage()\n\
+ <Key>Delete: PreviousPage()\n\
+ <Key>g: SelectPage()\n\
+ <Key>o: OpenFile()\n\
+ <Key>r: Rerasterize()\n\
+ <Key>q: Quit()
+GXditview.paned.viewport.clip.translations: #augment \
+ <Btn1Down>: XawPositionSimpleMenu(menu) MenuPopup(menu)
+GXditview.paned.label.translations: #augment \
+ <Btn1Down>: XawPositionSimpleMenu(menu) MenuPopup(menu)
+GXditview.paned.viewport.vertical.accelerators: #override \
+ <Key>k: StartScroll(Backward) NotifyScroll(FullLength) EndScroll()\n\
+ <Key>j: StartScroll(Forward) NotifyScroll(FullLength) EndScroll()\n\
+ <Key>Up: StartScroll(Backward) NotifyScroll(FullLength) EndScroll()\n\
+ <Key>Down: StartScroll(Forward) NotifyScroll(FullLength) EndScroll()
+GXditview.paned.viewport.horizontal.accelerators: #override \
+ <Key>h: StartScroll(Backward) NotifyScroll(FullLength) EndScroll()\n\
+ <Key>l: StartScroll(Forward) NotifyScroll(FullLength) EndScroll()\n\
+ <Key>Left: StartScroll(Backward) NotifyScroll(FullLength) EndScroll()\n\
+ <Key>Right: StartScroll(Forward) NotifyScroll(FullLength) EndScroll()
+
+GXditview.menu.nextPage.label: Next Page
+GXditview.menu.previousPage.label: Previous Page
+GXditview.menu.selectPage.label: Goto Page
+GXditview.menu.print.label: Print
+GXditview.menu.openFile.label: Open
+GXditview.menu.quit.label: Quit
+
+GXditview.promptShell.allowShellResize: true
+GXditview.promptShell.promptDialog.value.translations: #override \
+ <Key>Return: Accept() \n\
+ <Key>Escape: Cancel()
+
+GXditview.promptShell.promptDialog.accept.label: Accept
+GXditview.promptShell.promptDialog.accept.translations: #override \
+ <BtnUp>: Accept() unset()
+
+GXditview.promptShell.promptDialog.cancel.label: Cancel
+GXditview.promptShell.promptDialog.cancel.translations: #override \
+ <BtnUp>: Cancel() unset()
+
diff --git a/src/devices/xditview/Menu.h b/src/devices/xditview/Menu.h
new file mode 100644
index 0000000..c306b27
--- /dev/null
+++ b/src/devices/xditview/Menu.h
@@ -0,0 +1,46 @@
+/*
+ * $XConsortium: Menu.h,v 1.2 89/07/21 14:22:10 jim Exp $
+ */
+
+#ifndef _XtMenu_h
+#define _XtMenu_h
+
+/***********************************************************************
+ *
+ * Menu Widget
+ *
+ ***********************************************************************/
+
+/* Parameters:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ background Background pixel White
+ border BorderColor pixel Black
+ borderWidth BorderWidth int 1
+ height Height int 120
+ mappedWhenManaged MappedWhenManaged Boolean True
+ reverseVideo ReverseVideo Boolean False
+ width Width int 120
+ x Position int 0
+ y Position int 0
+
+*/
+
+#define XtNmenuEntries "menuEntries"
+#define XtNhorizontalPadding "horizontalPadding"
+#define XtNverticalPadding "verticalPadding"
+#define XtNselection "Selection"
+
+#define XtCMenuEntries "MenuEntries"
+#define XtCPadding "Padding"
+#define XtCSelection "Selection"
+
+typedef struct _MenuRec *MenuWidget; /* completely defined in MenuPrivate.h */
+typedef struct _MenuClassRec *MenuWidgetClass; /* completely defined in MenuPrivate.h */
+
+extern WidgetClass menuWidgetClass;
+
+extern Widget XawMenuCreate ();
+#endif /* _XtMenu_h */
+/* DON'T ADD STUFF AFTER THIS #endif */
diff --git a/src/devices/xditview/README b/src/devices/xditview/README
new file mode 100644
index 0000000..9de7869
--- /dev/null
+++ b/src/devices/xditview/README
@@ -0,0 +1,13 @@
+This is gxditview, an X11 previewer for groff based on MIT's xditview.
+This version can be used with the output of gtroff -Tps as well as
+with -TX75 and -TX100. You will need X11R5 or newer to install it (it
+might work on X11R4, but I haven't tested it.)
+
+Previously, gxditview was installed in the usual place for X binaries
+(e.g., /usr/bin/X11); you have to remove it manually.
+
+xditview is copyrighted by MIT under the usual X terms (see
+gxditview.man); the changes to that which come along with the groff package
+are in the public domain.
+
+Please report bugs at http://savannah.gnu.org/bugs/?group=groff.
diff --git a/src/devices/xditview/TODO b/src/devices/xditview/TODO
new file mode 100644
index 0000000..0b5b140
--- /dev/null
+++ b/src/devices/xditview/TODO
@@ -0,0 +1,21 @@
+Open the main window with the correct width and height, depending on
+both the selected device and the paper dimensions.
+
+Add a command-line option to specify the paper dimensions (similar to
+other groff devices).
+
+Better error handling.
+
+Resource and command-line option to specify font path.
+
+Resource to specify name of environment variable from which to get the
+font path.
+
+Have character substitutions (currently done in draw.c:FakeCharacter)
+specified in a resource (similar format to FontMap).
+
+The initial width of the dialog box should expand to accommodate the
+default value.
+
+Option in Print dialog to specify that only the current page should be
+printed.
diff --git a/src/devices/xditview/ad2c b/src/devices/xditview/ad2c
new file mode 100644
index 0000000..2ec45ed
--- /dev/null
+++ b/src/devices/xditview/ad2c
@@ -0,0 +1,64 @@
+#! /bin/sh
+#
+# ad2c : Convert app-defaults file to C strings decls.
+#
+# George Ferguson, ferguson@cs.rcohester.edu, 12 Nov 1990.
+# 19 Mar 1991: gf
+# Made it self-contained.
+# 6 Jan 1992: mycroft@gnu.ai.mit.edu (Charles Hannum)
+# Removed use of "-n" and ":read" label since Gnu and
+# IBM sed print pattern space on "n" command. Still works
+# with Sun sed, of course.
+# 7 Jan 1992: matthew@sunpix.East.Sun.COM (Matthew Stier)
+# Escape quotes after escaping backslashes.
+# 8 Jul 1992: Version 1.6
+# Manpage fixes.
+# 19 Apr 1993: Version 1.7
+# Remove comments that were inside the sed command since
+# some versions of sed don't like them. The comments are
+# now given here in the header.
+# 31 May 2004: Werner Lemberg <wl@gnu.org>
+# Force casts to 'String'.
+#
+# Comments on the script by line:
+# /^!/d Remove comments
+# /^$/d Remove blanks
+# s/\\/\\\\/g Escape backslashes...
+# s/\\$//g ...except the line continuation ones
+# s/"/\\"/g Escape quotes
+# s/^/"/ Add leading quote and cast
+# : test Establish label for later branch
+# /\\$/b slash Branch to label "slash" if line ends in backslash
+# s/$/",/ Otherwise add closing quote and comma...
+# p ...output the line...
+# d ...and clear the pattern space so it's not printed again
+# : slash Branch comes here if line ends in backslash
+# n Read next line, append to pattern space
+# [...] The "d" and "s" commands that follow just delete
+# comments and blank lines and escape control sequences
+# b test Branch up to see if the line ends in backslash or not
+#
+
+sed '
+/^!/d
+/^$/d
+s/\\/\\\\/g
+s/\\$//g
+s/"/\\"/g
+s/^/(String)"/
+: test
+/\\$/b slash
+s/$/",/
+p
+d
+: slash
+n
+/^!/d
+/^$/d
+s/"/\\"/g
+s/\\\\/\\/g
+s/\\n/\\\\n/g
+s/\\t/\\\\t/g
+s/\\f/\\\\f/g
+s/\\b/\\\\b/g
+b test' "$@"
diff --git a/src/devices/xditview/device.c b/src/devices/xditview/device.c
new file mode 100644
index 0000000..1eaafbe
--- /dev/null
+++ b/src/devices/xditview/device.c
@@ -0,0 +1,565 @@
+/* device.c */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+
+#include "device.h"
+#include "defs.h"
+
+#ifndef isascii
+#define isascii(c) (1)
+#endif
+
+/* Name of environment variable containing path to be used for
+searching for device and font description files. */
+#define FONTPATH_ENV_VAR "GROFF_FONT_PATH"
+
+#define WS " \t\r\n"
+
+#ifndef INT_MIN
+/* Minimum and maximum values a 'signed int' can hold. */
+#define INT_MIN (-INT_MAX-1)
+#define INT_MAX 2147483647
+#endif
+
+#define CHAR_TABLE_SIZE 307
+
+struct _DeviceFont {
+ char *name;
+ int special;
+ DeviceFont *next;
+ Device *dev;
+ struct charinfo *char_table[CHAR_TABLE_SIZE];
+ struct charinfo *code_table[256];
+};
+
+struct charinfo {
+ int width;
+ int code;
+ struct charinfo *next;
+ struct charinfo *code_next;
+ char name[1];
+};
+
+static char *current_filename = 0;
+static int current_lineno = -1;
+
+static void error(const char *s);
+static FILE *open_device_file(const char *, const char *, char **);
+static DeviceFont *load_font(Device *, const char *);
+static Device *new_device(const char *);
+static DeviceFont *new_font(const char *, Device *);
+static void delete_font(DeviceFont *);
+static unsigned hash_name(const char *);
+static struct charinfo *add_char(DeviceFont *, const char *, int, int);
+static int read_charset_section(DeviceFont *, FILE *);
+static char *canonicalize_name(const char *);
+static int scale_round(int, int, int);
+
+static
+Device *new_device(const char *name)
+{
+ Device *dev;
+
+ dev = XtNew(Device);
+ dev->sizescale = 1;
+ dev->res = 0;
+ dev->unitwidth = 0;
+ dev->fonts = 0;
+ dev->X11 = 0;
+ dev->paperlength = 0;
+ dev->paperwidth = 0;
+ dev->name = XtNewString(name);
+ return dev;
+}
+
+void device_destroy(Device *dev)
+{
+ DeviceFont *f;
+
+ if (!dev)
+ return;
+ f = dev->fonts;
+ while (f) {
+ DeviceFont *tem = f;
+ f = f->next;
+ delete_font(tem);
+ }
+
+ XtFree(dev->name);
+ XtFree((char *)dev);
+}
+
+Device *device_load(const char *name)
+{
+ Device *dev;
+ FILE *fp;
+ int err = 0;
+ char buf[256];
+
+ fp = open_device_file(name, "DESC", &current_filename);
+ if (!fp)
+ return 0;
+ dev = new_device(name);
+ current_lineno = 0;
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *p;
+ current_lineno++;
+ p = strtok(buf, WS);
+ if (p) {
+ int *np = 0;
+ char *q;
+
+ if (strcmp(p, "charset") == 0)
+ break;
+ if (strcmp(p, "X11") == 0)
+ dev->X11 = 1;
+ else if (strcmp(p, "sizescale") == 0)
+ np = &dev->sizescale;
+ else if (strcmp(p, "res") == 0)
+ np = &dev->res;
+ else if (strcmp(p, "unitwidth") == 0)
+ np = &dev->unitwidth;
+ else if (strcmp(p, "paperwidth") == 0)
+ np = &dev->paperwidth;
+ else if (strcmp(p, "paperlength") == 0)
+ np = &dev->paperlength;
+
+ if (np) {
+ q = strtok((char *)0, WS);
+ if (!q || sscanf(q, "%d", np) != 1 || *np <= 0) {
+ error("bad argument");
+ err = 1;
+ break;
+ }
+ }
+ }
+ }
+ fclose(fp);
+ current_lineno = -1;
+ if (!err) {
+ if (dev->res == 0) {
+ error("missing res line");
+ err = 1;
+ }
+ else if (dev->unitwidth == 0) {
+ error("missing unitwidth line");
+ err = 1;
+ }
+ }
+ if (dev->paperlength == 0)
+ dev->paperlength = dev->res*11;
+ if (dev->paperwidth == 0)
+ dev->paperwidth = dev->res*8 + dev->res/2;
+ if (err) {
+ device_destroy(dev);
+ dev = 0;
+ }
+ XtFree(current_filename);
+ current_filename = 0;
+ return dev;
+}
+
+
+DeviceFont *device_find_font(Device *dev, const char *name)
+{
+ DeviceFont *f;
+
+ if (!dev)
+ return 0;
+ for (f = dev->fonts; f; f = f->next)
+ if (strcmp(f->name, name) == 0)
+ return f;
+ return load_font(dev, name);
+}
+
+static
+DeviceFont *load_font(Device *dev, const char *name)
+{
+ FILE *fp;
+ char buf[256];
+ DeviceFont *f;
+ int special = 0;
+
+ fp = open_device_file(dev->name, name, &current_filename);
+ if (!fp)
+ return 0;
+ current_lineno = 0;
+ for (;;) {
+ char *p;
+
+ if (!fgets(buf, sizeof(buf), fp)) {
+ error("no charset line");
+ return 0;
+ }
+ current_lineno++;
+ p = strtok(buf, WS);
+ /* charset must be on a line by itself */
+ if (p && strcmp(p, "charset") == 0 && strtok((char *)0, WS) == 0)
+ break;
+ if (p && strcmp(p, "special") == 0)
+ special = 1;
+ }
+ f = new_font(name, dev);
+ f->special = special;
+ if (!read_charset_section(f, fp)) {
+ delete_font(f);
+ f = 0;
+ }
+ else {
+ f->next = dev->fonts;
+ dev->fonts = f;
+ }
+ fclose(fp);
+ XtFree(current_filename);
+ current_filename = 0;
+ return f;
+}
+
+static
+DeviceFont *new_font(const char *name, Device *dev)
+{
+ int i;
+ DeviceFont *f;
+
+ f = XtNew(DeviceFont);
+ f->name = XtNewString(name);
+ f->dev = dev;
+ f->special = 0;
+ f->next = 0;
+ for (i = 0; i < CHAR_TABLE_SIZE; i++)
+ f->char_table[i] = 0;
+ for (i = 0; i < 256; i++)
+ f->code_table[i] = 0;
+ return f;
+}
+
+static
+void delete_font(DeviceFont *f)
+{
+ int i;
+
+ if (!f)
+ return;
+ XtFree(f->name);
+ for (i = 0; i < CHAR_TABLE_SIZE; i++) {
+ struct charinfo *ptr = f->char_table[i];
+ while (ptr) {
+ struct charinfo *tem = ptr;
+ ptr = ptr->next;
+ XtFree((char *)tem);
+ }
+ }
+ XtFree((char *)f);
+}
+
+
+static
+unsigned hash_name(const char *name)
+{
+ unsigned n = 0;
+ /* XXX do better than this */
+ while (*name)
+ n = (n << 1) ^ *name++;
+
+ return n;
+}
+
+static
+int scale_round(int n, int x, int y)
+{
+ int y2;
+
+ if (x == 0)
+ return 0;
+ y2 = y/2;
+ if (n >= 0) {
+ if (n <= (INT_MAX - y2)/x)
+ return (n*x + y2)/y;
+ return (int)(n*(double)x/(double)y + .5);
+ }
+ else {
+ if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x)
+ return (n*x - y2)/y;
+ return (int)(n*(double)x/(double)y + .5);
+ }
+}
+
+static
+char *canonicalize_name(const char *s)
+{
+ static char ch[2];
+ if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') {
+ const char *p;
+ int n;
+
+ for (p = s + 4; *p; p++)
+ if (!isascii(*p) || !isdigit((unsigned char)*p))
+ return (char *)s;
+ n = atoi(s + 4);
+ if (n >= 0 && n <= 0xff) {
+ ch[0] = (char)n;
+ return ch;
+ }
+ }
+ return (char *)s;
+}
+
+/* Return 1 if the character is present in the font; widthp gets the
+width if non-null. */
+
+int device_char_width(DeviceFont *f, int ps, const char *name, int *widthp)
+{
+ struct charinfo *p;
+
+ name = canonicalize_name(name);
+ for (p = f->char_table[hash_name(name) % CHAR_TABLE_SIZE];; p = p->next) {
+ if (!p)
+ return 0;
+ if (strcmp(p->name, name) == 0)
+ break;
+ }
+ *widthp = scale_round(p->width, ps, f->dev->unitwidth);
+ return 1;
+}
+
+int device_code_width(DeviceFont *f, int ps, int code, int *widthp)
+{
+ struct charinfo *p;
+
+ for (p = f->code_table[code & 0xff];; p = p->code_next) {
+ if (!p)
+ return 0;
+ if (p->code == code)
+ break;
+ }
+ *widthp = scale_round(p->width, ps, f->dev->unitwidth);
+ return 1;
+}
+
+char *device_name_for_code(DeviceFont *f, int code)
+{
+ static struct charinfo *state = 0;
+ if (f)
+ state = f->code_table[code & 0xff];
+ for (; state; state = state->code_next)
+ if (state->code == code && state->name[0] != '\0') {
+ char *name = state->name;
+ state = state->code_next;
+ return name;
+ }
+ return 0;
+}
+
+int device_font_special(DeviceFont *f)
+{
+ return f->special;
+}
+
+static
+struct charinfo *add_char(DeviceFont *f, const char *name, int width, int code)
+{
+ struct charinfo **pp;
+ struct charinfo *ci;
+
+ name = canonicalize_name(name);
+ if (strcmp(name, "---") == 0)
+ name = "";
+
+ ci = (struct charinfo *)XtMalloc(XtOffsetOf(struct charinfo, name[0])
+ + strlen(name) + 1);
+
+ strcpy(ci->name, name);
+ ci->width = width;
+ ci->code = code;
+
+ if (*name != '\0') {
+ pp = &f->char_table[hash_name(name) % CHAR_TABLE_SIZE];
+ ci->next = *pp;
+ *pp = ci;
+ }
+ pp = &f->code_table[code & 0xff];
+ ci->code_next = *pp;
+ *pp = ci;
+ return ci;
+}
+
+/* Return non-zero for success. */
+
+static
+int read_charset_section(DeviceFont *f, FILE *fp)
+{
+ struct charinfo *last_charinfo = 0;
+ char buf[256];
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *name;
+ int width;
+ int code;
+ char *p;
+
+ current_lineno++;
+ name = strtok(buf, WS);
+ if (!name)
+ continue; /* ignore blank lines */
+ p = strtok((char *)0, WS);
+ if (!p) /* end of charset section */
+ break;
+ if (strcmp(p, "\"") == 0) {
+ if (!last_charinfo) {
+ error("first line of charset section cannot use '\"'");
+ return 0;
+ }
+ else
+ (void)add_char(f, name,
+ last_charinfo->width, last_charinfo->code);
+ }
+ else {
+ char *q;
+ if (sscanf(p, "%d", &width) != 1) {
+ error("bad width field");
+ return 0;
+ }
+ p = strtok((char *)0, WS);
+ if (!p) {
+ error("missing type field");
+ return 0;
+ }
+ p = strtok((char *)0, WS);
+ if (!p) {
+ error("missing code field");
+ return 0;
+ }
+ code = (int)strtol(p, &q, 0);
+ if (q == p) {
+ error("bad code field");
+ return 0;
+ }
+ last_charinfo = add_char(f, name, width, code);
+ }
+ }
+ return 1;
+}
+
+static
+FILE *find_file(const char *file, char **result)
+{
+ char *buf = NULL;
+ int bufsiz = 0;
+ int flen;
+ FILE *fp;
+ char *path;
+ char *env;
+
+ env = getenv(FONTPATH_ENV_VAR);
+ path = XtMalloc(((env && *env) ? strlen(env) + 1 : 0)
+ + strlen(FONTPATH) + 1);
+ *path = '\0';
+ if (env && *env) {
+ strcat(path, env);
+ strcat(path, ":");
+ }
+ strcat(path, FONTPATH);
+
+ *result = NULL;
+
+ if (file == NULL)
+ return NULL;
+ if (*file == '\0')
+ return NULL;
+
+ if (*file == '/') {
+ fp = fopen(file, "r");
+ if (fp)
+ *result = XtNewString(file);
+ return fp;
+ }
+
+ flen = strlen(file);
+
+ while (*path) {
+ int len;
+ char *start, *end;
+
+ start = path;
+ end = strchr(path, ':');
+ if (end)
+ path = end + 1;
+ else
+ path = end = strchr(path, '\0');
+ if (start >= end)
+ continue;
+ if (end[-1] == '/')
+ --end;
+ len = (end - start) + 1 + flen + 1;
+ if (len > bufsiz) {
+ if (buf)
+ buf = XtRealloc(buf, len);
+ else
+ buf = XtMalloc(len);
+ bufsiz = len;
+ }
+ memcpy(buf, start, end - start);
+ buf[end - start] = '/';
+ strcpy(buf + (end - start) + 1, file);
+ fp = fopen(buf, "r");
+ if (fp) {
+ *result = buf;
+ return fp;
+ }
+ }
+ XtFree(buf);
+ return NULL;
+}
+
+static
+FILE *open_device_file(const char *device_name, const char *file_name,
+ char **result)
+{
+ char *buf;
+ FILE *fp;
+
+ buf = XtMalloc(3 + strlen(device_name) + 1 + strlen(file_name) + 1);
+ sprintf(buf, "dev%s/%s", device_name, file_name);
+ fp = find_file(buf, result);
+ if (!fp) {
+ fprintf(stderr, "can't find device file '%s'\n", file_name);
+ fflush(stderr);
+ }
+ XtFree(buf);
+ return fp;
+}
+
+static
+void error(const char *s)
+{
+ if (current_filename) {
+ fprintf(stderr, "%s:", current_filename);
+ if (current_lineno > 0)
+ fprintf(stderr, "%d:", current_lineno);
+ putc(' ', stderr);
+ }
+ fputs(s, stderr);
+ putc('\n', stderr);
+ fflush(stderr);
+}
+
+/*
+Local Variables:
+c-indent-level: 4
+c-continued-statement-offset: 4
+c-brace-offset: -4
+c-argdecl-indent: 4
+c-label-offset: -4
+c-tab-always-indent: nil
+End:
+*/
diff --git a/src/devices/xditview/device.h b/src/devices/xditview/device.h
new file mode 100644
index 0000000..6f2944b
--- /dev/null
+++ b/src/devices/xditview/device.h
@@ -0,0 +1,21 @@
+
+typedef struct _DeviceFont DeviceFont;
+
+typedef struct _Device {
+ char *name;
+ int sizescale;
+ int res;
+ int unitwidth;
+ int paperlength;
+ int paperwidth;
+ int X11;
+ DeviceFont *fonts;
+} Device;
+
+void device_destroy(Device *);
+Device *device_load(const char *);
+DeviceFont *device_find_font(Device *, const char *);
+int device_char_width(DeviceFont *, int, const char *, int *);
+char *device_name_for_code(DeviceFont *, int);
+int device_code_width(DeviceFont *, int, int, int *);
+int device_font_special(DeviceFont *);
diff --git a/src/devices/xditview/draw.c b/src/devices/xditview/draw.c
new file mode 100644
index 0000000..288d98a
--- /dev/null
+++ b/src/devices/xditview/draw.c
@@ -0,0 +1,709 @@
+/*
+ * draw.c
+ *
+ * accept dvi function calls and translate to X
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+
+/* math.h on a Sequent doesn't define M_PI, apparently */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "DviP.h"
+#include "draw.h"
+#include "font.h"
+
+#define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5))
+#define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \
+ (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width)
+#define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y))
+
+/* forward reference */
+static int FakeCharacter(DviWidget, char *, int);
+
+/* shadowed by a macro definition in parse.c, and unused elsewhere */
+#if 0
+static void
+HorizontalMove(DviWidget dw, int delta)
+{
+ dw->dvi.state->x += delta;
+}
+#endif
+
+void
+HorizontalGoto(DviWidget dw, int NewPosition)
+{
+ dw->dvi.state->x = NewPosition;
+}
+
+void
+VerticalMove(DviWidget dw, int delta)
+{
+ dw->dvi.state->y += delta;
+}
+
+void
+VerticalGoto(DviWidget dw, int NewPosition)
+{
+ dw->dvi.state->y = NewPosition;
+}
+
+static void
+AdjustCacheDeltas (DviWidget dw)
+{
+ int extra;
+ int nadj;
+ int i;
+
+ nadj = 0;
+ extra = DeviceToX(dw, dw->dvi.text_device_width)
+ - dw->dvi.text_x_width;
+ if (extra == 0)
+ return;
+ for (i = 0; i <= dw->dvi.cache.index; i++)
+ if (dw->dvi.cache.adjustable[i])
+ ++nadj;
+ dw->dvi.text_x_width += extra;
+ if (nadj <= 1)
+ return;
+ for (i = 0; i <= dw->dvi.cache.index; i++)
+ if (dw->dvi.cache.adjustable[i]) {
+ int x;
+ int *deltap;
+
+ x = extra/nadj;
+ deltap = &dw->dvi.cache.cache[i].delta;
+#define MIN_DELTA 2
+ if (*deltap > 0 && x + *deltap < MIN_DELTA) {
+ x = MIN_DELTA - *deltap;
+ if (x <= 0)
+ *deltap = MIN_DELTA;
+ else
+ x = 0;
+ }
+ else
+ *deltap += x;
+ extra -= x;
+ --nadj;
+ dw->dvi.cache.adjustable[i] = 0;
+ }
+}
+
+void
+FlushCharCache (DviWidget dw)
+{
+ if (dw->dvi.cache.char_index != 0) {
+ AdjustCacheDeltas (dw);
+ XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ dw->dvi.cache.start_x, dw->dvi.cache.start_y,
+ dw->dvi.cache.cache, dw->dvi.cache.index + 1);
+ }
+ dw->dvi.cache.index = 0;
+ dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
+#if 0
+ if (dw->dvi.noPolyText)
+ dw->dvi.cache.max = 1;
+#endif
+ dw->dvi.cache.char_index = 0;
+ dw->dvi.cache.cache[0].nchars = 0;
+ dw->dvi.cache.start_x = dw->dvi.cache.x = XPos (dw);
+ dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw);
+}
+
+void
+Newline (DviWidget dw)
+{
+ FlushCharCache (dw);
+ dw->dvi.text_x_width = dw->dvi.text_device_width = 0;
+ dw->dvi.word_flag = 0;
+}
+
+void
+Word (DviWidget dw)
+{
+ dw->dvi.word_flag = 1;
+}
+
+#define charWidth(fi,c) (\
+ (fi)->per_char ?\
+ (fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
+ :\
+ (fi)->max_bounds.width\
+)
+
+
+static
+int charExists (XFontStruct *fi, int c)
+{
+ XCharStruct *p;
+
+ /* 'c' is always >= 0 */
+ if (fi->per_char == NULL
+ || (unsigned int)c < fi->min_char_or_byte2
+ || (unsigned int)c > fi->max_char_or_byte2)
+ return 0;
+ p = fi->per_char + (c - fi->min_char_or_byte2);
+ return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
+ || p->ascent != 0 || p->descent != 0 || p->attributes != 0);
+}
+
+/* 'wid' is in device units */
+static void
+DoCharacter (DviWidget dw, int c, int wid)
+{
+ register XFontStruct *font;
+ register XTextItem *text;
+ int x, y;
+
+ x = XPos(dw);
+ y = YPos(dw);
+
+ /*
+ * quick and dirty extents calculation:
+ */
+ if (!(y + 24 >= dw->dvi.extents.y1
+ && y - 24 <= dw->dvi.extents.y2
+#if 0
+ && x + 24 >= dw->dvi.extents.x1
+ && x - 24 <= dw->dvi.extents.x2
+#endif
+ ))
+ return;
+
+ if (y != dw->dvi.cache.y
+ || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) {
+ FlushCharCache (dw);
+ x = dw->dvi.cache.x;
+ dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
+ }
+ /*
+ * load a new font, if the current block is not empty,
+ * step to the next.
+ */
+ if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
+ dw->dvi.cache.font_number != dw->dvi.state->font_number)
+ {
+ FlushCharCache (dw);
+ x = dw->dvi.cache.x;
+ dw->dvi.cache.font_size = dw->dvi.state->font_size;
+ dw->dvi.cache.font_number = dw->dvi.state->font_number;
+ dw->dvi.cache.font = QueryFont (dw,
+ dw->dvi.cache.font_number,
+ dw->dvi.cache.font_size);
+ if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
+ ++dw->dvi.cache.index;
+ if (dw->dvi.cache.index >= dw->dvi.cache.max)
+ FlushCharCache (dw);
+ dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
+ dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
+ }
+ }
+ if (x != dw->dvi.cache.x || dw->dvi.word_flag) {
+ if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
+ ++dw->dvi.cache.index;
+ if (dw->dvi.cache.index >= dw->dvi.cache.max)
+ FlushCharCache (dw);
+ dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
+ dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
+ }
+ dw->dvi.cache.adjustable[dw->dvi.cache.index]
+ = dw->dvi.word_flag;
+ dw->dvi.word_flag = 0;
+ }
+ font = dw->dvi.cache.font;
+ text = &dw->dvi.cache.cache[dw->dvi.cache.index];
+ if (text->nchars == 0) {
+ text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
+ text->delta = x - dw->dvi.cache.x;
+ if (font != dw->dvi.font) {
+ text->font = font->fid;
+ dw->dvi.font = font;
+ } else
+ text->font = None;
+ dw->dvi.cache.x += text->delta;
+ }
+ if (charExists(font, c)) {
+ int w;
+ dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
+ ++text->nchars;
+ w = charWidth(font, c);
+ dw->dvi.cache.x += w;
+ if (wid != 0) {
+ dw->dvi.text_x_width += w;
+ dw->dvi.text_device_width += wid;
+ }
+ }
+}
+
+static
+int FindCharWidth (DviWidget dw, char *buf, int *widp)
+{
+ int maxpos;
+ int i;
+
+ if (dw->dvi.device_font == 0
+ || dw->dvi.state->font_number != dw->dvi.device_font_number) {
+ dw->dvi.device_font_number = dw->dvi.state->font_number;
+ dw->dvi.device_font
+ = QueryDeviceFont (dw, dw->dvi.device_font_number);
+ }
+ if (dw->dvi.device_font
+ && device_char_width (dw->dvi.device_font,
+ dw->dvi.state->font_size, buf, widp))
+ return 1;
+
+ maxpos = MaxFontPosition (dw);
+ for (i = 1; i <= maxpos; i++) {
+ DeviceFont *f = QueryDeviceFont (dw, i);
+ if (f && device_font_special (f)
+ && device_char_width (f, dw->dvi.state->font_size,
+ buf, widp)) {
+ dw->dvi.state->font_number = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Return the width of the character in device units. */
+
+int
+PutCharacter (DviWidget dw, char *buf)
+{
+ int prevFont;
+ int c = -1;
+ int wid = 0;
+ DviCharNameMap *map;
+
+ if (!dw->dvi.display_enable)
+ return 0; /* The width doesn't matter in this case. */
+ prevFont = dw->dvi.state->font_number;
+ if (!FindCharWidth (dw, buf, &wid))
+ return 0;
+ map = QueryFontMap (dw, dw->dvi.state->font_number);
+ if (map)
+ c = DviCharIndex (map, buf);
+ if (c >= 0)
+ DoCharacter (dw, c, wid);
+ else
+ (void) FakeCharacter (dw, buf, wid);
+ dw->dvi.state->font_number = prevFont;
+ return wid;
+}
+
+/* Return 1 if we can fake it; 0 otherwise. */
+
+static
+int FakeCharacter (DviWidget dw, char *buf, int wid)
+{
+ int oldx, oldw;
+ char ch[2];
+ const char *chars = 0;
+
+ if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0')
+ return 0;
+#define pack2(c1, c2) (((c1) << 8) | (c2))
+
+ switch (pack2(buf[0], buf[1])) {
+ case pack2('f', 'i'):
+ chars = "fi";
+ break;
+ case pack2('f', 'l'):
+ chars = "fl";
+ break;
+ case pack2('f', 'f'):
+ chars = "ff";
+ break;
+ case pack2('F', 'i'):
+ chars = "ffi";
+ break;
+ case pack2('F', 'l'):
+ chars = "ffl";
+ break;
+ }
+ if (!chars)
+ return 0;
+ oldx = dw->dvi.state->x;
+ oldw = dw->dvi.text_device_width;
+ ch[1] = '\0';
+ for (; *chars; chars++) {
+ ch[0] = *chars;
+ dw->dvi.state->x += PutCharacter (dw, ch);
+ }
+ dw->dvi.state->x = oldx;
+ dw->dvi.text_device_width = oldw + wid;
+ return 1;
+}
+
+void
+PutNumberedCharacter (DviWidget dw, int c)
+{
+ char *name;
+ int wid;
+ DviCharNameMap *map;
+
+ if (!dw->dvi.display_enable)
+ return;
+
+ if (dw->dvi.device_font == 0
+ || dw->dvi.state->font_number != dw->dvi.device_font_number) {
+ dw->dvi.device_font_number = dw->dvi.state->font_number;
+ dw->dvi.device_font
+ = QueryDeviceFont (dw, dw->dvi.device_font_number);
+ }
+
+ if (dw->dvi.device_font == 0
+ || !device_code_width (dw->dvi.device_font,
+ dw->dvi.state->font_size, c, &wid))
+ return;
+ if (dw->dvi.native) {
+ DoCharacter (dw, c, wid);
+ return;
+ }
+ map = QueryFontMap (dw, dw->dvi.state->font_number);
+ if (!map)
+ return;
+ for (name = device_name_for_code (dw->dvi.device_font, c);
+ name;
+ name = device_name_for_code ((DeviceFont *)0, c)) {
+ int code = DviCharIndex (map, name);
+ if (code >= 0) {
+ DoCharacter (dw, code, wid);
+ break;
+ }
+ if (FakeCharacter (dw, name, wid))
+ break;
+ }
+}
+
+/* unused */
+#if 0
+static void
+ClearPage (DviWidget dw)
+{
+ XClearWindow (XtDisplay (dw), XtWindow (dw));
+}
+#endif
+
+static void
+setGC (DviWidget dw)
+{
+ int desired_line_width;
+
+ if (dw->dvi.line_thickness < 0)
+ desired_line_width = (int)(((double)dw->dvi.device_resolution
+ * dw->dvi.state->font_size)
+ / (10.0*72.0*dw->dvi.sizescale));
+ else
+ desired_line_width = dw->dvi.line_thickness;
+
+ if (desired_line_width != dw->dvi.line_width) {
+ XGCValues values;
+ values.line_width = DeviceToX(dw, desired_line_width);
+ if (values.line_width == 0)
+ values.line_width = 1;
+ XChangeGC(XtDisplay (dw), dw->dvi.normal_GC,
+ GCLineWidth, &values);
+ dw->dvi.line_width = desired_line_width;
+ }
+}
+
+static void
+setFillGC (DviWidget dw)
+{
+ int fill_type;
+ unsigned long mask = GCFillStyle | GCForeground;
+
+ fill_type = (dw->dvi.fill * 10) / (DVI_FILL_MAX + 1);
+ if (dw->dvi.fill_type != fill_type) {
+ XGCValues values;
+ if (fill_type <= 0) {
+ values.foreground = dw->dvi.background;
+ values.fill_style = FillSolid;
+ } else if (fill_type >= 9) {
+ values.foreground = dw->dvi.foreground;
+ values.fill_style = FillSolid;
+ } else {
+ values.foreground = dw->dvi.foreground;
+ values.fill_style = FillOpaqueStippled;
+ values.stipple = dw->dvi.gray[fill_type - 1];
+ mask |= GCStipple;
+ }
+ XChangeGC(XtDisplay (dw), dw->dvi.fill_GC, mask, &values);
+ dw->dvi.fill_type = fill_type;
+ }
+}
+
+void
+DrawLine (DviWidget dw, int x, int y)
+{
+ int xp, yp;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ xp = XPos (dw);
+ yp = YPos (dw);
+ XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ xp, yp,
+ xp + DeviceToX (dw, x), yp + DeviceToX (dw, y));
+}
+
+void
+DrawCircle (DviWidget dw, int diam)
+{
+ int d;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ d = DeviceToX (dw, diam);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ XPos (dw), YPos (dw) - d/2,
+ d, d, 0, 64*360);
+}
+
+void
+DrawFilledCircle (DviWidget dw, int diam)
+{
+ int d;
+
+ AdjustCacheDeltas (dw);
+ setFillGC (dw);
+ d = DeviceToX (dw, diam);
+ XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ XPos (dw), YPos (dw) - d/2,
+ d, d, 0, 64*360);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ XPos (dw), YPos (dw) - d/2,
+ d, d, 0, 64*360);
+}
+
+void
+DrawEllipse (DviWidget dw, int a, int b)
+{
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
+ DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
+}
+
+void
+DrawFilledEllipse (DviWidget dw, int a, int b)
+{
+ AdjustCacheDeltas (dw);
+ setFillGC (dw);
+ XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
+ DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
+ DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
+}
+
+void
+DrawArc (DviWidget dw, int x_0, int y_0, int x_1, int y_1)
+{
+ int angle1, angle2;
+ int rad = (int)((sqrt ((double)x_0*x_0 + (double)y_0*y_0)
+ + sqrt ((double)x_1*x_1 + (double)y_1*y_1)
+ + 1.0)/2.0);
+ if ((x_0 == 0 && y_0 == 0) || (x_1 == 0 && y_1 == 0))
+ return;
+ angle1 = (int)(atan2 ((double)y_0, (double)-x_0)*180.0*64.0/M_PI);
+ angle2 = (int)(atan2 ((double)-y_1, (double)x_1)*180.0*64.0/M_PI);
+
+ angle2 -= angle1;
+ if (angle2 < 0)
+ angle2 += 64*360;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+
+ rad = DeviceToX (dw, rad);
+ XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ XPos (dw) + DeviceToX (dw, x_0) - rad,
+ YPos (dw) + DeviceToX (dw, y_0) - rad,
+ rad*2, rad*2, angle1, angle2);
+}
+
+void
+DrawPolygon (DviWidget dw, int *v, int n)
+{
+ XPoint *p;
+ int i;
+ int dx, dy;
+
+ n /= 2;
+
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
+ p[0].x = XPos (dw);
+ p[0].y = YPos (dw);
+ dx = 0;
+ dy = 0;
+ for (i = 0; i < n; i++) {
+ dx += v[2*i];
+ p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
+ dy += v[2*i + 1];
+ p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
+ }
+ p[n+1].x = p[0].x;
+ p[n+1].y = p[0].y;
+ XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ p, n + 2, CoordModeOrigin);
+ XtFree((char *)p);
+}
+
+void
+DrawFilledPolygon (DviWidget dw, int *v, int n)
+{
+ XPoint *p;
+ int i;
+ int dx, dy;
+
+ n /= 2;
+ if (n < 2)
+ return;
+
+ AdjustCacheDeltas (dw);
+ setFillGC (dw);
+ p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
+ p[0].x = p[n+1].x = XPos (dw);
+ p[0].y = p[n+1].y = YPos (dw);
+ dx = 0;
+ dy = 0;
+ for (i = 0; i < n; i++) {
+ dx += v[2*i];
+ p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
+ dy += v[2*i + 1];
+ p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
+ }
+ XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ p, n + 1, Complex, CoordModeOrigin);
+ XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
+ p, n + 2, CoordModeOrigin);
+ XtFree((char *)p);
+}
+
+#define POINTS_MAX 10000
+
+static void
+appendPoint(XPoint *points, int *pointi, int x, int y)
+{
+ if (*pointi < POINTS_MAX) {
+ points[*pointi].x = x;
+ points[*pointi].y = y;
+ *pointi += 1;
+ }
+}
+
+#define FLATNESS 1
+
+static void
+flattenCurve(XPoint *points, int *pointi,
+ int x_2, int y_2, int x_3, int y_3, int x_4, int y_4)
+{
+ int x_1, y_1, dx, dy, n1, n2, n;
+
+ x_1 = points[*pointi - 1].x;
+ y_1 = points[*pointi - 1].y;
+
+ dx = x_4 - x_1;
+ dy = y_4 - y_1;
+
+ n1 = dy*(x_2 - x_1) - dx*(y_2 - y_1);
+ n2 = dy*(x_3 - x_1) - dx*(y_3 - y_1);
+ if (n1 < 0)
+ n1 = -n1;
+ if (n2 < 0)
+ n2 = -n2;
+ n = n1 > n2 ? n1 : n2;
+
+ if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS)
+ appendPoint (points, pointi, x_4, y_4);
+ else {
+ flattenCurve (points, pointi,
+ (x_1 + x_2)/2,
+ (y_1 + y_2)/2,
+ (x_1 + x_2*2 + x_3)/4,
+ (y_1 + y_2*2 + y_3)/4,
+ (x_1 + 3*x_2 + 3*x_3 + x_4)/8,
+ (y_1 + 3*y_2 + 3*y_3 + y_4)/8);
+ flattenCurve (points, pointi,
+ (x_2 + x_3*2 + x_4)/4,
+ (y_2 + y_3*2 + y_4)/4,
+ (x_3 + x_4)/2,
+ (y_3 + y_4)/2,
+ x_4,
+ y_4);
+ }
+}
+
+void
+DrawSpline (DviWidget dw, int *v, int n)
+{
+ int sx, sy, tx, ty;
+ int ox, oy, dx, dy;
+ int i;
+ int pointi;
+ XPoint points[POINTS_MAX];
+
+ if (n == 0 || (n & 1) != 0)
+ return;
+ AdjustCacheDeltas (dw);
+ setGC (dw);
+ ox = XPos (dw);
+ oy = YPos (dw);
+ dx = v[0];
+ dy = v[1];
+ sx = ox;
+ sy = oy;
+ tx = sx + DeviceToX (dw, dx);
+ ty = sy + DeviceToX (dw, dy);
+
+ pointi = 0;
+
+ appendPoint (points, &pointi, sx, sy);
+ appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2);
+
+ for (i = 2; i < n; i += 2) {
+ int ux = ox + DeviceToX (dw, dx += v[i]);
+ int uy = oy + DeviceToX (dw, dy += v[i+1]);
+ flattenCurve (points, &pointi,
+ (sx + tx*5)/6, (sy + ty*5)/6,
+ (tx*5 + ux)/6, (ty*5 + uy)/6,
+ (tx + ux)/2, (ty + uy)/2);
+ sx = tx;
+ sy = ty;
+ tx = ux;
+ ty = uy;
+ }
+
+ appendPoint (points, &pointi, tx, ty);
+
+ XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
+ points, pointi, CoordModeOrigin);
+}
+
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/src/devices/xditview/draw.h b/src/devices/xditview/draw.h
new file mode 100644
index 0000000..7a3772c
--- /dev/null
+++ b/src/devices/xditview/draw.h
@@ -0,0 +1,18 @@
+void HorizontalGoto(DviWidget, int);
+void VerticalGoto(DviWidget, int);
+void VerticalMove(DviWidget, int);
+void FlushCharCache(DviWidget);
+void Newline(DviWidget);
+void Word(DviWidget);
+int PutCharacter(DviWidget, char *);
+void PutNumberedCharacter(DviWidget, int);
+void DrawLine(DviWidget, int, int);
+void DrawCircle(DviWidget, int);
+void DrawFilledCircle(DviWidget, int);
+void DrawEllipse(DviWidget, int, int);
+void DrawFilledEllipse(DviWidget, int, int);
+void DrawArc(DviWidget, int, int, int, int);
+void DrawPolygon(DviWidget, int *, int);
+void DrawFilledPolygon(DviWidget, int *, int);
+void DrawSpline(DviWidget, int *, int);
+
diff --git a/src/devices/xditview/font.c b/src/devices/xditview/font.c
new file mode 100644
index 0000000..8462608
--- /dev/null
+++ b/src/devices/xditview/font.c
@@ -0,0 +1,446 @@
+/*
+ * font.c
+ *
+ * map dvi fonts to X fonts
+ */
+
+#include <config.h>
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "DviP.h"
+#include "XFontName.h"
+#include "font.h"
+
+/* forward reference */
+static void DisposeFontSizes(DviWidget, DviFontSizeList *);
+
+static char *
+savestr (const char *s)
+{
+ char *n;
+
+ if (!s)
+ return 0;
+ n = XtMalloc (strlen (s) + 1);
+ if (n)
+ strcpy (n, s);
+ return n;
+}
+
+static DviFontList *
+LookupFontByPosition (DviWidget dw, int position)
+{
+ DviFontList *f;
+
+ for (f = dw->dvi.fonts; f; f = f->next)
+ if (f->dvi_number == position)
+ break;
+ return f;
+}
+
+int
+MaxFontPosition (DviWidget dw)
+{
+ DviFontList *f;
+ int n = -1;
+
+ for (f = dw->dvi.fonts; f; f = f->next)
+ if (f->dvi_number > n)
+ n = f->dvi_number;
+ return n;
+}
+
+static DviFontSizeList *
+LookupFontSizeBySize (DviWidget dw, DviFontList *f, int size)
+{
+ DviFontSizeList *fs, *best = 0, *smallest = 0;
+ int bestsize = 0;
+ XFontName fontName;
+ unsigned int fontNameAttributes;
+ char fontNameString[2048];
+ int decipointsize;
+
+ if (f->scalable) {
+ decipointsize = (10*size)/dw->dvi.sizescale;
+ for (best = f->sizes; best; best = best->next)
+ if (best->size == decipointsize)
+ return best;
+ best = (DviFontSizeList *) XtMalloc(sizeof *best);
+ best->next = f->sizes;
+ best->size = decipointsize;
+ f->sizes = best;
+ XParseFontName (f->x_name, &fontName, &fontNameAttributes);
+ fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
+ fontNameAttributes |= FontNameResolutionX;
+ fontNameAttributes |= FontNameResolutionY;
+ fontNameAttributes |= FontNamePointSize;
+ fontName.ResolutionX = dw->dvi.display_resolution;
+ fontName.ResolutionY = dw->dvi.display_resolution;
+ fontName.PointSize = decipointsize;
+ XFormatFontName (&fontName, fontNameAttributes, fontNameString);
+ best->x_name = savestr (fontNameString);
+ best->doesnt_exist = 0;
+ best->font = 0;
+ return best;
+ }
+ for (fs = f->sizes; fs; fs=fs->next) {
+ if (dw->dvi.sizescale*fs->size <= 10*size
+ && fs->size >= bestsize) {
+ best = fs;
+ bestsize = fs->size;
+ }
+ if (smallest == 0 || fs->size < smallest->size)
+ smallest = fs;
+ }
+ return best ? best : smallest;
+}
+
+static char *
+SkipFontNameElement (char *n)
+{
+ while (*n != '-')
+ if (!*++n)
+ return 0;
+ return n+1;
+}
+
+# define SizePosition 8
+# define EncodingPosition 13
+
+static int
+ConvertFontNameToSize (char *n)
+{
+ int i, size;
+
+ for (i = 0; i < SizePosition; i++) {
+ n = SkipFontNameElement (n);
+ if (!n)
+ return -1;
+ }
+ size = atoi (n);
+ return size;
+}
+
+static char *
+ConvertFontNameToEncoding (char *n)
+{
+ int i;
+ for (i = 0; i < EncodingPosition; i++) {
+ n = SkipFontNameElement (n);
+ if (!n)
+ return 0;
+ }
+ return n;
+}
+
+static DviFontSizeList *
+InstallFontSizes (DviWidget dw, const char *x_name, Boolean *scalablep)
+{
+ char fontNameString[2048];
+ char **fonts;
+ int i, count;
+ int size;
+ DviFontSizeList *sizes, *new_size;
+ XFontName fontName;
+ unsigned int fontNameAttributes;
+
+ *scalablep = FALSE;
+ if (!XParseFontName ((XFontNameString)x_name, &fontName,
+ &fontNameAttributes))
+ return 0;
+ fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize
+ |FontNameAverageWidth);
+ fontNameAttributes |= FontNameResolutionX;
+ fontNameAttributes |= FontNameResolutionY;
+ fontName.ResolutionX = dw->dvi.display_resolution;
+ fontName.ResolutionY = dw->dvi.display_resolution;
+ XFormatFontName (&fontName, fontNameAttributes, fontNameString);
+ fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
+ sizes = 0;
+ for (i = 0; i < count; i++) {
+ size = ConvertFontNameToSize (fonts[i]);
+ if (size == 0) {
+ DisposeFontSizes (dw, sizes);
+ sizes = 0;
+ *scalablep = TRUE;
+ break;
+ }
+ if (size != -1) {
+ new_size = (DviFontSizeList *) XtMalloc (sizeof *new_size);
+ new_size->next = sizes;
+ new_size->size = size;
+ new_size->x_name = savestr (fonts[i]);
+ new_size->doesnt_exist = 0;
+ new_size->font = 0;
+ sizes = new_size;
+ }
+ }
+ XFreeFontNames (fonts);
+ return sizes;
+}
+
+static void
+DisposeFontSizes (DviWidget dw, DviFontSizeList *fs)
+{
+ DviFontSizeList *next;
+
+ for (; fs; fs=next) {
+ next = fs->next;
+ if (fs->x_name)
+ XtFree (fs->x_name);
+ if (fs->font && fs->font != dw->dvi.default_font) {
+ XUnloadFont (XtDisplay (dw), fs->font->fid);
+ XFree ((char *)fs->font);
+ }
+ XtFree ((char *) fs);
+ }
+}
+
+static DviFontList *
+InstallFont (DviWidget dw, int position,
+ const char *dvi_name, const char *x_name)
+{
+ DviFontList *f;
+ char *encoding;
+
+ if ((f = LookupFontByPosition (dw, position)) != NULL) {
+ /*
+ * ignore gratuitous font loading
+ */
+ if (!strcmp (f->dvi_name, dvi_name) &&
+ !strcmp (f->x_name, x_name))
+ return f;
+
+ DisposeFontSizes (dw, f->sizes);
+ if (f->dvi_name)
+ XtFree (f->dvi_name);
+ if (f->x_name)
+ XtFree (f->x_name);
+ f->device_font = 0;
+ } else {
+ f = (DviFontList *) XtMalloc (sizeof (*f));
+ f->next = dw->dvi.fonts;
+ dw->dvi.fonts = f;
+ }
+ f->initialized = FALSE;
+ f->dvi_name = savestr (dvi_name);
+ f->device_font = device_find_font (dw->dvi.device, dvi_name);
+ f->x_name = savestr (x_name);
+ f->dvi_number = position;
+ f->sizes = 0;
+ f->scalable = FALSE;
+ if (f->x_name) {
+ encoding = ConvertFontNameToEncoding (f->x_name);
+ f->char_map = DviFindMap (encoding);
+ } else
+ f->char_map = 0;
+ /*
+ * force requery of fonts
+ */
+ dw->dvi.font = 0;
+ dw->dvi.font_number = -1;
+ dw->dvi.cache.font = 0;
+ dw->dvi.cache.font_number = -1;
+ dw->dvi.device_font = 0;
+ dw->dvi.device_font_number = -1;
+ return f;
+}
+
+void
+ForgetFonts (DviWidget dw)
+{
+ DviFontList *f = dw->dvi.fonts;
+
+ while (f) {
+ DviFontList *tem = f;
+
+ if (f->sizes)
+ DisposeFontSizes (dw, f->sizes);
+ if (f->dvi_name)
+ XtFree (f->dvi_name);
+ if (f->x_name)
+ XtFree (f->x_name);
+ f = f->next;
+ XtFree ((char *) tem);
+ }
+
+ /*
+ * force requery of fonts
+ */
+ dw->dvi.font = 0;
+ dw->dvi.font_number = -1;
+ dw->dvi.cache.font = 0;
+ dw->dvi.cache.font_number = -1;
+ dw->dvi.device_font = 0;
+ dw->dvi.device_font_number = -1;
+ dw->dvi.fonts = 0;
+}
+
+
+static char *
+MapDviNameToXName (DviWidget dw, const char *dvi_name)
+{
+ DviFontMap *fm;
+
+ for (fm = dw->dvi.font_map; fm; fm=fm->next)
+ if (!strcmp (fm->dvi_name, dvi_name))
+ return fm->x_name;
+ return 0;
+}
+
+#if 0
+static char *
+MapXNameToDviName (DviWidget dw, const char *x_name)
+{
+ DviFontMap *fm;
+
+ for (fm = dw->dvi.font_map; fm; fm=fm->next)
+ if (!strcmp (fm->x_name, x_name))
+ return fm->dvi_name;
+ return 0;
+}
+#endif
+
+void
+ParseFontMap (DviWidget dw)
+{
+ char dvi_name[1024];
+ char x_name[2048];
+ char *m, *s;
+ DviFontMap *fm, *new_map;
+
+ if (dw->dvi.font_map)
+ DestroyFontMap (dw->dvi.font_map);
+ fm = 0;
+ m = dw->dvi.font_map_string;
+ while (*m) {
+ s = m;
+ while (*m && !isspace (*m))
+ ++m;
+ strncpy (dvi_name, s, m-s);
+ dvi_name[m-s] = '\0';
+ while (isspace (*m))
+ ++m;
+ s = m;
+ while (*m && *m != '\n')
+ ++m;
+ strncpy (x_name, s, m-s);
+ x_name[m-s] = '\0';
+ new_map = (DviFontMap *) XtMalloc (sizeof *new_map);
+ new_map->x_name = savestr (x_name);
+ new_map->dvi_name = savestr (dvi_name);
+ new_map->next = fm;
+ fm = new_map;
+ ++m;
+ }
+ dw->dvi.font_map = fm;
+}
+
+void
+DestroyFontMap (DviFontMap *font_map)
+{
+ DviFontMap *next;
+
+ for (; font_map; font_map = next) {
+ next = font_map->next;
+ if (font_map->x_name)
+ XtFree (font_map->x_name);
+ if (font_map->dvi_name)
+ XtFree (font_map->dvi_name);
+ XtFree ((char *) font_map);
+ }
+}
+
+/* ARGSUSED */
+
+void
+SetFontPosition (DviWidget dw, int position,
+ const char *dvi_name, const char *extra)
+{
+ char *x_name;
+
+ x_name = MapDviNameToXName (dw, dvi_name);
+ if (x_name)
+ (void) InstallFont (dw, position, dvi_name, x_name);
+
+ extra = extra; /* unused; suppress compiler warning */
+}
+
+XFontStruct *
+QueryFont (DviWidget dw, int position, int size)
+{
+ DviFontList *f;
+ DviFontSizeList *fs;
+
+ f = LookupFontByPosition (dw, position);
+ if (!f)
+ return dw->dvi.default_font;
+ if (!f->initialized) {
+ f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
+ f->initialized = TRUE;
+ }
+ fs = LookupFontSizeBySize (dw, f, size);
+ if (!fs)
+ return dw->dvi.default_font;
+ if (!fs->font) {
+ if (fs->x_name)
+ fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
+ if (!fs->font)
+ fs->font = dw->dvi.default_font;
+ }
+ return fs->font;
+}
+
+DeviceFont *
+QueryDeviceFont (DviWidget dw, int position)
+{
+ DviFontList *f;
+
+ f = LookupFontByPosition (dw, position);
+ if (!f)
+ return 0;
+ return f->device_font;
+}
+
+DviCharNameMap *
+QueryFontMap (DviWidget dw, int position)
+{
+ DviFontList *f;
+
+ f = LookupFontByPosition (dw, position);
+ if (f)
+ return f->char_map;
+ else
+ return 0;
+}
+
+#if 0
+LoadFont (DviWidget dw, int position, int size)
+{
+ XFontStruct *font;
+
+ font = QueryFont (dw, position, size);
+ dw->dvi.font_number = position;
+ dw->dvi.font_size = size;
+ dw->dvi.font = font;
+ XSetFont (XtDisplay (dw), dw->dvi.normal_GC, font->fid);
+ return;
+}
+#endif
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/src/devices/xditview/font.h b/src/devices/xditview/font.h
new file mode 100644
index 0000000..ae6c765
--- /dev/null
+++ b/src/devices/xditview/font.h
@@ -0,0 +1,6 @@
+void DestroyFontMap(DviFontMap *);
+void ForgetFonts (DviWidget dw);
+int MaxFontPosition (DviWidget dw);
+void ParseFontMap (DviWidget dw);
+void SetFontPosition (DviWidget dw, int position, const char *dvi_name,
+ const char *extra);
diff --git a/src/devices/xditview/gray1.bm b/src/devices/xditview/gray1.bm
new file mode 100644
index 0000000..c40a95e
--- /dev/null
+++ b/src/devices/xditview/gray1.bm
@@ -0,0 +1,4 @@
+#define gray1_width 3
+#define gray1_height 3
+static char gray1_bits[] = {
+ 0x00, 0x02, 0x00};
diff --git a/src/devices/xditview/gray2.bm b/src/devices/xditview/gray2.bm
new file mode 100644
index 0000000..e87a1bc
--- /dev/null
+++ b/src/devices/xditview/gray2.bm
@@ -0,0 +1,4 @@
+#define gray2_width 3
+#define gray2_height 3
+static char gray2_bits[] = {
+ 0x00, 0x03, 0x00};
diff --git a/src/devices/xditview/gray3.bm b/src/devices/xditview/gray3.bm
new file mode 100644
index 0000000..d9313eb
--- /dev/null
+++ b/src/devices/xditview/gray3.bm
@@ -0,0 +1,4 @@
+#define gray3_width 3
+#define gray3_height 3
+static char gray3_bits[] = {
+ 0x00, 0x03, 0x02};
diff --git a/src/devices/xditview/gray4.bm b/src/devices/xditview/gray4.bm
new file mode 100644
index 0000000..dad142a
--- /dev/null
+++ b/src/devices/xditview/gray4.bm
@@ -0,0 +1,4 @@
+#define gray4_width 3
+#define gray4_height 3
+static char gray4_bits[] = {
+ 0x00, 0x07, 0x02};
diff --git a/src/devices/xditview/gray5.bm b/src/devices/xditview/gray5.bm
new file mode 100644
index 0000000..5f57618
--- /dev/null
+++ b/src/devices/xditview/gray5.bm
@@ -0,0 +1,4 @@
+#define gray5_width 3
+#define gray5_height 3
+static char gray5_bits[] = {
+ 0x04, 0x07, 0x02};
diff --git a/src/devices/xditview/gray6.bm b/src/devices/xditview/gray6.bm
new file mode 100644
index 0000000..b76701d
--- /dev/null
+++ b/src/devices/xditview/gray6.bm
@@ -0,0 +1,4 @@
+#define gray6_width 3
+#define gray6_height 3
+static char gray6_bits[] = {
+ 0x04, 0x07, 0x03};
diff --git a/src/devices/xditview/gray7.bm b/src/devices/xditview/gray7.bm
new file mode 100644
index 0000000..ef47bc6
--- /dev/null
+++ b/src/devices/xditview/gray7.bm
@@ -0,0 +1,4 @@
+#define gray7_width 3
+#define gray7_height 3
+static char gray7_bits[] = {
+ 0x05, 0x07, 0x03};
diff --git a/src/devices/xditview/gray8.bm b/src/devices/xditview/gray8.bm
new file mode 100644
index 0000000..12de7cb
--- /dev/null
+++ b/src/devices/xditview/gray8.bm
@@ -0,0 +1,4 @@
+#define gray8_width 3
+#define gray8_height 3
+static char gray8_bits[] = {
+ 0x05, 0x07, 0x07};
diff --git a/src/devices/xditview/gxditview.1.man b/src/devices/xditview/gxditview.1.man
new file mode 100644
index 0000000..920ccfd
--- /dev/null
+++ b/src/devices/xditview/gxditview.1.man
@@ -0,0 +1,815 @@
+.TH gxditview @MAN1EXT@ "@MDATE@" "groff @VERSION@"
+.SH Name
+gxditview \- display
+.I groff
+intermediate output files in X11
+.
+.
+.\" ====================================================================
+.\" Legal Terms
+.\" ====================================================================
+.\"
+.\" Copyright 1991 Massachusetts Institute of Technology
+.\"
+.\" 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, and that the name of M.I.T. not be used in
+.\" advertising or publicity pertaining to distribution of the software
+.\" without specific, written prior permission. M.I.T. makes no
+.\" representations about the suitability of this software for any
+.\" purpose. It is provided "as is" without express or implied
+.\" warranty.
+.\"
+.\" M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+.\" NO EVENT SHALL M.I.T. 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.
+.
+.
+.\" Save and disable compatibility mode (for, e.g., Solaris 10/11).
+.do nr *groff_gxditview_1_man_C \n[.cp]
+.cp 0
+.
+.\" Define fallback for groff 1.23's MR macro if the system lacks it.
+.nr do-fallback 0
+.if !\n(.f .nr do-fallback 1 \" mandoc
+.if \n(.g .if !d MR .nr do-fallback 1 \" older groff
+.if !\n(.g .nr do-fallback 1 \" non-groff *roff
+.if \n[do-fallback] \{\
+. de MR
+. ie \\n(.$=1 \
+. I \%\\$1
+. el \
+. IR \%\\$1 (\\$2)\\$3
+. .
+.\}
+.rr do-fallback
+.
+.
+.\" ====================================================================
+.SH Synopsis
+.\" ====================================================================
+.
+.SY gxditview
+.RI [ X-toolkit-option \~.\|.\|.\&]
+.RB [ \-backingStore\~\c
+.IR backing-store-type ]
+.RB [ \-filename\~\c
+.IR file ]
+.\" While recognized, the relevant logic is "#if 0"ed out in draw.c.
+.\" .RB [ \-noPolyText ]
+.RB [ \-page\~\c
+.IR page-number ]
+.RB [ \-printCommand\~\c
+.IR command ]
+.RB [ \-resolution\~\c
+.IR resolution ]
+.I file
+.YS
+.
+.
+.SY gxditview
+.B \-help
+.
+.SY gxditview
+.B \-\-help
+.YS
+.
+.
+.SY gxditview
+.B \-version
+.
+.SY gxditview
+.B \-\-version
+.YS
+.
+.
+.\" ====================================================================
+.SH Description
+.\" ====================================================================
+.
+.I gxditview
+interprets and displays the intermediate output format of
+.MR groff @MAN1EXT@
+on an X11\~display.
+.
+It uses the standard X11 fonts,
+so it does not require access to the server machine for font loading.
+.
+There are several ways to use
+.IR gxditview .
+.
+.
+.PP
+The
+intermediate output format of
+.IR groff ,
+documented in
+.MR groff_out @MAN5EXT@ ,
+is produced by
+.I @g@troff
+or the
+.B \-Z
+option to
+.IR groff .
+.
+.
+It can be viewed by explicitly calling
+.RB \[lq] gxditview
+.IR file \[rq].
+.
+If the
+.I file
+operand is
+.RB \[lq] \- \[rq],
+.I gxditview
+will read the standard input stream;
+.I file
+cannot be omitted.
+.
+The intermediate output format of
+.I groff
+is device-independent but not device-agnostic.
+.
+.I gxditview
+can view it for all typesetter devices,
+but the quality is device-dependent.
+.
+.I gxditview
+will not display output for terminal
+.RI ( nroff )
+devices.
+.
+.
+.PP
+The best results are achieved with the
+.BR X *
+devices for
+.IR groff 's
+.B \-T
+option,
+of which there are four:
+.BR \-TX75 ,
+.BR \-TX75\-12 ,
+.BR \-TX100 ,
+and
+.BR \-TX100\-12 .
+.
+They differ by the X\~resolution
+(75 or 100 dots per inch)
+and the base point size
+(10 or 12 points).
+.
+They are especially built for
+.IR gxditview .
+.
+When using one of these,
+.I groff
+generates the intermediate output for this device and calls
+.I gxditview
+automatically for viewing.
+.
+.
+.P
+.B \-X
+produces good results only with
+.BR \-Tps ,
+.BR \-TX75 ,
+.BR \-TX75\-12 ,
+.BR \-TX100 ,
+and
+.BR \-TX100\-12 .
+.
+The default resolution for previewing
+.B \-Tps
+output is 75\|dpi;
+this can be changed with the
+.B \-resolution
+option.
+.
+.
+.PP
+While
+.I gxditview
+is running,
+the left mouse button brings up a menu with several entries.
+.
+.
+.TP 13n
+.B Next Page
+Display the next page.
+.
+.
+.TP
+.B Previous Page
+Display the previous page.
+.
+.
+.TP
+.B Select Page
+Select a particular numbered page specified by a dialog box.
+.
+.
+.TP
+.B Print
+Print the
+.I groff
+intermediate output using a command specified by a dialog box.
+.
+The default command initially displayed is controlled by the
+.B printCommand
+application resource,
+and by the
+.B \-printCommand
+option.
+.
+.
+.TP
+.B Open
+Open for display a new file specified by a dialog box.
+.
+The file should contain
+.I groff
+intermediate output.
+.
+If the filename starts with a bar or pipe symbol,
+.RB \[lq] | \[rq]
+it will be interpreted as a command from which to read.
+.
+.
+.TP
+.B Quit
+Exit from
+.BR gxditview .
+.
+.
+.PP
+The menu entries correspond to actions with similar but not identical
+names,
+which can also be accessed with keyboard accelerators.
+.
+The
+.IR n ,
+.IR Space ,
+.IR Return ,
+and
+.I Next
+.RI ( PgDn )
+keys are bound to the
+.B NextPage
+action.
+.
+The
+.IR p ,
+.IR b ,
+.IR BackSpace ,
+.IR Delete ,
+and
+.I Prior
+.RI ( PgUp )
+keys are bound to the
+.B PreviousPage
+action.
+.
+The
+.I g
+key is bound to the
+.B SelectPage
+action.
+.
+The
+.I o
+key is bound to the
+.B OpenFile
+action.
+.
+The
+.I q
+key is bound to the
+.B Quit
+action.
+.
+The
+.I r
+key is bound to a
+.B Rerasterize
+action which rereads the current file,
+and redisplays the current page;
+if the current file is a command,
+the command will be re-executed.
+.
+Vertical scrolling can be done with the
+.I k
+and
+.I j
+keys;
+horizontal scrolling is bound to the
+.I h
+and
+.I l
+keys.
+.
+The arrow keys
+.RI ( up ,
+.IR down ,
+.IR left ,
+and
+.IR right )
+are also bound to the obvious scrolling actions.
+.
+.
+.PP
+The
+.B paperlength
+and
+.B paperwidth
+commands in the
+.I DESC
+file describing a
+.I groff
+output device specify the length and width in machine units of the
+virtual page displayed by
+.IR gxditview ;
+see
+.MR groff_font @MAN5EXT@ .
+.
+.
+.\" ====================================================================
+.SS "X defaults"
+.\" ====================================================================
+.
+This program uses the
+.I Dvi
+widget from the X\~Toolkit.
+.
+It understands all of the core resource names and classes as well as:
+.
+.
+.TP
+.BR width\~ (class\~ Width )
+Specifies the width of the window.
+.
+.
+.TP
+.BR height\~ (class\~ Height )
+Specifies the height of the window.
+.
+.
+.TP
+.BR foreground\~ (class\~ Foreground )
+Specifies the default foreground color.
+.
+.
+.TP
+.BR font\~ (class\~ Font )
+Specifies the font to be used for error messages.
+.
+.
+.TP
+.BR fontMap\~ (class\~ FontMap )
+Specifies the mapping from
+.I groff
+font names to X\~font names.
+.
+This must be a string containing a sequence of lines.
+.
+Each line contains two whitespace-separated fields:
+firstly the
+.I groff
+font name,
+and secondly the XLFD
+(X Logical Font Description).
+.
+The default is shown in subsection \[lq]Default font map\[rq] below.
+.
+.
+.\" ====================================================================
+.SS "Default font map"
+.\" ====================================================================
+.
+XLFDs are long and unwieldy,
+so some lines are shown broken and indented below.
+.\" Break them after the POINT_SIZE field (in "decipoints", so "100").
+.
+.
+.PP
+.EX
+TR \-adobe\-times\-medium\-r\-normal\-\-*\-100\
+\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+TI \-adobe\-times\-medium\-i\-normal\-\-*\-100\
+\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+TB \-adobe\-times\-bold\-r\-normal\-\-*\-100\
+\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+TBI \-adobe\-times\-bold\-i\-normal\
+\-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+CR \-adobe\-courier\-medium\-r\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+CI \-adobe\-courier\-medium\-o\-normal\" break
+ \-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+CB \-adobe\-courier\-bold\-r\-normal\
+\-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+CBI \-adobe\-courier\-bold\-o\-normal\
+\-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+HR \-adobe\-helvetica\-medium\-r\-normal\" break
+ \-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+HI \-adobe\-helvetica\-medium\-o\-normal\" break
+ \-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+HB \-adobe\-helvetica\-bold\-r\-normal\" break
+ \-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+HBI \-adobe\-helvetica\-bold\-o\-normal\" break
+ \-\-*\-100\-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+NR \-adobe\-new century schoolbook\-medium\-r\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+NI \-adobe\-new century schoolbook\-medium\-i\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+NB \-adobe\-new century schoolbook\-bold\-r\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+NBI \-adobe\-new century schoolbook\-bold\-i\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-iso8859\-1\[rs]n\[rs]
+S \-adobe\-symbol\-medium\-r\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-adobe\-fontspecific\[rs]n\[rs]
+SS \-adobe\-symbol\-medium\-r\-normal\-\-*\-100\" break
+ \-*\-*\-*\-*\-adobe\-fontspecific\[rs]n\[rs]
+.EE
+.
+.
+.br
+.ne 3v
+.\" ====================================================================
+.SH Options
+.\" ====================================================================
+.
+.B \-help
+and
+.B \-\-help
+display a usage message,
+while
+.B \-version
+and
+.B \-\-version
+show version information;
+all exit afterward.
+.
+.
+.P
+.I gxditview
+accepts all of the standard X\~Toolkit command-line options along with
+the additional options listed below.
+.
+.
+.TP
+.B \-page
+This option specifies the page number of the document to be displayed.
+.
+.
+.TP
+.BI \-backingStore\~ backing-store-type
+Because redisplay of the
+.I groff
+intermediate output window can take a perceiptible amount of time,
+this option causes the server to save the window contents so that when
+it is scrolled around the viewport,
+the window is painted from contents saved in backing store.
+.
+.I backing-store-type
+can be one of
+.BR Always ,
+.B WhenMapped
+or
+.BR NotUseful .
+.
+.
+.TP
+.BI \-printCommand\~ command
+The default command displayed in the dialog box for the
+.B Print
+menu entry will be
+.IR command .
+.
+.
+.TP
+.BI \-resolution\~ res
+The
+.I groff
+intermediate output file will be displayed at a resolution of
+.I res
+dots per inch,
+unless the
+.I DESC
+file contains the
+.B X11
+command,
+in which case the device resolution will be used.
+.
+This corresponds to the
+.I Dvi
+widget's
+.B resolution
+resource.
+.
+The default is
+.BR 75 .
+.
+.
+.TP
+.BI \-filename\~ string
+The default filename displayed in the dialog box for the
+.B Open
+menu entry will be
+.IR string .
+.
+This can be either a filename,
+or a command starting with
+.RB \[lq] | \[rq].
+.
+.
+.PP
+The following standard X\~Toolkit command-line arguments are commonly
+used with
+.IR gxditview .
+.
+.
+.TP
+.BI \-bg\~ color
+This option specifies the color to use for the background of the window.
+.
+The default is
+.RB \[lq] white \[rq].
+.
+.
+.TP
+.BI \-bd\~ color
+This option specifies the color to use for the border of the window.
+.
+The default is
+.RB \[lq] black \[rq].
+.
+.
+.TP
+.BI \-bw\~ number
+This option specifies the width in pixels of the border surrounding the
+window.
+.
+.
+.TP
+.BI \-fg\~ color
+This option specifies the color to use for displaying text.
+.
+The default is
+.RB \[lq] black \[rq].
+.
+.
+.TP
+.BI \-fn\~ font
+This option specifies the font to be used for displaying widget text.
+.
+The default is
+.RB \[lq] fixed \[rq].
+.
+.
+.TP
+.B \-rv
+This option indicates that reverse video should be simulated by swapping
+the foreground and background colors.
+.
+.
+.TP
+.BI \-geometry\~ geometry
+This option specifies the preferred size and position of the window.
+.
+.
+.TP
+.BI \-display\~ host : display
+This option specifies the X\~server to contact.
+.
+.
+.TP
+.BI \-xrm\~ resourcestring
+This option specifies a resource string to be used.
+.
+.
+.\" ====================================================================
+.SH Environment
+.\" ====================================================================
+.
+.TP
+.I GROFF_FONT_PATH
+A list of directories in which to seek the selected output device's
+directory of device and font description files.
+.
+See
+.MR @g@troff @MAN1EXT@
+and
+.MR groff_font @MAN5EXT@ .
+.
+.
+.\" ====================================================================
+.SH Files
+.\" ====================================================================
+.
+.TP
+.I @APPDEFDIR@/\:\%GXditview
+.TQ
+.I @APPDEFDIR@/\:\%GXditview\-color
+define X application defaults for
+.IR gxditview .
+.
+Users can override these values in the
+.I .Xdefaults
+file,
+normally located in the user's home directory.
+.
+See
+.MR appres 1
+and
+.MR xrdb 1 .
+.
+.
+.TP
+.I @FONTDIR@/\:\%devX100/\:DESC
+describes the
+.B X100
+output device.
+.
+.
+.TP
+.IR @FONTDIR@/\:\%devX100/ F
+describes the font known
+.RI as\~ F
+on device
+.BR X100 .
+.
+.
+.TP
+.I @FONTDIR@/\:\%devX100\-12/\:DESC
+describes the
+.B X100\-12
+output device.
+.
+.
+.TP
+.IR @FONTDIR@/\:\%devX100\-12/ F
+describes the font known
+.RI as\~ F
+on device
+.BR X100\-12 .
+.
+.
+.TP
+.I @FONTDIR@/\:\%devX75/\:DESC
+describes the
+.B X75
+output device.
+.
+.
+.TP
+.IR @FONTDIR@/\:\%devX75/ F
+describes the font known
+.RI as\~ F
+on device
+.BR X75 .
+.
+.
+.TP
+.I @FONTDIR@/\:\%devX75\-12/\:DESC
+describes the
+.B X75\-12
+output device.
+.
+.
+.TP
+.IR @FONTDIR@/\:\%devX75\-12/ F
+describes the font known
+.RI as\~ F
+on device
+.BR X75\-12 .
+.
+.
+.TP
+.I @MACRODIR@/\:X.tmac
+defines macros for use with the
+.BR X100 ,
+.BR X100\-12 ,
+.BR X75 ,
+and
+.B X75\-12
+output devices.
+.
+It is automatically loaded by
+.I troffrc
+when any of those output devices is selected.
+.
+.
+.TP
+.I @MACRODIR@/\:Xps\:.tmac
+sets up
+.I @g@troff
+to use
+.I \%gxditview
+as a previewer for device-independent output targeting the
+.B ps
+output device.
+.
+It is automatically loaded by
+.I troffrc
+when
+.I @g@troff
+is given the options
+.B \-X
+and
+.BR \-Tps .
+.
+.
+.\" ====================================================================
+.SH Examples
+.\" ====================================================================
+.
+The following command views this man page with a base point size of 12.
+.
+.
+.RS
+.P
+.EX
+groff \-TX100\-12 \-man gxditview.1
+.EE
+.RE
+.
+.
+.P
+The quality of the result depends mainly on the chosen point size and
+display resolution;
+for rapid previewing,
+however,
+something like
+.
+.RS
+.EX
+.RI "groff \-X \-P\-resolution \-P100\~" document
+.EE
+.RE
+.
+yields acceptable results.
+.
+.
+.\" ====================================================================
+.SH Authors
+.\" ====================================================================
+.
+.I gxditview
+and its predecessor
+.I xditview
+were written by
+Keith Packard (MIT X Consortium),
+Richard L.\& Hyde (Purdue),
+David Slattengren (Berkeley),
+Malcolm Slaney (Schlumberger Palo Alto Research),
+Mark Moraes (University of Toronto),
+and
+James Clark.
+.
+.
+.PP
+This program is derived from
+.IR xditview ;
+portions of
+.I xditview
+originated in
+.IR xtroff ,
+which was derived from
+.IR \%suntroff .
+.
+.
+.\" ====================================================================
+.SH "See also"
+.\" ====================================================================
+.
+.UR https://\:www\:.x\:.org/\:releases/\:X11R7.6/\:doc/\:xorg\-docs/\
+\:specs/\:XLFD/xlfd\:.html
+\[lq]X Logical Font Description Conventions\[rq]
+.UE ,
+by Jim Flowers and Stephen Gildea.
+.
+.
+.PP
+.MR X 7 ,
+.MR xrdb 1 ,
+.MR xditview 1 ,
+.MR groff @MAN1EXT@ ,
+.MR groff_out @MAN5EXT@
+.
+.
+.\" Restore compatibility mode (for, e.g., Solaris 10/11).
+.cp \n[*groff_gxditview_1_man_C]
+.do rr *groff_gxditview_1_man_C
+.
+.
+.\" Local Variables:
+.\" fill-column: 72
+.\" mode: nroff
+.\" End:
+.\" vim: set filetype=groff textwidth=72:
diff --git a/src/devices/xditview/lex.c b/src/devices/xditview/lex.c
new file mode 100644
index 0000000..19cf292
--- /dev/null
+++ b/src/devices/xditview/lex.c
@@ -0,0 +1,100 @@
+#include <config.h>
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+
+#include "DviP.h"
+#include "lex.h"
+
+int
+DviGetAndPut(DviWidget dw, int *cp)
+{
+ if (dw->dvi.ungot) {
+ dw->dvi.ungot = 0;
+ *cp = getc (dw->dvi.file);
+ }
+ else {
+ *cp = getc (dw->dvi.file);
+ if (*cp != EOF)
+ putc (*cp, dw->dvi.tmpFile);
+ }
+ return *cp;
+}
+
+char *
+GetLine(DviWidget dw, char *Buffer, int Length)
+{
+ int i = 0, c;
+
+ Length--; /* Save room for final '\0' */
+
+ while (DviGetC (dw, &c) != EOF) {
+ if (Buffer && i < Length)
+ Buffer[i++] = c;
+ if (c == '\n') {
+ DviUngetC(dw, c);
+ break;
+ }
+ }
+ if (Buffer)
+ Buffer[i] = '\0';
+ return Buffer;
+}
+
+char *
+GetWord(DviWidget dw, char *Buffer, int Length)
+{
+ int i = 0, c;
+
+ Length--; /* Save room for final '\0' */
+ while (DviGetC(dw, &c) == ' ' || c == '\n')
+ ;
+ while (c != EOF) {
+ if (Buffer && i < Length)
+ Buffer[i++] = c;
+ if (DviGetC(dw, &c) == ' ' || c == '\n') {
+ DviUngetC(dw, c);
+ break;
+ }
+ }
+ if (Buffer)
+ Buffer[i] = '\0';
+ return Buffer;
+}
+
+int
+GetNumber(DviWidget dw)
+{
+ int i = 0, c;
+ int negative = 0;
+
+ while (DviGetC(dw, &c) == ' ' || c == '\n')
+ ;
+ if (c == '-') {
+ negative = 1;
+ DviGetC(dw, &c);
+ }
+
+ for (; c >= '0' && c <= '9'; DviGetC(dw, &c)) {
+ if (negative)
+ i = i*10 - (c - '0');
+ else
+ i = i*10 + c - '0';
+ }
+ if (c != EOF)
+ DviUngetC(dw, c);
+ return i;
+}
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/src/devices/xditview/lex.h b/src/devices/xditview/lex.h
new file mode 100644
index 0000000..0a4cba0
--- /dev/null
+++ b/src/devices/xditview/lex.h
@@ -0,0 +1 @@
+int GetNumber(DviWidget);
diff --git a/src/devices/xditview/page.c b/src/devices/xditview/page.c
new file mode 100644
index 0000000..352d871
--- /dev/null
+++ b/src/devices/xditview/page.c
@@ -0,0 +1,86 @@
+/*
+ * page.c
+ *
+ * map page numbers to file position
+ */
+
+#include <config.h>
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "DviP.h"
+#include "page.h"
+
+#ifdef X_NOT_STDC_ENV
+extern long ftell();
+#endif
+
+static DviFileMap *
+MapPageNumberToFileMap (DviWidget dw, int number)
+{
+ DviFileMap *m;
+
+ for (m = dw->dvi.file_map; m; m=m->next)
+ if (m->page_number == number)
+ break;
+ return m;
+}
+
+void
+DestroyFileMap (DviFileMap *m)
+{
+ DviFileMap *next;
+
+ for (; m; m = next) {
+ next = m->next;
+ XtFree ((char *) m);
+ }
+}
+
+void
+ForgetPagePositions (DviWidget dw)
+{
+ DestroyFileMap (dw->dvi.file_map);
+ dw->dvi.file_map = 0;
+}
+
+void
+RememberPagePosition(DviWidget dw, int number)
+{
+ DviFileMap *m;
+
+ if (!(m = MapPageNumberToFileMap (dw, number))) {
+ m = (DviFileMap *) XtMalloc (sizeof *m);
+ m->page_number = number;
+ m->next = dw->dvi.file_map;
+ dw->dvi.file_map = m;
+ }
+ if (dw->dvi.tmpFile)
+ m->position = ftell (dw->dvi.tmpFile);
+ else
+ m->position = ftell (dw->dvi.file);
+}
+
+long
+SearchPagePosition (DviWidget dw, int number)
+{
+ DviFileMap *m;
+
+ if (!(m = MapPageNumberToFileMap (dw, number)))
+ return -1;
+ return m->position;
+}
+
+void
+FileSeek(DviWidget dw, long position)
+{
+ if (dw->dvi.tmpFile) {
+ dw->dvi.readingTmp = 1;
+ fseek (dw->dvi.tmpFile, position, 0);
+ } else
+ fseek (dw->dvi.file, position, 0);
+}
diff --git a/src/devices/xditview/page.h b/src/devices/xditview/page.h
new file mode 100644
index 0000000..e2c938d
--- /dev/null
+++ b/src/devices/xditview/page.h
@@ -0,0 +1,5 @@
+void DestroyFileMap(DviFileMap *);
+void FileSeek(DviWidget, long);
+void ForgetPagePositions(DviWidget);
+void RememberPagePosition(DviWidget, int);
+long SearchPagePosition(DviWidget, int);
diff --git a/src/devices/xditview/parse.c b/src/devices/xditview/parse.c
new file mode 100644
index 0000000..456c7da
--- /dev/null
+++ b/src/devices/xditview/parse.c
@@ -0,0 +1,343 @@
+/*
+ * parse.c
+ *
+ * parse dvi input
+ */
+
+#include <config.h>
+
+#include <X11/Xos.h>
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "DviP.h"
+#include "draw.h"
+#include "font.h"
+#include "lex.h"
+#include "page.h"
+#include "parse.h"
+
+static int StopSeen = 0;
+static void ParseDrawFunction(DviWidget, char *);
+static void ParseDeviceControl(DviWidget);
+static void push_env(DviWidget);
+static void pop_env(DviWidget);
+
+#define HorizontalMove(dw, delta) ((dw)->dvi.state->x += (delta))
+
+
+int
+ParseInput(register DviWidget dw)
+{
+ int n, k;
+ int c;
+ char Buffer[BUFSIZ];
+ int NextPage;
+ int otherc;
+
+ StopSeen = 0;
+
+ /*
+ * make sure some state exists
+ */
+
+ if (!dw->dvi.state)
+ push_env (dw);
+ for (;;) {
+ switch (DviGetC(dw, &c)) {
+ case '\n':
+ break;
+ case ' ': /* when input is text */
+ case 0: /* occasional noise creeps in */
+ break;
+ case '{': /* push down current environment */
+ push_env(dw);
+ break;
+ case '}':
+ pop_env(dw);
+ break;
+ /*
+ * two motion digits plus a character
+ */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ HorizontalMove(dw, (c-'0')*10 +
+ DviGetC(dw,&otherc)-'0');
+ /* fall through */
+ case 'c': /* single ascii character */
+ DviGetC(dw,&c);
+ if (c == ' ')
+ break;
+ Buffer[0] = c;
+ Buffer[1] = '\0';
+ (void) PutCharacter (dw, Buffer);
+ break;
+ case 'C':
+ GetWord (dw, Buffer, BUFSIZ);
+ (void) PutCharacter (dw, Buffer);
+ break;
+ case 't':
+ Buffer[1] = '\0';
+ while (DviGetC (dw, &c) != EOF
+ && c != ' ' && c != '\n') {
+ Buffer[0] = c;
+ HorizontalMove (dw, PutCharacter (dw, Buffer));
+ }
+ break;
+ case 'u':
+ n = GetNumber(dw);
+ Buffer[1] = '\0';
+ while (DviGetC (dw, &c) == ' ')
+ ;
+ while (c != EOF && c != ' ' && c != '\n') {
+ Buffer[0] = c;
+ HorizontalMove (dw,
+ PutCharacter (dw, Buffer) + n);
+ DviGetC (dw, &c);
+ }
+ break;
+
+ case 'D': /* draw function */
+ (void) GetLine(dw, Buffer, BUFSIZ);
+ if (dw->dvi.display_enable)
+ ParseDrawFunction(dw, Buffer);
+ break;
+ case 's': /* ignore fractional sizes */
+ n = GetNumber(dw);
+ dw->dvi.state->font_size = n;
+ break;
+ case 'f':
+ n = GetNumber(dw);
+ dw->dvi.state->font_number = n;
+ break;
+ case 'H': /* absolute horizontal motion */
+ k = GetNumber(dw);
+ HorizontalGoto(dw, k);
+ break;
+ case 'h': /* relative horizontal motion */
+ k = GetNumber(dw);
+ HorizontalMove(dw, k);
+ break;
+ case 'w': /* word space */
+ Word (dw);
+ break;
+ case 'V':
+ n = GetNumber(dw);
+ VerticalGoto(dw, n);
+ break;
+ case 'v':
+ n = GetNumber(dw);
+ VerticalMove(dw, n);
+ break;
+ case 'P': /* new spread */
+ break;
+ case 'p': /* new page */
+ (void) GetNumber(dw);
+ NextPage = dw->dvi.current_page + 1;
+ RememberPagePosition(dw, NextPage);
+ FlushCharCache (dw);
+ return(NextPage);
+ case 'N':
+ n = GetNumber(dw);
+ PutNumberedCharacter (dw, n);
+ break;
+ case 'n': /* end of line */
+ GetNumber(dw);
+ GetNumber(dw);
+ Newline (dw);
+ HorizontalGoto(dw, 0);
+ break;
+ case 'F': /* input files */
+ case '+': /* continuation of X device control */
+ case 'm': /* color */
+ case '#': /* comment */
+ GetLine(dw, NULL, 0);
+ break;
+ case 'x': /* device control */
+ ParseDeviceControl(dw);
+ break;
+ case EOF:
+ dw->dvi.last_page = dw->dvi.current_page;
+ FlushCharCache (dw);
+ return dw->dvi.current_page;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+push_env(DviWidget dw)
+{
+ DviState *new_state;
+
+ new_state = (DviState *) XtMalloc (sizeof (*new_state));
+ if (dw->dvi.state)
+ *new_state = *(dw->dvi.state);
+ else {
+ new_state->font_size = 10;
+ new_state->font_number = 1;
+ new_state->x = 0;
+ new_state->y = 0;
+ }
+ new_state->next = dw->dvi.state;
+ dw->dvi.state = new_state;
+}
+
+static void
+pop_env(DviWidget dw)
+{
+ DviState *old;
+
+ old = dw->dvi.state;
+ dw->dvi.state = old->next;
+ XtFree ((char *) old);
+}
+
+static void
+InitTypesetter (DviWidget dw)
+{
+ while (dw->dvi.state)
+ pop_env (dw);
+ push_env (dw);
+ FlushCharCache (dw);
+}
+
+#define DRAW_ARGS_MAX 128
+
+static void
+ParseDrawFunction(DviWidget dw, char *buf)
+{
+ int v[DRAW_ARGS_MAX];
+ int i, no_move = 0;
+ char *ptr;
+
+ v[0] = v[1] = v[2] = v[3] = 0;
+
+ if (buf[0] == '\0')
+ return;
+ ptr = buf+1;
+
+ for (i = 0; i < DRAW_ARGS_MAX; i++) {
+ if (sscanf(ptr, "%d", v + i) != 1)
+ break;
+ while (*ptr == ' ')
+ ptr++;
+ while (*ptr != '\0' && *ptr != ' ')
+ ptr++;
+ }
+
+ switch (buf[0]) {
+ case 'l': /* draw a line */
+ DrawLine(dw, v[0], v[1]);
+ break;
+ case 'c': /* circle */
+ DrawCircle(dw, v[0]);
+ break;
+ case 'C':
+ DrawFilledCircle(dw, v[0]);
+ break;
+ case 'e': /* ellipse */
+ DrawEllipse(dw, v[0], v[1]);
+ break;
+ case 'E':
+ DrawFilledEllipse(dw, v[0], v[1]);
+ break;
+ case 'a': /* arc */
+ DrawArc(dw, v[0], v[1], v[2], v[3]);
+ break;
+ case 'p':
+ DrawPolygon(dw, v, i);
+ break;
+ case 'P':
+ DrawFilledPolygon(dw, v, i);
+ break;
+ case '~': /* wiggly line */
+ DrawSpline(dw, v, i);
+ break;
+ case 't':
+ dw->dvi.line_thickness = v[0];
+ break;
+ case 'f':
+ if (i > 0 && v[0] >= 0 && v[0] <= DVI_FILL_MAX)
+ dw->dvi.fill = v[0];
+ no_move = 1;
+ break;
+ default:
+#if 0
+ warning("unknown drawing function %s", buf);
+#endif
+ no_move = 1;
+ break;
+ }
+
+ if (!no_move) {
+ if (buf[0] == 'e') {
+ if (i > 0)
+ dw->dvi.state->x += v[0];
+ }
+ else {
+ while (--i >= 0) {
+ if (i & 1)
+ dw->dvi.state->y += v[i];
+ else
+ dw->dvi.state->x += v[i];
+ }
+ }
+ }
+}
+
+static void
+ParseDeviceControl(DviWidget dw) /* Parse the x commands */
+{
+ char str[20], str1[50];
+ int c, n;
+
+ GetWord (dw, str, 20);
+ switch (str[0]) { /* crude for now */
+ case 'T': /* output device */
+ GetWord (dw, str, 20);
+ SetDevice (dw, str);
+ break;
+ case 'i': /* initialize */
+ InitTypesetter (dw);
+ break;
+ case 't': /* trailer */
+ break;
+ case 'p': /* pause -- can restart */
+ break;
+ case 's': /* stop */
+ StopSeen = 1;
+ return;
+ case 'r': /* resolution when prepared */
+ break;
+ case 'f': /* font used */
+ n = GetNumber (dw);
+ GetWord (dw, str, 20);
+ GetLine (dw, str1, 50);
+ SetFontPosition (dw, n, str, str1);
+ break;
+ case 'H': /* char height */
+ break;
+ case 'S': /* slant */
+ break;
+ }
+ while (DviGetC (dw, &c) != '\n') /* skip rest of input line */
+ if (c == EOF)
+ return;
+ return;
+}
+
+
+/*
+Local Variables:
+c-indent-level: 8
+c-continued-statement-offset: 8
+c-brace-offset: -8
+c-argdecl-indent: 8
+c-label-offset: -8
+c-tab-always-indent: nil
+End:
+*/
diff --git a/src/devices/xditview/parse.h b/src/devices/xditview/parse.h
new file mode 100644
index 0000000..636f3a6
--- /dev/null
+++ b/src/devices/xditview/parse.h
@@ -0,0 +1 @@
+int ParseInput(register DviWidget dw);
diff --git a/src/devices/xditview/xdit.bm b/src/devices/xditview/xdit.bm
new file mode 100644
index 0000000..0c7aa8c
--- /dev/null
+++ b/src/devices/xditview/xdit.bm
@@ -0,0 +1,14 @@
+#define xdit_width 32
+#define xdit_height 32
+static unsigned char xdit_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x03, 0x02, 0x00, 0x00, 0x02,
+ 0x8a, 0xa2, 0xfc, 0x03, 0x52, 0x14, 0x03, 0x04, 0x02, 0x80, 0x00, 0x08,
+ 0x52, 0x54, 0x00, 0x10, 0x8a, 0x22, 0x8f, 0x23, 0x02, 0x20, 0x06, 0x21,
+ 0x8a, 0x12, 0x8c, 0x40, 0x52, 0x14, 0x8c, 0x40, 0x02, 0x10, 0x58, 0x40,
+ 0x52, 0x14, 0x30, 0x40, 0x8a, 0x12, 0x30, 0x40, 0x02, 0x10, 0x70, 0x40,
+ 0x8a, 0x12, 0xc8, 0x40, 0x52, 0x24, 0xc4, 0xe0, 0x02, 0x20, 0x84, 0xe1,
+ 0x52, 0x54, 0xce, 0xf3, 0x8a, 0xa2, 0x00, 0xf8, 0x02, 0x00, 0x03, 0xfc,
+ 0x8a, 0x22, 0xfc, 0xf3, 0x52, 0x14, 0x00, 0xc2, 0x02, 0x00, 0x00, 0x02,
+ 0x52, 0x14, 0x45, 0x02, 0x8a, 0xa2, 0x28, 0x02, 0x02, 0x00, 0x00, 0x02,
+ 0x02, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/devices/xditview/xdit_mask.bm b/src/devices/xditview/xdit_mask.bm
new file mode 100644
index 0000000..a584629
--- /dev/null
+++ b/src/devices/xditview/xdit_mask.bm
@@ -0,0 +1,14 @@
+#define xdit_mask_width 32
+#define xdit_mask_height 32
+static unsigned char xdit_mask_bits[] = {
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07,
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x1f,
+ 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xc7,
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07,
+ 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
diff --git a/src/devices/xditview/xditview.am b/src/devices/xditview/xditview.am
new file mode 100644
index 0000000..7bb32ba
--- /dev/null
+++ b/src/devices/xditview/xditview.am
@@ -0,0 +1,130 @@
+# Copyright (C) 2014-2020 Free Software Foundation, Inc.
+#
+# This file is part of groff.
+#
+# groff 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 3 of the License, or (at your
+# option) any later version.
+#
+# groff 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, see <http://www.gnu.org/licenses/>.
+
+GXDITVIEWSOURCES = \
+ src/devices/xditview/device.c \
+ src/devices/xditview/draw.c \
+ src/devices/xditview/draw.h \
+ src/devices/xditview/Dvi.c \
+ src/devices/xditview/font.c \
+ src/devices/xditview/font.h \
+ src/devices/xditview/lex.c \
+ src/devices/xditview/lex.h \
+ src/devices/xditview/page.c \
+ src/devices/xditview/page.h \
+ src/devices/xditview/parse.c \
+ src/devices/xditview/parse.h \
+ src/devices/xditview/xditview.c \
+ src/devices/xditview/device.h \
+ src/devices/xditview/DviP.h \
+ src/devices/xditview/Menu.h \
+ src/devices/xditview/Dvi.h
+
+GXDITVIEW_GROFF_VERSION_H=src/devices/xditview/groff_version.h
+
+$(GXDITVIEW_GROFF_VERSION_H): $(top_srcdir)/.version
+ $(AM_V_at)$(MKDIR_P) `dirname $@`
+ $(AM_V_GEN)printf \
+ 'const char *Version_string = "%s";\n' '@VERSION@' > $@
+
+if WITHOUT_X11
+GXDITVIEW_MAN1 =
+EXTRA_DIST += $(GXDITVIEWSOURCES)
+else
+GXDITVIEW_MAN1 = src/devices/xditview/gxditview.1
+xditview_srcdir = $(top_srcdir)/src/devices/xditview
+bin_PROGRAMS += gxditview
+gxditview_CPPFLAGS = $(AM_CPPFLAGS) $(X_CFLAGS) -Dlint \
+ -I$(top_builddir)/src/devices/xditview
+gxditview_LDADD = $(X_LIBS) $(X_PRE_LIBS) -lXaw -lXmu -lXt -lX11 \
+ $(X_EXTRA_LIBS) $(LIBM) libxutil.a lib/libgnu.a
+XDITVIEW_GENHDRS = \
+ src/devices/xditview/GXditview-ad.h \
+ $(GXDITVIEW_GROFF_VERSION_H)
+gxditview_SOURCES = $(GXDITVIEWSOURCES)
+nodist_gxditview_SOURCES = $(XDITVIEW_GENHDRS)
+CLEANFILES += $(XDITVIEW_GENHDRS)
+
+man1_MANS += $(GXDITVIEW_MAN1)
+
+# Because we defined gxditview_CPPFLAGS, automake renames all of
+# xditview's objects, adding an "gxditview-" prefix.
+src/devices/xditview/gxditview-device.$(OBJEXT): defs.h
+src/devices/xditview/gxditview-xditview.$(OBJEXT): $(XDITVIEW_GENHDRS)
+
+src/devices/xditview/GXditview-ad.h: $(xditview_srcdir)/GXditview.ad
+ $(AM_V_GEN)$(SHELL) $(xditview_srcdir)/ad2c \
+ $(xditview_srcdir)/GXditview.ad > $@
+endif
+
+EXTRA_DIST += \
+ src/devices/xditview/ad2c \
+ src/devices/xditview/ChangeLog \
+ src/devices/xditview/DESC.in \
+ src/devices/xditview/FontMap-X11 \
+ src/devices/xditview/GXditview-color.ad \
+ src/devices/xditview/GXditview.ad \
+ src/devices/xditview/README \
+ src/devices/xditview/TODO \
+ src/devices/xditview/gray1.bm \
+ src/devices/xditview/gray2.bm \
+ src/devices/xditview/gray3.bm \
+ src/devices/xditview/gray4.bm \
+ src/devices/xditview/gray5.bm \
+ src/devices/xditview/gray6.bm \
+ src/devices/xditview/gray7.bm \
+ src/devices/xditview/gray8.bm \
+ src/devices/xditview/xdit.bm \
+ src/devices/xditview/xdit_mask.bm \
+ src/devices/xditview/gxditview.1.man
+
+# Custom installation of GXditview.ad and GXditview-color.ad
+install-data-local: install_xditview
+uninstall-local: uninstall_xditview
+
+if WITHOUT_X11
+install_xditview:
+uninstall_xditview:
+else
+install_xditview: \
+ $(xditview_srcdir)/FontMap-X11 \
+ $(xditview_srcdir)/GXditview.ad \
+ $(xditview_srcdir)/GXditview-color.ad
+ $(MKDIR_P) $(DESTDIR)$(fontdir)
+ $(INSTALL_DATA) $(xditview_srcdir)/FontMap-X11 \
+ $(DESTDIR)$(fontdir)/FontMap-X11
+ -test -d $(DESTDIR)$(appdefdir) \
+ || $(mkinstalldirs) $(DESTDIR)$(appdefdir)
+ $(INSTALL_DATA) $(xditview_srcdir)/GXditview.ad \
+ $(DESTDIR)$(appdefdir)/GXditview
+ $(INSTALL_DATA) $(xditview_srcdir)/GXditview-color.ad \
+ $(DESTDIR)$(appdefdir)/GXditview-color
+
+uninstall_xditview:
+ rm -f $(DESTDIR)$(appdefdir)/GXditview
+ rm -f $(DESTDIR)$(appdefdir)/GXditview-color
+ rm -f $(DESTDIR)$(fontdir)/FontMap-X11
+ -rmdir $(DESTDIR)$(fontdir) 2>/dev/null
+
+endif
+
+
+# Local Variables:
+# fill-column: 72
+# mode: makefile-automake
+# End:
+# vim: set autoindent filetype=automake textwidth=72:
diff --git a/src/devices/xditview/xditview.c b/src/devices/xditview/xditview.c
new file mode 100644
index 0000000..1f56940
--- /dev/null
+++ b/src/devices/xditview/xditview.c
@@ -0,0 +1,684 @@
+/*
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * 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, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * 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.
+ *
+ */
+/*
+ * xditview --
+ *
+ * Display ditroff output in an X window
+ */
+
+#ifndef SABER
+#ifndef lint
+static char rcsid[] = "$XConsortium: xditview.c,v 1.17 89/12/10 17:05:08 rws Exp $";
+#endif /* lint */
+#endif /* SABER */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Dialog.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/SmeBSB.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include "Dvi.h"
+#include "groff_version.h"
+
+#include "xdit.bm"
+#include "xdit_mask.bm"
+
+#ifdef NEED_DECLARATION_POPEN
+FILE *popen(const char *, const char *);
+#endif /* NEED_DECLARATION_POPEN */
+
+#ifdef NEED_DECLARATION_PCLOSE
+int pclose (FILE *);
+#endif /* NEED_DECLARATION_PCLOSE */
+
+typedef void (*MakePromptFunc)(const char *);
+
+static String fallback_resources[] = {
+#include "GXditview-ad.h"
+ NULL
+};
+
+static struct app_resources {
+ char *print_command;
+ char *filename;
+} app_resources;
+
+#define offset(field) XtOffset(struct app_resources *, field)
+
+/* Application resources. */
+
+static XtResource resources[] = {
+ {(String)"printCommand", (String)"PrintCommand", (String)XtRString,
+ sizeof(char*), offset(print_command), (String)XtRString, NULL},
+ {(String)"filename", (String)"Filename", (String)XtRString,
+ sizeof(char*), offset(filename), (String)XtRString, NULL},
+};
+
+#undef offset
+
+/* Command line options table. Only resources are entered here...there is a
+ pass over the remaining options after XrmParseCommand is let loose. */
+
+static XrmOptionDescRec options[] = {
+{(char *)"-page", (char *)"*dvi.pageNumber",
+ XrmoptionSepArg, NULL},
+{(char *)"-backingStore", (char *)"*dvi.backingStore",
+ XrmoptionSepArg, NULL},
+{(char *)"-resolution", (char *)"*dvi.resolution",
+ XrmoptionSepArg, NULL},
+{(char *)"-printCommand", (char *)".printCommand",
+ XrmoptionSepArg, NULL},
+{(char *)"-filename", (char *)".filename",
+ XrmoptionSepArg, NULL},
+{(char *)"-noPolyText", (char *)"*dvi.noPolyText",
+ XrmoptionNoArg, (XPointer)"TRUE"},
+};
+
+static char current_print_command[1024];
+
+static char current_file_name[1024];
+static FILE *current_file;
+
+/*
+ * Report the syntax for calling xditview.
+ */
+
+static void
+Syntax(const char *progname, bool had_error)
+{
+ FILE *stream = stdout;
+ if (had_error)
+ stream = stderr;
+ (void) fprintf (stream, "usage: %s [X-toolkit-option]"
+ " [-backingStore backing-store-type]"
+ " [-filename file]"
+// See draw.c:FlushCharCache().
+#if 0
+ " [-noPolyText]"
+#endif
+ " [-page page-number]"
+ " [-printCommand command]"
+ " [-resolution resolution]"
+ " [file]\n", progname);
+ (void) fprintf (stream, "usage: %s {-version | --version}\n",
+ progname);
+ (void) fprintf (stream, "usage: %s {-help | --help}\n",
+ progname);
+ if (had_error)
+ exit(EXIT_FAILURE);
+ else
+ exit(EXIT_SUCCESS);
+}
+
+static void NewFile (const char *);
+static void SetPageNumber (int);
+static Widget toplevel, paned, viewport, dvi;
+static Widget page;
+static Widget simpleMenu;
+
+static void NextPage(Widget, XtPointer, XtPointer);
+static void PreviousPage(Widget, XtPointer, XtPointer);
+static void SelectPage(Widget, XtPointer, XtPointer);
+static void OpenFile(Widget, XtPointer, XtPointer);
+static void Quit(Widget, XtPointer, XtPointer);
+static void Print(Widget, XtPointer, XtPointer);
+
+static struct menuEntry {
+ const char *name;
+ XtCallbackProc function;
+} menuEntries[] = {
+ {"nextPage", NextPage},
+ {"previousPage", PreviousPage},
+ {"selectPage", SelectPage},
+ {"print", Print},
+ {"openFile", OpenFile},
+ {"quit", Quit},
+};
+
+static void NextPageAction(Widget, XEvent *, String *, Cardinal *);
+static void PreviousPageAction(Widget, XEvent *, String *, Cardinal *);
+static void SelectPageAction(Widget, XEvent *, String *, Cardinal *);
+static void OpenFileAction(Widget, XEvent *, String *, Cardinal *);
+static void QuitAction(Widget, XEvent *, String *, Cardinal *);
+static void AcceptAction(Widget, XEvent *, String *, Cardinal *);
+static void CancelAction(Widget, XEvent *, String *, Cardinal *);
+static void PrintAction(Widget, XEvent *, String *, Cardinal *);
+static void RerasterizeAction(Widget, XEvent *, String *, Cardinal *);
+
+static void MakePrompt(Widget, const char *, MakePromptFunc, const char *);
+
+XtActionsRec xditview_actions[] = {
+ {(String)"NextPage", NextPageAction},
+ {(String)"PreviousPage", PreviousPageAction},
+ {(String)"SelectPage", SelectPageAction},
+ {(String)"Print", PrintAction},
+ {(String)"OpenFile", OpenFileAction},
+ {(String)"Rerasterize", RerasterizeAction},
+ {(String)"Quit", QuitAction},
+ {(String)"Accept", AcceptAction},
+ {(String)"Cancel", CancelAction},
+};
+
+#define MenuNextPage 0
+#define MenuPreviousPage 1
+#define MenuSelectPage 2
+#define MenuPrint 3
+#define MenuOpenFile 4
+#define MenuQuit 5
+
+static char pageLabel[256] = "Page <none>";
+
+int main(int argc, char **argv)
+{
+ char *file_name = 0;
+ Cardinal i;
+ static Arg labelArgs[] = {
+ {XtNlabel, (XtArgVal) pageLabel},
+ };
+ XtAppContext xtcontext;
+ Arg topLevelArgs[2];
+ Widget entry;
+ Arg pageNumberArgs[1];
+ int page_number;
+
+ toplevel = XtAppInitialize(&xtcontext, "GXditview",
+ options, XtNumber (options),
+ &argc, argv, fallback_resources, NULL, 0);
+ if (argc > 2)
+ Syntax(argv[0], true /* had error */);
+ else if (argc == 2) {
+ if ((strcmp(argv[1], "-help") == 0)
+ || (strcmp(argv[1], "--help") == 0))
+ Syntax(argv[0], false /* did not have error */);
+ else if ((strcmp(argv[1], "-version") == 0)
+ || (strcmp(argv[1], "--version") == 0)) {
+ (void) printf("GNU gxditview (groff) version %s\n",
+ Version_string);
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ XtGetApplicationResources(toplevel, (XtPointer)&app_resources,
+ resources, XtNumber(resources),
+ NULL, (Cardinal) 0);
+ if (app_resources.print_command)
+ strcpy(current_print_command, app_resources.print_command);
+
+ XtAppAddActions(xtcontext, xditview_actions, XtNumber (xditview_actions));
+
+ XtSetArg (topLevelArgs[0], XtNiconPixmap,
+ XCreateBitmapFromData (XtDisplay (toplevel),
+ XtScreen(toplevel)->root,
+ (char *)xdit_bits,
+ xdit_width, xdit_height));
+
+ XtSetArg (topLevelArgs[1], XtNiconMask,
+ XCreateBitmapFromData (XtDisplay (toplevel),
+ XtScreen(toplevel)->root,
+ (char *)xdit_mask_bits,
+ xdit_mask_width, xdit_mask_height));
+ XtSetValues (toplevel, topLevelArgs, 2);
+ if (argc > 1)
+ file_name = argv[1];
+
+ /*
+ * create the menu and insert the entries
+ */
+ simpleMenu = XtCreatePopupShell ("menu", simpleMenuWidgetClass, toplevel,
+ NULL, 0);
+ for (i = 0; i < XtNumber (menuEntries); i++) {
+ entry = XtCreateManagedWidget(menuEntries[i].name,
+ smeBSBObjectClass, simpleMenu,
+ NULL, (Cardinal) 0);
+ XtAddCallback(entry, XtNcallback, menuEntries[i].function, NULL);
+ }
+
+ paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel,
+ NULL, (Cardinal) 0);
+ viewport = XtCreateManagedWidget("viewport", viewportWidgetClass, paned,
+ NULL, (Cardinal) 0);
+ dvi = XtCreateManagedWidget ("dvi", dviWidgetClass, viewport, NULL, 0);
+ page = XtCreateManagedWidget ("label", labelWidgetClass, paned,
+ labelArgs, XtNumber (labelArgs));
+ XtSetArg (pageNumberArgs[0], XtNpageNumber, &page_number);
+ XtGetValues (dvi, pageNumberArgs, 1);
+ if (file_name)
+ NewFile (file_name);
+ /* NewFile modifies current_file_name, so do this here. */
+ if (app_resources.filename)
+ strcpy(current_file_name, app_resources.filename);
+ XtRealizeWidget (toplevel);
+ if (file_name)
+ SetPageNumber (page_number);
+ XtInstallAllAccelerators(paned,paned);
+ XtAppMainLoop(xtcontext);
+ return 0;
+}
+
+static void
+SetPageNumber (int number)
+{
+ Arg arg[2];
+ int actual_number, last_page;
+
+ XtSetArg (arg[0], XtNpageNumber, number);
+ XtSetValues (dvi, arg, 1);
+ XtSetArg (arg[0], XtNpageNumber, &actual_number);
+ XtSetArg (arg[1], XtNlastPageNumber, &last_page);
+ XtGetValues (dvi, arg, 2);
+ if (actual_number == 0)
+ sprintf (pageLabel, "Page <none>");
+ else if (last_page > 0)
+ sprintf (pageLabel, "Page %d of %d", actual_number, last_page);
+ else
+ sprintf (pageLabel, "Page %d", actual_number);
+ XtSetArg (arg[0], XtNlabel, pageLabel);
+ XtSetValues (page, arg, 1);
+}
+
+static void
+SelectPageNumber (const char *number_string)
+{
+ SetPageNumber (atoi(number_string));
+}
+
+static int hadFile = 0;
+
+static void
+NewFile (const char *name)
+{
+ Arg arg[2];
+ char *n;
+ FILE *new_file;
+ Boolean seek = 0;
+
+ if (current_file) {
+ if (!strcmp (current_file_name, "-"))
+ ;
+ else if (current_file_name[0] == '|')
+ pclose (current_file);
+ else
+ fclose (current_file);
+ }
+ if (!strcmp (name, "-"))
+ new_file = stdin;
+ else if (name[0] == '|')
+ new_file = popen (name+1, "r");
+ else {
+ new_file = fopen (name, "r");
+ seek = 1;
+ }
+ if (!new_file) {
+ /* XXX display error message */
+ return;
+ }
+ XtSetArg (arg[0], XtNfile, new_file);
+ XtSetArg (arg[1], XtNseek, seek);
+ XtSetValues (dvi, arg, 2);
+ if (hadFile || name[0] != '-' || name[1] != '\0') {
+ XtSetArg (arg[0], XtNtitle, name);
+ if (name[0] != '/' && (n = strrchr (name, '/')))
+ n = n + 1;
+ else
+ n = (char *)name;
+ XtSetArg (arg[1], XtNiconName, n);
+ XtSetValues (toplevel, arg, 2);
+ }
+ hadFile = 1;
+ SelectPageNumber ("1");
+ strcpy (current_file_name, name);
+ current_file = new_file;
+}
+
+static char fileBuf[1024];
+
+static void
+ResetMenuEntry (Widget entry)
+{
+ Arg arg[1];
+
+ XtSetArg (arg[0], (String)XtNpopupOnEntry, entry);
+ XtSetValues (XtParent(entry) , arg, (Cardinal) 1);
+}
+
+/*ARGSUSED*/
+
+static void
+NextPage (Widget entry, XtPointer name, XtPointer data)
+{
+ name = name; /* unused; suppress compiler warning */
+ data = data;
+
+ NextPageAction((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
+ ResetMenuEntry (entry);
+}
+
+static void
+NextPageAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Arg args[1];
+ int number;
+
+ XtSetArg (args[0], XtNpageNumber, &number);
+ XtGetValues (dvi, args, 1);
+ SetPageNumber (number+1);
+
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+}
+
+/*ARGSUSED*/
+
+static void
+PreviousPage (Widget entry, XtPointer name, XtPointer data)
+{
+ name = name; /* unused; suppress compiler warning */
+ data = data;
+
+ PreviousPageAction ((Widget)NULL, (XEvent *) 0, (String *) 0,
+ (Cardinal *) 0);
+ ResetMenuEntry (entry);
+}
+
+static void
+PreviousPageAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Arg args[1];
+ int number;
+
+ XtSetArg (args[0], XtNpageNumber, &number);
+ XtGetValues (dvi, args, 1);
+ SetPageNumber (number-1);
+
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+}
+
+/* ARGSUSED */
+
+static void
+SelectPage (Widget entry, XtPointer name, XtPointer data)
+{
+ name = name; /* unused; suppress compiler warning */
+ data = data;
+
+ SelectPageAction ((Widget)NULL, (XEvent *) 0, (String *) 0,
+ (Cardinal *) 0);
+ ResetMenuEntry (entry);
+}
+
+static void
+SelectPageAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+
+ MakePrompt (toplevel, "Page number", SelectPageNumber, "");
+}
+
+
+static void
+DoPrint (const char *name)
+{
+ FILE *print_file;
+ RETSIGTYPE (*handler)(int);
+
+ /* Avoid dying because of an invalid command. */
+ handler = signal(SIGPIPE, SIG_IGN);
+
+ print_file = popen(name, "w");
+ if (!print_file)
+ /* XXX print error message */
+ return;
+ DviSaveToFile(dvi, print_file);
+ pclose(print_file);
+ signal(SIGPIPE, handler);
+ strcpy(current_print_command, name);
+}
+
+static void
+RerasterizeAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ Arg args[1];
+ int number;
+
+ if (current_file_name[0] == 0) {
+ /* XXX display an error message */
+ return;
+ }
+ XtSetArg (args[0], XtNpageNumber, &number);
+ XtGetValues (dvi, args, 1);
+ NewFile(current_file_name);
+ SetPageNumber (number);
+
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+}
+
+/* ARGSUSED */
+
+static void
+Print (Widget entry, XtPointer name, XtPointer data)
+{
+ name = name; /* unused; suppress compiler warning */
+ data = data;
+
+ PrintAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
+ ResetMenuEntry (entry);
+}
+
+static void
+PrintAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+
+ if (current_print_command[0])
+ strcpy (fileBuf, current_print_command);
+ else
+ fileBuf[0] = '\0';
+ MakePrompt (toplevel, "Print command:", DoPrint, fileBuf);
+}
+
+
+/* ARGSUSED */
+
+static void
+OpenFile (Widget entry, XtPointer name, XtPointer data)
+{
+ name = name; /* unused; suppress compiler warning */
+ data = data;
+
+ OpenFileAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
+ ResetMenuEntry (entry);
+}
+
+static void
+OpenFileAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+
+ if (current_file_name[0])
+ strcpy (fileBuf, current_file_name);
+ else
+ fileBuf[0] = '\0';
+ MakePrompt (toplevel, "File to open:", NewFile, fileBuf);
+}
+
+/* ARGSUSED */
+
+static void
+Quit (Widget entry, XtPointer closure, XtPointer data)
+{
+ entry = entry; /* unused; suppress compiler warning */
+ closure = closure;
+ data = data;
+
+ QuitAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
+}
+
+static void
+QuitAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+
+ exit (0);
+}
+
+Widget promptShell, promptDialog;
+MakePromptFunc promptfunction;
+
+/* ARGSUSED */
+static
+void CancelAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ widget = widget; /* unused; suppress compiler warning */
+ event = event;
+ params = params;
+ num_params = num_params;
+
+ if (promptShell) {
+ XtSetKeyboardFocus(toplevel, (Widget) None);
+ XtDestroyWidget(promptShell);
+ promptShell = (Widget) 0;
+ }
+}
+
+static
+void AcceptAction (Widget widget, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ (*promptfunction)(XawDialogGetValueString(promptDialog));
+ CancelAction (widget, event, params, num_params);
+}
+
+static void
+MakePrompt(Widget centerw, const char *prompt,
+ MakePromptFunc func, const char *def)
+{
+ static Arg dialogArgs[] = {
+ {XtNlabel, 0},
+ {XtNvalue, 0},
+ };
+ Arg valueArgs[1];
+ Arg centerArgs[2];
+ Position source_x, source_y;
+ Position dest_x, dest_y;
+ Dimension center_width, center_height;
+ Dimension prompt_width, prompt_height;
+ Widget valueWidget;
+
+ CancelAction ((Widget)NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0);
+ promptShell = XtCreatePopupShell ("promptShell", transientShellWidgetClass,
+ toplevel, NULL, (Cardinal) 0);
+ dialogArgs[0].value = (XtArgVal)prompt;
+ dialogArgs[1].value = (XtArgVal)def;
+ promptDialog = XtCreateManagedWidget( "promptDialog", dialogWidgetClass,
+ promptShell, dialogArgs, XtNumber (dialogArgs));
+ XawDialogAddButton(promptDialog, "accept", NULL, (XtPointer) 0);
+ XawDialogAddButton(promptDialog, "cancel", NULL, (XtPointer) 0);
+ valueWidget = XtNameToWidget (promptDialog, "value");
+ if (valueWidget) {
+ XtSetArg (valueArgs[0], (String)XtNresizable, TRUE);
+ XtSetValues (valueWidget, valueArgs, 1);
+ /*
+ * as resizable isn't set until just above, the
+ * default value will be displayed incorrectly.
+ * rectify the situation by resetting the values
+ */
+ XtSetValues (promptDialog, dialogArgs, XtNumber (dialogArgs));
+ }
+ XtSetKeyboardFocus (promptDialog, valueWidget);
+ XtSetKeyboardFocus (toplevel, valueWidget);
+ XtRealizeWidget (promptShell);
+ /*
+ * place the widget in the center of the "parent"
+ */
+ XtSetArg (centerArgs[0], XtNwidth, &center_width);
+ XtSetArg (centerArgs[1], XtNheight, &center_height);
+ XtGetValues (centerw, centerArgs, 2);
+ XtSetArg (centerArgs[0], XtNwidth, &prompt_width);
+ XtSetArg (centerArgs[1], XtNheight, &prompt_height);
+ XtGetValues (promptShell, centerArgs, 2);
+ source_x = (center_width - prompt_width) / 2;
+ source_y = (center_height - prompt_height) / 3;
+ XtTranslateCoords (centerw, source_x, source_y, &dest_x, &dest_y);
+ XtSetArg (centerArgs[0], XtNx, dest_x);
+ XtSetArg (centerArgs[1], XtNy, dest_y);
+ XtSetValues (promptShell, centerArgs, 2);
+ XtMapWidget(promptShell);
+ promptfunction = func;
+}
+
+/*
+Local Variables:
+c-indent-level: 4
+c-continued-statement-offset: 4
+c-brace-offset: -4
+c-argdecl-indent: 4
+c-label-offset: -4
+c-tab-always-indent: nil
+End:
+*/